string_view.cc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // Copyright 2017 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "y_absl/strings/string_view.h"
  15. #ifndef Y_ABSL_USES_STD_STRING_VIEW
  16. #include <algorithm>
  17. #include <climits>
  18. #include <cstring>
  19. #include <ostream>
  20. namespace y_absl {
  21. Y_ABSL_NAMESPACE_BEGIN
  22. namespace {
  23. // This is significantly faster for case-sensitive matches with very
  24. // few possible matches.
  25. const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle,
  26. size_t neelen) {
  27. if (0 == neelen) {
  28. return phaystack; // even if haylen is 0
  29. }
  30. if (haylen < neelen) return nullptr;
  31. const char* match;
  32. const char* hayend = phaystack + haylen - neelen + 1;
  33. // A static cast is used here to work around the fact that memchr returns
  34. // a void* on Posix-compliant systems and const void* on Windows.
  35. while (
  36. (match = static_cast<const char*>(memchr(
  37. phaystack, pneedle[0], static_cast<size_t>(hayend - phaystack))))) {
  38. if (memcmp(match, pneedle, neelen) == 0)
  39. return match;
  40. else
  41. phaystack = match + 1;
  42. }
  43. return nullptr;
  44. }
  45. void WritePadding(std::ostream& o, size_t pad) {
  46. char fill_buf[32];
  47. memset(fill_buf, o.fill(), sizeof(fill_buf));
  48. while (pad) {
  49. size_t n = std::min(pad, sizeof(fill_buf));
  50. o.write(fill_buf, static_cast<std::streamsize>(n));
  51. pad -= n;
  52. }
  53. }
  54. class LookupTable {
  55. public:
  56. // For each character in wanted, sets the index corresponding
  57. // to the ASCII code of that character. This is used by
  58. // the find_.*_of methods below to tell whether or not a character is in
  59. // the lookup table in constant time.
  60. explicit LookupTable(string_view wanted) {
  61. for (char c : wanted) {
  62. table_[Index(c)] = true;
  63. }
  64. }
  65. bool operator[](char c) const { return table_[Index(c)]; }
  66. private:
  67. static unsigned char Index(char c) { return static_cast<unsigned char>(c); }
  68. bool table_[UCHAR_MAX + 1] = {};
  69. };
  70. } // namespace
  71. std::ostream& operator<<(std::ostream& o, string_view piece) {
  72. std::ostream::sentry sentry(o);
  73. if (sentry) {
  74. size_t lpad = 0;
  75. size_t rpad = 0;
  76. if (static_cast<size_t>(o.width()) > piece.size()) {
  77. size_t pad = static_cast<size_t>(o.width()) - piece.size();
  78. if ((o.flags() & o.adjustfield) == o.left) {
  79. rpad = pad;
  80. } else {
  81. lpad = pad;
  82. }
  83. }
  84. if (lpad) WritePadding(o, lpad);
  85. o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
  86. if (rpad) WritePadding(o, rpad);
  87. o.width(0);
  88. }
  89. return o;
  90. }
  91. string_view::size_type string_view::find(string_view s,
  92. size_type pos) const noexcept {
  93. if (empty() || pos > length_) {
  94. if (empty() && pos == 0 && s.empty()) return 0;
  95. return npos;
  96. }
  97. const char* result = memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_);
  98. return result ? static_cast<size_type>(result - ptr_) : npos;
  99. }
  100. string_view::size_type string_view::find(char c, size_type pos) const noexcept {
  101. if (empty() || pos >= length_) {
  102. return npos;
  103. }
  104. const char* result =
  105. static_cast<const char*>(memchr(ptr_ + pos, c, length_ - pos));
  106. return result != nullptr ? static_cast<size_type>(result - ptr_) : npos;
  107. }
  108. string_view::size_type string_view::rfind(string_view s,
  109. size_type pos) const noexcept {
  110. if (length_ < s.length_) return npos;
  111. if (s.empty()) return std::min(length_, pos);
  112. const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_;
  113. const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
  114. return result != last ? static_cast<size_type>(result - ptr_) : npos;
  115. }
  116. // Search range is [0..pos] inclusive. If pos == npos, search everything.
  117. string_view::size_type string_view::rfind(char c,
  118. size_type pos) const noexcept {
  119. // Note: memrchr() is not available on Windows.
  120. if (empty()) return npos;
  121. for (size_type i = std::min(pos, length_ - 1);; --i) {
  122. if (ptr_[i] == c) {
  123. return i;
  124. }
  125. if (i == 0) break;
  126. }
  127. return npos;
  128. }
  129. string_view::size_type string_view::find_first_of(
  130. string_view s, size_type pos) const noexcept {
  131. if (empty() || s.empty()) {
  132. return npos;
  133. }
  134. // Avoid the cost of LookupTable() for a single-character search.
  135. if (s.length_ == 1) return find_first_of(s.ptr_[0], pos);
  136. LookupTable tbl(s);
  137. for (size_type i = pos; i < length_; ++i) {
  138. if (tbl[ptr_[i]]) {
  139. return i;
  140. }
  141. }
  142. return npos;
  143. }
  144. string_view::size_type string_view::find_first_not_of(
  145. string_view s, size_type pos) const noexcept {
  146. if (empty()) return npos;
  147. // Avoid the cost of LookupTable() for a single-character search.
  148. if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos);
  149. LookupTable tbl(s);
  150. for (size_type i = pos; i < length_; ++i) {
  151. if (!tbl[ptr_[i]]) {
  152. return i;
  153. }
  154. }
  155. return npos;
  156. }
  157. string_view::size_type string_view::find_first_not_of(
  158. char c, size_type pos) const noexcept {
  159. if (empty()) return npos;
  160. for (; pos < length_; ++pos) {
  161. if (ptr_[pos] != c) {
  162. return pos;
  163. }
  164. }
  165. return npos;
  166. }
  167. string_view::size_type string_view::find_last_of(string_view s,
  168. size_type pos) const noexcept {
  169. if (empty() || s.empty()) return npos;
  170. // Avoid the cost of LookupTable() for a single-character search.
  171. if (s.length_ == 1) return find_last_of(s.ptr_[0], pos);
  172. LookupTable tbl(s);
  173. for (size_type i = std::min(pos, length_ - 1);; --i) {
  174. if (tbl[ptr_[i]]) {
  175. return i;
  176. }
  177. if (i == 0) break;
  178. }
  179. return npos;
  180. }
  181. string_view::size_type string_view::find_last_not_of(
  182. string_view s, size_type pos) const noexcept {
  183. if (empty()) return npos;
  184. size_type i = std::min(pos, length_ - 1);
  185. if (s.empty()) return i;
  186. // Avoid the cost of LookupTable() for a single-character search.
  187. if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos);
  188. LookupTable tbl(s);
  189. for (;; --i) {
  190. if (!tbl[ptr_[i]]) {
  191. return i;
  192. }
  193. if (i == 0) break;
  194. }
  195. return npos;
  196. }
  197. string_view::size_type string_view::find_last_not_of(
  198. char c, size_type pos) const noexcept {
  199. if (empty()) return npos;
  200. size_type i = std::min(pos, length_ - 1);
  201. for (;; --i) {
  202. if (ptr_[i] != c) {
  203. return i;
  204. }
  205. if (i == 0) break;
  206. }
  207. return npos;
  208. }
  209. #ifdef Y_ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
  210. constexpr string_view::size_type string_view::npos;
  211. constexpr string_view::size_type string_view::kMaxSize;
  212. #endif
  213. Y_ABSL_NAMESPACE_END
  214. } // namespace y_absl
  215. #endif // Y_ABSL_USES_STD_STRING_VIEW