jpayne@69: // © 2016 and later: Unicode, Inc. and others. jpayne@69: // License & terms of use: http://www.unicode.org/copyright.html jpayne@69: // Copyright (C) 2009-2013, International Business Machines jpayne@69: // Corporation and others. All Rights Reserved. jpayne@69: // jpayne@69: // Copyright 2001 and onwards Google Inc. jpayne@69: // Author: Sanjay Ghemawat jpayne@69: jpayne@69: // This code is a contribution of Google code, and the style used here is jpayne@69: // a compromise between the original Google code and the ICU coding guidelines. jpayne@69: // For example, data types are ICU-ified (size_t,int->int32_t), jpayne@69: // and API comments doxygen-ified, but function names and behavior are jpayne@69: // as in the original, if possible. jpayne@69: // Assertion-style error handling, not available in ICU, was changed to jpayne@69: // parameter "pinning" similar to UnicodeString. jpayne@69: // jpayne@69: // In addition, this is only a partial port of the original Google code, jpayne@69: // limited to what was needed so far. The (nearly) complete original code jpayne@69: // is in the ICU svn repository at icuhtml/trunk/design/strings/contrib jpayne@69: // (see ICU ticket 6765, r25517). jpayne@69: jpayne@69: #ifndef __STRINGPIECE_H__ jpayne@69: #define __STRINGPIECE_H__ jpayne@69: jpayne@69: /** jpayne@69: * \file jpayne@69: * \brief C++ API: StringPiece: Read-only byte string wrapper class. jpayne@69: */ jpayne@69: jpayne@69: #include "unicode/utypes.h" jpayne@69: jpayne@69: #if U_SHOW_CPLUSPLUS_API jpayne@69: jpayne@69: #include jpayne@69: #include jpayne@69: jpayne@69: #include "unicode/uobject.h" jpayne@69: #include "unicode/std_string.h" jpayne@69: jpayne@69: // Arghh! I wish C++ literals were "string". jpayne@69: jpayne@69: U_NAMESPACE_BEGIN jpayne@69: jpayne@69: /** jpayne@69: * A string-like object that points to a sized piece of memory. jpayne@69: * jpayne@69: * We provide non-explicit singleton constructors so users can pass jpayne@69: * in a "const char*" or a "string" wherever a "StringPiece" is jpayne@69: * expected. jpayne@69: * jpayne@69: * Functions or methods may use StringPiece parameters to accept either a jpayne@69: * "const char*" or a "string" value that will be implicitly converted to a jpayne@69: * StringPiece. jpayne@69: * jpayne@69: * Systematic usage of StringPiece is encouraged as it will reduce unnecessary jpayne@69: * conversions from "const char*" to "string" and back again. jpayne@69: * jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: class U_COMMON_API StringPiece : public UMemory { jpayne@69: private: jpayne@69: const char* ptr_; jpayne@69: int32_t length_; jpayne@69: jpayne@69: public: jpayne@69: /** jpayne@69: * Default constructor, creates an empty StringPiece. jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: StringPiece() : ptr_(nullptr), length_(0) { } jpayne@69: jpayne@69: /** jpayne@69: * Constructs from a NUL-terminated const char * pointer. jpayne@69: * @param str a NUL-terminated const char * pointer jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: StringPiece(const char* str); jpayne@69: #ifndef U_HIDE_DRAFT_API jpayne@69: #if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN) jpayne@69: /** jpayne@69: * Constructs from a NUL-terminated const char8_t * pointer. jpayne@69: * @param str a NUL-terminated const char8_t * pointer jpayne@69: * @draft ICU 67 jpayne@69: */ jpayne@69: StringPiece(const char8_t* str) : StringPiece(reinterpret_cast(str)) {} jpayne@69: #endif jpayne@69: /** jpayne@69: * Constructs an empty StringPiece. jpayne@69: * Needed for type disambiguation from multiple other overloads. jpayne@69: * @param p nullptr jpayne@69: * @draft ICU 67 jpayne@69: */ jpayne@69: StringPiece(std::nullptr_t p) : ptr_(p), length_(0) {} jpayne@69: #endif // U_HIDE_DRAFT_API jpayne@69: jpayne@69: /** jpayne@69: * Constructs from a std::string. jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: StringPiece(const std::string& str) jpayne@69: : ptr_(str.data()), length_(static_cast(str.size())) { } jpayne@69: #ifndef U_HIDE_DRAFT_API jpayne@69: #if defined(__cpp_lib_char8_t) || defined(U_IN_DOXYGEN) jpayne@69: /** jpayne@69: * Constructs from a std::u8string. jpayne@69: * @draft ICU 67 jpayne@69: */ jpayne@69: StringPiece(const std::u8string& str) jpayne@69: : ptr_(reinterpret_cast(str.data())), jpayne@69: length_(static_cast(str.size())) { } jpayne@69: #endif jpayne@69: #endif // U_HIDE_DRAFT_API jpayne@69: jpayne@69: #ifndef U_HIDE_DRAFT_API jpayne@69: /** jpayne@69: * Constructs from some other implementation of a string piece class, from any jpayne@69: * C++ record type that has these two methods: jpayne@69: * jpayne@69: * \code{.cpp} jpayne@69: * jpayne@69: * struct OtherStringPieceClass { jpayne@69: * const char* data(); // or const char8_t* jpayne@69: * size_t size(); jpayne@69: * }; jpayne@69: * jpayne@69: * \endcode jpayne@69: * jpayne@69: * The other string piece class will typically be std::string_view from C++17 jpayne@69: * or absl::string_view from Abseil. jpayne@69: * jpayne@69: * Starting with C++20, data() may also return a const char8_t* pointer, jpayne@69: * as from std::u8string_view. jpayne@69: * jpayne@69: * @param str the other string piece jpayne@69: * @draft ICU 65 jpayne@69: */ jpayne@69: template ::value jpayne@69: #if defined(__cpp_char8_t) jpayne@69: || std::is_same::value jpayne@69: #endif jpayne@69: ) && jpayne@69: std::is_same::value>::type> jpayne@69: StringPiece(T str) jpayne@69: : ptr_(reinterpret_cast(str.data())), jpayne@69: length_(static_cast(str.size())) {} jpayne@69: #endif // U_HIDE_DRAFT_API jpayne@69: jpayne@69: /** jpayne@69: * Constructs from a const char * pointer and a specified length. jpayne@69: * @param offset a const char * pointer (need not be terminated) jpayne@69: * @param len the length of the string; must be non-negative jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: StringPiece(const char* offset, int32_t len) : ptr_(offset), length_(len) { } jpayne@69: #ifndef U_HIDE_DRAFT_API jpayne@69: #if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN) jpayne@69: /** jpayne@69: * Constructs from a const char8_t * pointer and a specified length. jpayne@69: * @param str a const char8_t * pointer (need not be terminated) jpayne@69: * @param len the length of the string; must be non-negative jpayne@69: * @draft ICU 67 jpayne@69: */ jpayne@69: StringPiece(const char8_t* str, int32_t len) : jpayne@69: StringPiece(reinterpret_cast(str), len) {} jpayne@69: #endif jpayne@69: #endif // U_HIDE_DRAFT_API jpayne@69: jpayne@69: /** jpayne@69: * Substring of another StringPiece. jpayne@69: * @param x the other StringPiece jpayne@69: * @param pos start position in x; must be non-negative and <= x.length(). jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: StringPiece(const StringPiece& x, int32_t pos); jpayne@69: /** jpayne@69: * Substring of another StringPiece. jpayne@69: * @param x the other StringPiece jpayne@69: * @param pos start position in x; must be non-negative and <= x.length(). jpayne@69: * @param len length of the substring; jpayne@69: * must be non-negative and will be pinned to at most x.length() - pos. jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: StringPiece(const StringPiece& x, int32_t pos, int32_t len); jpayne@69: jpayne@69: /** jpayne@69: * Returns the string pointer. May be nullptr if it is empty. jpayne@69: * jpayne@69: * data() may return a pointer to a buffer with embedded NULs, and the jpayne@69: * returned buffer may or may not be null terminated. Therefore it is jpayne@69: * typically a mistake to pass data() to a routine that expects a NUL jpayne@69: * terminated string. jpayne@69: * @return the string pointer jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: const char* data() const { return ptr_; } jpayne@69: /** jpayne@69: * Returns the string length. Same as length(). jpayne@69: * @return the string length jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: int32_t size() const { return length_; } jpayne@69: /** jpayne@69: * Returns the string length. Same as size(). jpayne@69: * @return the string length jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: int32_t length() const { return length_; } jpayne@69: /** jpayne@69: * Returns whether the string is empty. jpayne@69: * @return TRUE if the string is empty jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: UBool empty() const { return length_ == 0; } jpayne@69: jpayne@69: /** jpayne@69: * Sets to an empty string. jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: void clear() { ptr_ = nullptr; length_ = 0; } jpayne@69: jpayne@69: /** jpayne@69: * Reset the stringpiece to refer to new data. jpayne@69: * @param xdata pointer the new string data. Need not be nul terminated. jpayne@69: * @param len the length of the new data jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: void set(const char* xdata, int32_t len) { ptr_ = xdata; length_ = len; } jpayne@69: jpayne@69: /** jpayne@69: * Reset the stringpiece to refer to new data. jpayne@69: * @param str a pointer to a NUL-terminated string. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: void set(const char* str); jpayne@69: jpayne@69: #ifndef U_HIDE_DRAFT_API jpayne@69: #if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN) jpayne@69: /** jpayne@69: * Resets the stringpiece to refer to new data. jpayne@69: * @param xdata pointer the new string data. Need not be NUL-terminated. jpayne@69: * @param len the length of the new data jpayne@69: * @draft ICU 67 jpayne@69: */ jpayne@69: inline void set(const char8_t* xdata, int32_t len) { jpayne@69: set(reinterpret_cast(xdata), len); jpayne@69: } jpayne@69: jpayne@69: /** jpayne@69: * Resets the stringpiece to refer to new data. jpayne@69: * @param str a pointer to a NUL-terminated string. jpayne@69: * @draft ICU 67 jpayne@69: */ jpayne@69: inline void set(const char8_t* str) { jpayne@69: set(reinterpret_cast(str)); jpayne@69: } jpayne@69: #endif jpayne@69: #endif // U_HIDE_DRAFT_API jpayne@69: jpayne@69: /** jpayne@69: * Removes the first n string units. jpayne@69: * @param n prefix length, must be non-negative and <=length() jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: void remove_prefix(int32_t n) { jpayne@69: if (n >= 0) { jpayne@69: if (n > length_) { jpayne@69: n = length_; jpayne@69: } jpayne@69: ptr_ += n; jpayne@69: length_ -= n; jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: /** jpayne@69: * Removes the last n string units. jpayne@69: * @param n suffix length, must be non-negative and <=length() jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: void remove_suffix(int32_t n) { jpayne@69: if (n >= 0) { jpayne@69: if (n <= length_) { jpayne@69: length_ -= n; jpayne@69: } else { jpayne@69: length_ = 0; jpayne@69: } jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: #ifndef U_HIDE_DRAFT_API jpayne@69: /** jpayne@69: * Searches the StringPiece for the given search string (needle); jpayne@69: * @param needle The string for which to search. jpayne@69: * @param offset Where to start searching within this string (haystack). jpayne@69: * @return The offset of needle in haystack, or -1 if not found. jpayne@69: * @draft ICU 67 jpayne@69: */ jpayne@69: int32_t find(StringPiece needle, int32_t offset); jpayne@69: jpayne@69: /** jpayne@69: * Compares this StringPiece with the other StringPiece, with semantics jpayne@69: * similar to std::string::compare(). jpayne@69: * @param other The string to compare to. jpayne@69: * @return below zero if this < other; above zero if this > other; 0 if this == other. jpayne@69: * @draft ICU 67 jpayne@69: */ jpayne@69: int32_t compare(StringPiece other); jpayne@69: #endif // U_HIDE_DRAFT_API jpayne@69: jpayne@69: /** jpayne@69: * Maximum integer, used as a default value for substring methods. jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: static const int32_t npos; // = 0x7fffffff; jpayne@69: jpayne@69: /** jpayne@69: * Returns a substring of this StringPiece. jpayne@69: * @param pos start position; must be non-negative and <= length(). jpayne@69: * @param len length of the substring; jpayne@69: * must be non-negative and will be pinned to at most length() - pos. jpayne@69: * @return the substring StringPiece jpayne@69: * @stable ICU 4.2 jpayne@69: */ jpayne@69: StringPiece substr(int32_t pos, int32_t len = npos) const { jpayne@69: return StringPiece(*this, pos, len); jpayne@69: } jpayne@69: }; jpayne@69: jpayne@69: /** jpayne@69: * Global operator == for StringPiece jpayne@69: * @param x The first StringPiece to compare. jpayne@69: * @param y The second StringPiece to compare. jpayne@69: * @return TRUE if the string data is equal jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: U_EXPORT UBool U_EXPORT2 jpayne@69: operator==(const StringPiece& x, const StringPiece& y); jpayne@69: jpayne@69: /** jpayne@69: * Global operator != for StringPiece jpayne@69: * @param x The first StringPiece to compare. jpayne@69: * @param y The second StringPiece to compare. jpayne@69: * @return TRUE if the string data is not equal jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: inline UBool operator!=(const StringPiece& x, const StringPiece& y) { jpayne@69: return !(x == y); jpayne@69: } jpayne@69: jpayne@69: U_NAMESPACE_END jpayne@69: jpayne@69: #endif /* U_SHOW_CPLUSPLUS_API */ jpayne@69: jpayne@69: #endif // __STRINGPIECE_H__