summaryrefslogtreecommitdiff
path: root/src/mongo/base/string_data.h
diff options
context:
space:
mode:
authorJason Carey <jcarey@argv.me>2016-05-10 14:17:00 -0400
committerJason Carey <jcarey@argv.me>2016-06-17 17:56:11 -0400
commit907182f4672ab2dcea1e16da5366518a4e44fa8d (patch)
treeb74d4d9f97a3797b409db0f428ac05462501fa73 /src/mongo/base/string_data.h
parent737d557b1729d8d6c2892832b75630f045787ec1 (diff)
downloadmongo-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.h136
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