// Some experiments with byte slice objects in C++, inspired by // masde4.c. #include #include #include using std::string, std::pair, std::make_pair; // Byte slice, inspired by Golang’s slices and Alexandrescu’s ranges. class bs { friend std::ostream& operator<<(std::ostream& out, const bs &s) { for (auto p : s) out << p; return out; } public: char *b, *e; char& operator[](int i) const { return b[i]; } bs& operator++() { b++; return *this; } explicit operator bool() const { return b != e; } char *begin() const { return b; } char *end() const { return e; } bs tok(bs delims); }; // I don’t think I can make this conversion implicit without // preventing bs from being a “mere aggregate”. bs bs_of_string(string& s) { return bs(&*s.begin(), &*s.end()); } // XXX not sure how to make this handle pointers to string literals. // Maybe I’d have to templatize bs! bs bs_of_asciz(char *s) { return bs(s, s + strlen(s)); } // XXX basically just reimplements std::ranges::find_first_of. // https://en.cppreference.com/w/cpp/algorithm/find_first_of // https://en.cppreference.com/w/cpp/algorithm/ranges/find_first_of inline pair find_cset(bs s, bs delims) { bs tok = s; for (; s; ++s) { for (bs t = delims; t; ++t) { if (s[0] == t[0]) return make_pair(bs(tok.b, s.b), s); } } return make_pair(tok, s); } bs bs::tok(bs delims) { pair result = find_cset(*this, delims); *this = result.second; return result.first; } int main(int argc, char **argv) { string s3 = "these are some words. Can you read them?x"; bs t = bs_of_string(s3); string delims_s = " .?"; bs delims = bs_of_string(delims_s); for (;;) { auto toknt = find_cset(t, delims); std::cout << "[" << toknt.first << "]"; t = toknt.second; if (!t) break; char delim = t[0]; std::cout << "{" << delim << "}"; ++t; } std::cout << "\n"; // Compare the interface that modifies the bs in place. t = bs_of_string(s3); for (;;) { bs tok = t.tok(delims); std::cout << "[" << tok << "]"; if (!t) break; char delim = t[0]; std::cout << "{" << delim << "}"; ++t; } std::cout << "\n"; return 0; }