delim_string_iter.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #pragma once
  2. #include <util/generic/algorithm.h>
  3. #include <util/generic/strbuf.h>
  4. #include <util/generic/yexception.h>
  5. #include <util/string/cast.h>
  6. #include <util/system/yassert.h>
  7. #include <iterator>
  8. class TDelimStringIter {
  9. public:
  10. using value_type = TStringBuf;
  11. using difference_type = ptrdiff_t;
  12. using pointer = const TStringBuf*;
  13. using reference = const TStringBuf&;
  14. using iterator_category = std::forward_iterator_tag;
  15. inline TDelimStringIter(const char* begin, const char* strEnd, TStringBuf delim)
  16. : TDelimStringIter(TStringBuf(begin, strEnd), delim)
  17. {
  18. }
  19. inline TDelimStringIter(TStringBuf str, TStringBuf delim)
  20. : IsValid(true)
  21. , Str(str)
  22. , Delim(delim)
  23. {
  24. UpdateCurrent();
  25. }
  26. inline TDelimStringIter()
  27. : IsValid(false)
  28. {
  29. }
  30. inline explicit operator bool() const {
  31. return IsValid;
  32. }
  33. // NOTE: this is a potentially unsafe operation (no overrun check)
  34. inline TDelimStringIter& operator++() {
  35. if (Current.end() != Str.end()) {
  36. Str.Skip(Current.length() + Delim.length());
  37. UpdateCurrent();
  38. } else {
  39. Str.Clear();
  40. Current.Clear();
  41. IsValid = false;
  42. }
  43. return *this;
  44. }
  45. inline void operator+=(size_t n) {
  46. for (; n > 0; --n) {
  47. ++(*this);
  48. }
  49. }
  50. inline bool operator==(const TDelimStringIter& rhs) const {
  51. return (IsValid == rhs.IsValid) && (!IsValid || (Current.begin() == rhs.Current.begin()));
  52. }
  53. inline bool operator!=(const TDelimStringIter& rhs) const {
  54. return !(*this == rhs);
  55. }
  56. inline TStringBuf operator*() const {
  57. return Current;
  58. }
  59. inline const TStringBuf* operator->() const {
  60. return &Current;
  61. }
  62. // Get & advance
  63. template <class T>
  64. inline bool TryNext(T& t) {
  65. if (IsValid) {
  66. t = FromString<T>(Current);
  67. operator++();
  68. return true;
  69. } else {
  70. return false;
  71. }
  72. }
  73. template <class T>
  74. inline TDelimStringIter& Next(T& t) // Get & advance
  75. {
  76. if (!TryNext(t))
  77. ythrow yexception() << "No valid field";
  78. return *this;
  79. }
  80. template <class T>
  81. inline T GetNext() {
  82. T res;
  83. Next(res);
  84. return res;
  85. }
  86. inline const char* GetBegin() const {
  87. return Current.begin();
  88. }
  89. inline const char* GetEnd() const {
  90. return Current.end();
  91. }
  92. inline bool Valid() const {
  93. return IsValid;
  94. }
  95. // contents from next token to the end of string
  96. inline TStringBuf Cdr() const {
  97. return Str.SubStr(Current.length() + Delim.length());
  98. }
  99. inline TDelimStringIter IterEnd() const {
  100. return TDelimStringIter();
  101. }
  102. private:
  103. inline void UpdateCurrent() {
  104. // it is much faster than TStringBuf::find
  105. size_t pos = std::search(Str.begin(), Str.end(), Delim.begin(), Delim.end()) - Str.begin();
  106. Current = Str.Head(pos);
  107. }
  108. private:
  109. bool IsValid;
  110. TStringBuf Str;
  111. TStringBuf Current;
  112. TStringBuf Delim;
  113. };
  114. //example: for (TStringBuf field: TDelimStroka(line, "@@")) { ... }
  115. struct TDelimStroka {
  116. TStringBuf S;
  117. TStringBuf Delim;
  118. inline TDelimStroka(TStringBuf s, TStringBuf delim)
  119. : S(s)
  120. , Delim(delim)
  121. {
  122. }
  123. inline TDelimStringIter begin() const {
  124. return TDelimStringIter(S, Delim);
  125. }
  126. inline TDelimStringIter end() const {
  127. return TDelimStringIter();
  128. }
  129. };
  130. inline TDelimStringIter begin_delim(const TString& str, TStringBuf delim) {
  131. return TDelimStringIter(str, delim);
  132. }
  133. inline TDelimStringIter begin_delim(TStringBuf str, TStringBuf delim) {
  134. return TDelimStringIter(str.begin(), str.end(), delim);
  135. }
  136. inline TDelimStringIter end_delim(const TString& /*str*/, TStringBuf /*delim*/) {
  137. return TDelimStringIter();
  138. }
  139. class TKeyValueDelimStringIter {
  140. public:
  141. TKeyValueDelimStringIter(const TStringBuf str, const TStringBuf delim);
  142. bool Valid() const;
  143. TKeyValueDelimStringIter& operator++();
  144. const TStringBuf& Key() const;
  145. const TStringBuf& Value() const;
  146. private:
  147. TDelimStringIter DelimIter;
  148. TStringBuf ChunkKey, ChunkValue;
  149. private:
  150. void ReadKeyAndValue();
  151. };