#pragma once #include #include #include #include #include #include class TDelimStringIter { public: using value_type = TStringBuf; using difference_type = ptrdiff_t; using pointer = const TStringBuf*; using reference = const TStringBuf&; using iterator_category = std::forward_iterator_tag; inline TDelimStringIter(const char* begin, const char* strEnd, TStringBuf delim) : TDelimStringIter(TStringBuf(begin, strEnd), delim) { } inline TDelimStringIter(TStringBuf str, TStringBuf delim) : IsValid(true) , Str(str) , Delim(delim) { UpdateCurrent(); } inline TDelimStringIter() : IsValid(false) { } inline explicit operator bool() const { return IsValid; } // NOTE: this is a potentially unsafe operation (no overrun check) inline TDelimStringIter& operator++() { if (Current.end() != Str.end()) { Str.Skip(Current.length() + Delim.length()); UpdateCurrent(); } else { Str.Clear(); Current.Clear(); IsValid = false; } return *this; } inline void operator+=(size_t n) { for (; n > 0; --n) { ++(*this); } } inline bool operator==(const TDelimStringIter& rhs) const { return (IsValid == rhs.IsValid) && (!IsValid || (Current.begin() == rhs.Current.begin())); } inline bool operator!=(const TDelimStringIter& rhs) const { return !(*this == rhs); } inline TStringBuf operator*() const { return Current; } inline const TStringBuf* operator->() const { return &Current; } // Get & advance template inline bool TryNext(T& t) { if (IsValid) { t = FromString(Current); operator++(); return true; } else { return false; } } template inline TDelimStringIter& Next(T& t) // Get & advance { if (!TryNext(t)) ythrow yexception() << "No valid field"; return *this; } template inline T GetNext() { T res; Next(res); return res; } inline const char* GetBegin() const { return Current.begin(); } inline const char* GetEnd() const { return Current.end(); } inline bool Valid() const { return IsValid; } // contents from next token to the end of string inline TStringBuf Cdr() const { return Str.SubStr(Current.length() + Delim.length()); } inline TDelimStringIter IterEnd() const { return TDelimStringIter(); } private: inline void UpdateCurrent() { // it is much faster than TStringBuf::find size_t pos = std::search(Str.begin(), Str.end(), Delim.begin(), Delim.end()) - Str.begin(); Current = Str.Head(pos); } private: bool IsValid; TStringBuf Str; TStringBuf Current; TStringBuf Delim; }; //example: for (TStringBuf field: TDelimStroka(line, "@@")) { ... } struct TDelimStroka { TStringBuf S; TStringBuf Delim; inline TDelimStroka(TStringBuf s, TStringBuf delim) : S(s) , Delim(delim) { } inline TDelimStringIter begin() const { return TDelimStringIter(S, Delim); } inline TDelimStringIter end() const { return TDelimStringIter(); } }; inline TDelimStringIter begin_delim(const TString& str, TStringBuf delim) { return TDelimStringIter(str, delim); } inline TDelimStringIter begin_delim(TStringBuf str, TStringBuf delim) { return TDelimStringIter(str.begin(), str.end(), delim); } inline TDelimStringIter end_delim(const TString& /*str*/, TStringBuf /*delim*/) { return TDelimStringIter(); } class TKeyValueDelimStringIter { public: TKeyValueDelimStringIter(const TStringBuf str, const TStringBuf delim); bool Valid() const; TKeyValueDelimStringIter& operator++(); const TStringBuf& Key() const; const TStringBuf& Value() const; private: TDelimStringIter DelimIter; TStringBuf ChunkKey, ChunkValue; private: void ReadKeyAndValue(); };