diff options
author | Jason Carey <jcarey@argv.me> | 2016-05-10 14:17:00 -0400 |
---|---|---|
committer | Jason Carey <jcarey@argv.me> | 2016-06-17 17:56:11 -0400 |
commit | 907182f4672ab2dcea1e16da5366518a4e44fa8d (patch) | |
tree | b74d4d9f97a3797b409db0f428ac05462501fa73 /src/mongo/base/string_data.h | |
parent | 737d557b1729d8d6c2892832b75630f045787ec1 (diff) | |
download | mongo-907182f4672ab2dcea1e16da5366518a4e44fa8d.tar.gz |
SERVER-24651 Add and use string data literals
Replace StringData("foo", StringData::LiteralTag()) with "foo"_sd
Diffstat (limited to 'src/mongo/base/string_data.h')
-rw-r--r-- | src/mongo/base/string_data.h | 136 |
1 files changed, 122 insertions, 14 deletions
diff --git a/src/mongo/base/string_data.h b/src/mongo/base/string_data.h index 86c809fc7a7..b1491b919e6 100644 --- a/src/mongo/base/string_data.h +++ b/src/mongo/base/string_data.h @@ -33,6 +33,7 @@ #include <cstring> #include <iosfwd> #include <limits> +#include <stdexcept> #include <string> #define MONGO_INCLUDE_INVARIANT_H_WHITELISTED @@ -56,14 +57,14 @@ namespace mongo { */ class StringData { struct TrustedInitTag {}; - StringData(const char* c, size_t len, TrustedInitTag) : _data(c), _size(len) {} + constexpr StringData(const char* c, size_t len, TrustedInitTag) : _data(c), _size(len) {} public: // Declared in string_data_comparator_interface.h. class ComparatorInterface; /** Constructs an empty StringData. */ - StringData() = default; + constexpr StringData() = default; /** * Constructs a StringData, for the case where the length of the @@ -73,16 +74,6 @@ public: StringData(const char* str) : StringData(str, str ? std::strlen(str) : 0) {} /** - * Constructs a StringData explicitly, for the case of a literal - * whose size is known at compile time. Note that you probably - * don't need this on a modern compiler that can see that the call - * to std::strlen on StringData("foo") can be constexpr'ed out. - */ - struct LiteralTag {}; - template <size_t N> - StringData(const char (&val)[N], LiteralTag) : StringData(&val[0], N - 1) {} - - /** * Constructs a StringData, for the case of a std::string. We can * use the trusted init path with no follow on checks because * string::data is assured to never return nullptr. @@ -101,6 +92,12 @@ public: } /** + * Constructs a StringData from a user defined literal. This allows + * for constexpr creation of StringData's that are known at compile time. + */ + constexpr friend StringData operator"" _sd(const char* c, std::size_t len); + + /** * Returns -1, 0, or 1 if 'this' is less, equal, or greater than 'other' in * lexicographical order. */ @@ -214,6 +211,117 @@ inline bool operator>=(StringData lhs, StringData rhs) { std::ostream& operator<<(std::ostream& stream, StringData value); -} // namespace mongo +constexpr StringData operator"" _sd(const char* c, std::size_t len) { + return StringData(c, len, StringData::TrustedInitTag{}); +} + +inline int StringData::compare(StringData other) const { + // It is illegal to pass nullptr to memcmp. It is an invariant of + // StringData that if _data is nullptr, _size is zero. If asked to + // compare zero bytes, memcmp returns zero (how could they + // differ?). So, if either StringData object has a nullptr _data + // object, then memcmp would return zero. Achieve this by assuming + // zero, and only calling memcmp if both pointers are valid. + int res = 0; + if (_data && other._data) + res = memcmp(_data, other._data, std::min(_size, other._size)); + + if (res != 0) + return res > 0 ? 1 : -1; + + if (_size == other._size) + return 0; -#include "mongo/base/string_data-inl.h" + return _size > other._size ? 1 : -1; +} + +inline bool StringData::equalCaseInsensitive(StringData other) const { + if (other.size() != size()) + return false; + + for (size_t x = 0; x < size(); x++) { + char a = _data[x]; + char b = other._data[x]; + if (a == b) + continue; + if (tolower(a) == tolower(b)) + continue; + return false; + } + + return true; +} + +inline void StringData::copyTo(char* dest, bool includeEndingNull) const { + if (_data) + memcpy(dest, _data, size()); + if (includeEndingNull) + dest[size()] = 0; +} + +inline size_t StringData::find(char c, size_t fromPos) const { + if (fromPos >= size()) + return std::string::npos; + + const void* x = memchr(_data + fromPos, c, _size - fromPos); + if (x == 0) + return std::string::npos; + return static_cast<size_t>(static_cast<const char*>(x) - _data); +} + +inline size_t StringData::find(StringData needle) const { + size_t mx = size(); + size_t needleSize = needle.size(); + + if (needleSize == 0) + return 0; + else if (needleSize > mx) + return std::string::npos; + + mx -= needleSize; + + for (size_t i = 0; i <= mx; i++) { + if (memcmp(_data + i, needle._data, needleSize) == 0) + return i; + } + return std::string::npos; +} + +inline size_t StringData::rfind(char c, size_t fromPos) const { + const size_t sz = size(); + if (fromPos > sz) + fromPos = sz; + + for (const char* cur = _data + fromPos; cur > _data; --cur) { + if (*(cur - 1) == c) + return (cur - _data) - 1; + } + return std::string::npos; +} + +inline StringData StringData::substr(size_t pos, size_t n) const { + if (pos > size()) + throw std::out_of_range("out of range"); + + // truncate to end of string + if (n > size() - pos) + n = size() - pos; + + return StringData(_data + pos, n); +} + +inline bool StringData::startsWith(StringData prefix) const { + // TODO: Investigate an optimized implementation. + return substr(0, prefix.size()) == prefix; +} + +inline bool StringData::endsWith(StringData suffix) const { + // TODO: Investigate an optimized implementation. + const size_t thisSize = size(); + const size_t suffixSize = suffix.size(); + if (suffixSize > thisSize) + return false; + return substr(thisSize - suffixSize) == suffix; +} + +} // namespace mongo |