// Some experiments with byte slice objects in C++, inspired by // masde4.c. // This program compiles and runs successfully under ulimit -v 108032 // with G++ version “Debian 12.2.0-14” with the command line `g++ // -Wall -O -std=c++11 -g -O0 -std=c++20 findcset.cc -o findcset`. #include #include #include using std::string, std::pair, std::make_pair; // Byte slice, inspired by Golang’s slices and Alexandrescu’s ranges. template class slice { public: T *b, *e; T& operator[](int i) const { return b[i]; } slice& operator++() { b++; return *this; } explicit operator bool() const { return b != e; } T *begin() const { return b; } T *end() const { return e; } }; using bs = slice; using cbs = slice; std::ostream& operator<<(std::ostream& out, const bs &s) { for (auto p : s) out << p; return out; } std::ostream& operator<<(std::ostream& out, const cbs &s) { for (auto p : s) out << p; return out; } // 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()); } cbs cbs_of_asciz(const char *s) { return cbs { 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 // This is a template on two types to permit use of const chars with // chars, chars with const chars, const chars with const chars, or // chars with chars. template pair, slice> find_cset(slice s, slice delims) { auto tok = s; for (; s; ++s) { for (auto c : delims) if (s[0] == c) return { { tok.b, s.b }, s }; } return { tok, s }; } template slice token_until(slice& input, slice delims) { auto result = find_cset(input, delims); input = 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; also use a // cbs. t = bs_of_string(s3); cbs cdelims = cbs_of_asciz(" .?"); for (;;) { bs tok = token_until(t, cdelims); std::cout << "[" << tok << "]"; if (!t) break; char delim = t[0]; std::cout << "{" << delim << "}"; ++t; } std::cout << "\n"; return 0; }