summaryrefslogtreecommitdiff
path: root/src/mongo/base
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
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')
-rw-r--r--src/mongo/base/parse_number.cpp11
-rw-r--r--src/mongo/base/parse_number_test.cpp4
-rw-r--r--src/mongo/base/string_data-inl.h145
-rw-r--r--src/mongo/base/string_data.h136
-rw-r--r--src/mongo/base/string_data_test.cpp34
5 files changed, 149 insertions, 181 deletions
diff --git a/src/mongo/base/parse_number.cpp b/src/mongo/base/parse_number.cpp
index 7aa112f08be..b9c81807b19 100644
--- a/src/mongo/base/parse_number.cpp
+++ b/src/mongo/base/parse_number.cpp
@@ -95,8 +95,8 @@ static inline StringData _extractSign(StringData stringValue, bool* isNegative)
* "0x" or "0X" prefix, if present.
*/
static inline StringData _extractBase(StringData stringValue, int inputBase, int* outputBase) {
- const StringData hexPrefixLower("0x", StringData::LiteralTag());
- const StringData hexPrefixUpper("0X", StringData::LiteralTag());
+ const auto hexPrefixLower = "0x"_sd;
+ const auto hexPrefixUpper = "0X"_sd;
if (inputBase == 0) {
if (stringValue.size() > 2 &&
(stringValue.startsWith(hexPrefixLower) || stringValue.startsWith(hexPrefixUpper))) {
@@ -239,14 +239,13 @@ Status parseNumberFromStringWithBase<double>(StringData stringValue, int base, d
// The Windows libc implementation of strtod cannot parse +/-infinity or nan,
// so handle that here.
std::transform(str.begin(), str.end(), str.begin(), toLowerAscii);
- if (str == StringData("nan", StringData::LiteralTag())) {
+ if (str == "nan"_sd) {
*result = std::numeric_limits<double>::quiet_NaN();
return Status::OK();
- } else if (str == StringData("+infinity", StringData::LiteralTag()) ||
- str == StringData("infinity", StringData::LiteralTag())) {
+ } else if (str == "+infinity"_sd || str == "infinity"_sd) {
*result = std::numeric_limits<double>::infinity();
return Status::OK();
- } else if (str == StringData("-infinity", StringData::LiteralTag())) {
+ } else if (str == "-infinity"_sd) {
*result = -std::numeric_limits<double>::infinity();
return Status::OK();
}
diff --git a/src/mongo/base/parse_number_test.cpp b/src/mongo/base/parse_number_test.cpp
index df2902800e0..0ed768a7dd3 100644
--- a/src/mongo/base/parse_number_test.cpp
+++ b/src/mongo/base/parse_number_test.cpp
@@ -249,9 +249,7 @@ TEST(Double, TestParsingGarbage) {
ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("1e6 ", &d));
ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>(" 1e6", &d));
ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("0xabcab.defPa", &d));
- ASSERT_EQUALS(
- ErrorCodes::FailedToParse,
- parseNumberFromString<double>(StringData("1.0\0garbage", StringData::LiteralTag()), &d));
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("1.0\0garbage"_sd, &d));
}
TEST(Double, TestParsingOverflow) {
diff --git a/src/mongo/base/string_data-inl.h b/src/mongo/base/string_data-inl.h
deleted file mode 100644
index a8342aa88bb..00000000000
--- a/src/mongo/base/string_data-inl.h
+++ /dev/null
@@ -1,145 +0,0 @@
-// string_data_inline.h
-
-/* Copyright 2010 10gen Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the GNU Affero General Public License in all respects
- * for all of the code used other than as permitted herein. If you modify
- * file(s) with this exception, you may extend this exception to your
- * version of the file(s), but you are not obligated to do so. If you do not
- * wish to do so, delete this exception statement from your version. If you
- * delete this exception statement from all source files in the program,
- * then also delete it in the license file.
- */
-
-// this should never be included directly
-
-#include <stdexcept>
-
-namespace mongo {
-
-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;
-
- 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
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
diff --git a/src/mongo/base/string_data_test.cpp b/src/mongo/base/string_data_test.cpp
index 5dc19df3dd8..2c5e6c4019f 100644
--- a/src/mongo/base/string_data_test.cpp
+++ b/src/mongo/base/string_data_test.cpp
@@ -33,9 +33,8 @@
#include "mongo/base/string_data.h"
#include "mongo/unittest/unittest.h"
-namespace {
+namespace mongo {
-using mongo::StringData;
using std::string;
TEST(Construction, Empty) {
@@ -65,10 +64,22 @@ TEST(Construction, FromNullCString) {
ASSERT_TRUE(strData.rawData() == NULL);
}
-TEST(Construction, FromLiteral) {
- StringData strData("ccc", StringData::LiteralTag());
- ASSERT_EQUALS(strData.size(), 3U);
- ASSERT_EQUALS(strData.toString(), string("ccc"));
+TEST(Construction, FromUserDefinedLiteral) {
+ const auto strData = "cc\0c"_sd;
+ ASSERT_EQUALS(strData.size(), 4U);
+ ASSERT_EQUALS(strData.toString(), string("cc\0c", 4));
+}
+
+TEST(Construction, FromUserDefinedRawLiteral) {
+ const auto strData = R"("")"_sd;
+ ASSERT_EQUALS(strData.size(), 2U);
+ ASSERT_EQUALS(strData.toString(), string("\"\"", 2));
+}
+
+TEST(Construction, FromEmptyUserDefinedLiteral) {
+ const auto strData = ""_sd;
+ ASSERT_EQUALS(strData.size(), 0U);
+ ASSERT_EQUALS(strData.toString(), string(""));
}
TEST(Comparison, BothEmpty) {
@@ -266,8 +277,7 @@ TEST(EndsWith, Simple) {
TEST(ConstIterator, StdCopy) {
std::vector<char> chars;
- const char rawData[] = "This is some raw data.";
- StringData data(rawData, StringData::LiteralTag());
+ auto data = "This is some raw data."_sd;
chars.resize(data.size());
std::copy(data.begin(), data.end(), chars.begin());
@@ -279,8 +289,7 @@ TEST(ConstIterator, StdCopy) {
TEST(ConstIterator, StdReverseCopy) {
std::vector<char> chars;
- const char rawData[] = "This is some raw data.";
- StringData data(rawData, StringData::LiteralTag());
+ auto data = "This is some raw data."_sd;
chars.resize(data.size());
std::reverse_copy(data.begin(), data.end(), chars.begin());
@@ -294,8 +303,7 @@ TEST(ConstIterator, StdReverseCopy) {
TEST(ConstIterator, StdReplaceCopy) {
std::vector<char> chars;
- const char rawData[] = "This is some raw data.";
- StringData data(rawData, StringData::LiteralTag());
+ auto data = "This is some raw data."_sd;
chars.resize(data.size());
std::replace_copy(data.begin(), data.end(), chars.begin(), ' ', '_');
@@ -307,4 +315,4 @@ TEST(ConstIterator, StdReplaceCopy) {
}
}
-} // unnamed namespace
+} // namespace mongo