#ifndef _IV_STRINGPIECE_H_ #define _IV_STRINGPIECE_H_ #pragma once #include #include #include #include #include namespace iv { namespace core { template > class BasicStringPiece { public: typedef size_t size_type; typedef BasicStringPiece this_type; private: const CharT* ptr_; size_type length_; public: // We provide non-explicit singleton constructors so users can pass // in a "const char*" or a "string" wherever a "StringPiece" is // expected. BasicStringPiece() : ptr_(NULL), length_(0) { } BasicStringPiece(const CharT* str) // NOLINT : ptr_(str), length_((str == NULL) ? 0 : Traits::length(str)) { } template BasicStringPiece(const std::basic_string& str) // NOLINT : ptr_(str.data()), length_(str.size()) { } BasicStringPiece(const CharT* offset, size_type len) : ptr_(offset), length_(len) { } BasicStringPiece(const BasicStringPiece& str) : ptr_(str.ptr_), length_(str.length_) { } // data() may return a pointer to a buffer with embedded NULs, and the // returned buffer may or may not be null terminated. Therefore it is // typically a mistake to pass data() to a routine that expects a NUL // terminated string. const CharT* data() const { return ptr_; } size_type size() const { return length_; } size_type length() const { return length_; } bool empty() const { return length_ == 0; } void clear() { ptr_ = NULL; length_ = 0; } void set(const CharT* data, size_type len) { ptr_ = data; length_ = len; } void set(const CharT* str) { ptr_ = str; length_ = str ? Traits::length(str) : 0; } void set(const void* data, size_type len) { ptr_ = reinterpret_cast(data); length_ = len; } CharT operator[](size_type i) const { return ptr_[i]; } void remove_prefix(size_type n) { ptr_ += n; length_ -= n; } void remove_suffix(size_type n) { length_ -= n; } int compare(const this_type& x) const { int r = wordmemcmp(ptr_, x.ptr_, std::min(length_, x.length_)); if (r == 0) { if (length_ < x.length_) r = -1; else if (length_ > x.length_) r = +1; } return r; } std::basic_string as_string() const { // std::basic_string doesn't like to // take a NULL pointer even with a 0 size. if (!empty()) { return std::basic_string(data(), size()); } else { return std::basic_string(); } } template void CopyToString(std::basic_string* target) const { if (!empty()) { target->assign(data(), size()); } else { target->assign(0UL, static_cast('\0')); } } template void AppendToString(std::basic_string* target) const { if (!empty()) target->append(data(), size()); } // Does "this" start with "x" bool starts_with(const this_type& x) const { return ((length_ >= x.length_) && (wordmemcmp(ptr_, x.ptr_, x.length_) == 0)); } // Does "this" end with "x" bool ends_with(const this_type& x) const { return ((length_ >= x.length_) && (wordmemcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0)); } // standard STL container boilerplate typedef CharT value_type; typedef const CharT* pointer; typedef const CharT& reference; typedef const CharT& const_reference; typedef ptrdiff_t difference_type; static const size_type npos = -1; typedef const CharT* const_iterator; typedef const CharT* iterator; typedef std::reverse_iterator const_reverse_iterator; typedef std::reverse_iterator reverse_iterator; iterator begin() const { return ptr_; } iterator end() const { return ptr_ + length_; } const_reverse_iterator rbegin() const { return const_reverse_iterator(ptr_ + length_); } const_reverse_iterator rend() const { return const_reverse_iterator(ptr_); } size_type max_size() const { return length_; } size_type capacity() const { return length_; } size_type copy(CharT* buf, size_type n, size_type pos = 0) const { size_type ret = std::min(length_ - pos, n); memcpy(buf, ptr_ + pos, ret); return ret; } size_type find(const this_type& s, size_type pos = 0) const { if (pos > length_) return npos; const CharT * result = std::search(ptr_ + pos, ptr_ + length_, s.ptr_, s.ptr_ + s.length_); const size_type xpos = result - ptr_; return xpos + s.length_ <= length_ ? xpos : npos; } size_type find(CharT c, size_type pos = 0) const { if (pos >= length_) return npos; const CharT * result = std::find(ptr_ + pos, ptr_ + length_, c); return result != ptr_ + length_ ? static_cast(result - ptr_) : npos; } size_type rfind(const this_type& s, size_type pos = npos) const { if (length_ < s.length_) return npos; if (s.empty()) return std::min(length_, pos); const CharT * last = ptr_ + std::min(length_ - s.length_, pos) + s.length_; const CharT * result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_); return result != last ? static_cast(result - ptr_) : npos; } size_type rfind(CharT c, size_type pos = npos) const { if (length_ == 0) return npos; for (size_type i = std::min(pos, length_ - 1); ; --i) { if (ptr_[i] == c) return i; if (i == 0) break; } return npos; } size_type find_first_of(const this_type& s, size_type pos) const { if (length_ == 0 || s.length_ == 0) return npos; // Avoid the cost of BuildLookupTable() for a single-character search. if (s.length_ == 1) return find_first_of(s.ptr_[0], pos); bool lookup[std::numeric_limits::max() + 1] = { false }; BuildLookupTable(s, lookup); for (size_type i = pos; i < length_; ++i) { if (lookup[static_cast(ptr_[i])]) { return i; } } return npos; } size_type find_first_of(CharT c, size_type pos = 0) const { return find(c, pos); } size_type find_first_not_of(const this_type& s, size_type pos) const { if (length_ == 0) return npos; if (s.length_ == 0) return 0; // Avoid the cost of BuildLookupTable() for a single-character search. if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos); bool lookup[std::numeric_limits::max() + 1] = { false }; BuildLookupTable(s, lookup); for (size_type i = pos; i < length_; ++i) { if (!lookup[static_cast(ptr_[i])]) { return i; } } return npos; } size_type find_first_not_of(CharT c, size_type pos) const { if (length_ == 0) return npos; for (; pos < length_; ++pos) { if (ptr_[pos] != c) { return pos; } } return npos; } size_type find_last_of(const this_type& s, size_type pos) const { if (length_ == 0 || s.length_ == 0) return npos; // Avoid the cost of BuildLookupTable() for a single-character search. if (s.length_ == 1) return find_last_of(s.ptr_[0], pos); bool lookup[std::numeric_limits::max() + 1] = { false }; BuildLookupTable(s, lookup); for (size_type i = std::min(pos, length_ - 1); ; --i) { if (lookup[static_cast(ptr_[i])]) return i; if (i == 0) break; } return npos; } size_type find_last_of(CharT c, size_type pos = npos) const { return rfind(c, pos); } size_type find_last_not_of(const this_type& s, size_type pos) const { if (length_ == 0) return npos; size_type i = std::min(pos, length_ - 1); if (s.length_ == 0) return i; // Avoid the cost of BuildLookupTable() for a single-character search. if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos); bool lookup[std::numeric_limits::max() + 1] = { false }; BuildLookupTable(s, lookup); for (; ; --i) { if (!lookup[static_cast(ptr_[i])]) return i; if (i == 0) break; } return npos; } size_type find_last_not_of(CharT c, size_type pos) const { if (length_ == 0) return npos; for (size_type i = std::min(pos, length_ - 1); ; --i) { if (ptr_[i] != c) return i; if (i == 0) break; } return npos; } this_type substr(size_type pos, size_type n) const { if (pos > length_) pos = length_; if (n > length_ - pos) n = length_ - pos; return this_type(ptr_ + pos, n); } static int wordmemcmp(const CharT * p, const CharT * p2, size_type N) { return memcmp(p, p2, N); } static inline void BuildLookupTable(const this_type& characters_wanted, bool* table) { const size_type length = characters_wanted.length(); const CharT * const data = characters_wanted.data(); for (size_type i = 0; i < length; ++i) { table[static_cast(data[i])] = true; } } }; template bool operator==(const BasicStringPiece& x, const BasicStringPiece& y) { if (x.size() != y.size()) return false; return BasicStringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0; } template inline bool operator!=(const BasicStringPiece& x, const BasicStringPiece& y) { return !(x == y); } template inline bool operator<(const BasicStringPiece& x, const BasicStringPiece& y) { const int r = BasicStringPiece::wordmemcmp(x.data(), y.data(), std::min(x.size(), y.size())); return ((r < 0) || ((r == 0) && (x.size() < y.size()))); } template inline bool operator>(const BasicStringPiece& x, const BasicStringPiece& y) { return y < x; } template inline bool operator<=(const BasicStringPiece& x, const BasicStringPiece& y) { return !(x > y); } template inline bool operator>=(const BasicStringPiece& x, const BasicStringPiece& y) { return !(x < y); } // allow StringPiece to be logged (needed for unit testing). template std::ostream& operator<<(std::ostream& o, const BasicStringPiece& piece) { o.write(piece.data(), static_cast(piece.size())); return o; } typedef BasicStringPiece > StringPiece; } } // namespace iv::core #endif // _IV_STRINGPIECE_H_