From 96ad39f93f670e9e09a1e430898e3b9a8bd70f54 Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Tue, 9 Apr 2019 17:29:16 -0400 Subject: SERVER-40476 merge contents of utils/stringutils into utils/str. --- src/mongo/SConscript | 2 +- src/mongo/base/data_type_terminated.cpp | 11 +- src/mongo/base/data_type_terminated_test.cpp | 1 - src/mongo/bson/bsonelement.cpp | 13 +- src/mongo/bson/bsonobj.cpp | 3 +- src/mongo/db/auth/action_set.cpp | 5 +- src/mongo/db/auth/authorization_manager_impl.cpp | 2 +- .../db/auth/authz_manager_external_state_s.cpp | 1 - src/mongo/db/auth/sasl_commands.cpp | 1 - src/mongo/db/auth/user_document_parser.cpp | 3 +- .../db/auth/user_management_commands_parser.cpp | 3 +- src/mongo/db/catalog/rename_collection_test.cpp | 5 +- src/mongo/db/concurrency/lock_manager.cpp | 2 +- src/mongo/db/curop.cpp | 6 +- src/mongo/db/fts/fts_basic_tokenizer.cpp | 3 +- src/mongo/db/fts/fts_element_iterator.cpp | 1 - src/mongo/db/fts/fts_language.cpp | 1 - src/mongo/db/fts/fts_query_impl.cpp | 1 - src/mongo/db/fts/fts_query_parser.cpp | 1 - src/mongo/db/fts/fts_spec.cpp | 1 - src/mongo/db/fts/fts_spec_legacy.cpp | 22 +- src/mongo/db/fts/fts_unicode_tokenizer.cpp | 1 - src/mongo/db/fts/tokenizer.cpp | 1 - src/mongo/db/kill_sessions_common.h | 2 +- src/mongo/db/mongod_options.cpp | 3 +- src/mongo/db/pipeline/document_path_support.cpp | 4 +- src/mongo/db/pipeline/document_source_match.cpp | 2 +- src/mongo/db/query/get_executor.cpp | 2 +- src/mongo/db/query/getmore_request.cpp | 2 +- src/mongo/db/query/parsed_distinct.cpp | 4 +- src/mongo/db/repl/repl_set_config.cpp | 4 +- src/mongo/db/s/balancer/balancer_policy.cpp | 2 +- src/mongo/db/s/get_database_version_command.cpp | 2 +- src/mongo/db/s/get_shard_version_command.cpp | 2 +- src/mongo/db/s/set_shard_version_command.cpp | 2 +- src/mongo/db/s/unset_sharding_command.cpp | 2 +- src/mongo/db/update/path_support.cpp | 5 +- src/mongo/db/update/update_driver.cpp | 1 - src/mongo/db/update/update_leaf_node.cpp | 4 +- src/mongo/db/update/update_object_node.cpp | 4 +- src/mongo/dbtests/basictests.cpp | 2 +- src/mongo/dbtests/jsobjtests.cpp | 12 +- src/mongo/idl/server_parameter_with_storage.h | 4 +- src/mongo/logger/parse_log_component_settings.cpp | 1 - src/mongo/platform/decimal128.cpp | 12 +- src/mongo/s/catalog/mongo_version_range.cpp | 11 +- src/mongo/s/mongos_options.cpp | 5 +- src/mongo/s/server.cpp | 2 +- src/mongo/scripting/mozjs/wrapconstrainedmethod.h | 2 +- src/mongo/shell/dbshell.cpp | 10 +- src/mongo/shell/shell_utils_launcher.cpp | 4 +- src/mongo/transport/service_executor_adaptive.cpp | 2 +- src/mongo/util/SConscript | 4 +- src/mongo/util/net/hostandport.cpp | 5 +- src/mongo/util/processinfo_solaris.cpp | 3 +- src/mongo/util/stacktrace_posix.cpp | 4 +- src/mongo/util/str.cpp | 239 ++++++++++++++++++ src/mongo/util/str.h | 58 +++++ src/mongo/util/str_test.cpp | 273 +++++++++++++++++++++ src/mongo/util/stringutils.cpp | 243 ------------------ src/mongo/util/stringutils.h | 116 --------- src/mongo/util/stringutils_test.cpp | 273 --------------------- 62 files changed, 672 insertions(+), 750 deletions(-) create mode 100644 src/mongo/util/str.cpp create mode 100644 src/mongo/util/str_test.cpp delete mode 100644 src/mongo/util/stringutils.cpp delete mode 100644 src/mongo/util/stringutils.h delete mode 100644 src/mongo/util/stringutils_test.cpp diff --git a/src/mongo/SConscript b/src/mongo/SConscript index dc0dc2b5628..8cf44ff1562 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -130,7 +130,7 @@ env.Library( 'util/stacktrace.cpp', 'util/stacktrace_${TARGET_OS_FAMILY}.cpp', 'util/startup_test.cpp', - 'util/stringutils.cpp', + 'util/str.cpp', 'util/system_clock_source.cpp', 'util/system_tick_source.cpp', 'util/text.cpp', diff --git a/src/mongo/base/data_type_terminated.cpp b/src/mongo/base/data_type_terminated.cpp index 5074abbe22f..e3daa5d33dc 100644 --- a/src/mongo/base/data_type_terminated.cpp +++ b/src/mongo/base/data_type_terminated.cpp @@ -30,7 +30,6 @@ #include "mongo/base/data_type_terminated.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { @@ -38,8 +37,8 @@ Status TerminatedHelper::makeLoadNoTerminalStatus(char c, size_t length, std::ptrdiff_t debug_offset) { str::stream ss; - ss << "couldn't locate terminal char (" << escape(StringData(&c, 1)) << ") in buffer[" << length - << "] at offset: " << debug_offset; + ss << "couldn't locate terminal char (" << str::escape(StringData(&c, 1)) << ") in buffer[" + << length << "] at offset: " << debug_offset; return Status(ErrorCodes::Overflow, ss); } @@ -49,15 +48,15 @@ Status TerminatedHelper::makeLoadShortReadStatus(char c, std::ptrdiff_t debug_offset) { str::stream ss; ss << "only read (" << read << ") bytes. (" << length << ") bytes to terminal char (" - << escape(StringData(&c, 1)) << ") at offset: " << debug_offset; + << str::escape(StringData(&c, 1)) << ") at offset: " << debug_offset; return Status(ErrorCodes::Overflow, ss); } Status TerminatedHelper::makeStoreStatus(char c, size_t length, std::ptrdiff_t debug_offset) { str::stream ss; - ss << "couldn't write terminal char (" << escape(StringData(&c, 1)) << ") in buffer[" << length - << "] at offset: " << debug_offset; + ss << "couldn't write terminal char (" << str::escape(StringData(&c, 1)) << ") in buffer[" + << length << "] at offset: " << debug_offset; return Status(ErrorCodes::Overflow, ss); } diff --git a/src/mongo/base/data_type_terminated_test.cpp b/src/mongo/base/data_type_terminated_test.cpp index 45635760c6e..d516626e3b9 100644 --- a/src/mongo/base/data_type_terminated_test.cpp +++ b/src/mongo/base/data_type_terminated_test.cpp @@ -32,7 +32,6 @@ #include "mongo/base/data_range.h" #include "mongo/base/data_range_cursor.h" #include "mongo/unittest/unittest.h" -#include "mongo/util/stringutils.h" #include namespace mongo { diff --git a/src/mongo/bson/bsonelement.cpp b/src/mongo/bson/bsonelement.cpp index 5bef012b292..605623fb54f 100644 --- a/src/mongo/bson/bsonelement.cpp +++ b/src/mongo/bson/bsonelement.cpp @@ -46,7 +46,6 @@ #include "mongo/util/scopeguard.h" #include "mongo/util/str.h" #include "mongo/util/string_map.h" -#include "mongo/util/stringutils.h" #include "mongo/util/uuid.h" namespace mongo { @@ -69,11 +68,11 @@ void BSONElement::jsonStringStream(JsonStringFormat format, int pretty, std::stringstream& s) const { if (includeFieldNames) - s << '"' << escape(fieldName()) << "\" : "; + s << '"' << str::escape(fieldName()) << "\" : "; switch (type()) { case mongo::String: case Symbol: - s << '"' << escape(string(valuestr(), valuestrsize() - 1)) << '"'; + s << '"' << str::escape(string(valuestr(), valuestrsize() - 1)) << '"'; break; case NumberLong: if (format == TenGen) { @@ -271,10 +270,10 @@ void BSONElement::jsonStringStream(JsonStringFormat format, break; case RegEx: if (format == Strict) { - s << "{ \"$regex\" : \"" << escape(regex()); + s << "{ \"$regex\" : \"" << str::escape(regex()); s << "\", \"$options\" : \"" << regexFlags() << "\" }"; } else { - s << "/" << escape(regex(), true) << "/"; + s << "/" << str::escape(regex(), true) << "/"; // FIXME Worry about alpha order? for (const char* f = regexFlags(); *f; ++f) { switch (*f) { @@ -292,14 +291,14 @@ void BSONElement::jsonStringStream(JsonStringFormat format, case CodeWScope: { BSONObj scope = codeWScopeObject(); if (!scope.isEmpty()) { - s << "{ \"$code\" : \"" << escape(_asCode()) << "\" , " + s << "{ \"$code\" : \"" << str::escape(_asCode()) << "\" , " << "\"$scope\" : " << scope.jsonString() << " }"; break; } } case Code: - s << "\"" << escape(_asCode()) << "\""; + s << "\"" << str::escape(_asCode()) << "\""; break; case bsonTimestamp: diff --git a/src/mongo/bson/bsonobj.cpp b/src/mongo/bson/bsonobj.cpp index bae36f39544..57bbd59969b 100644 --- a/src/mongo/bson/bsonobj.cpp +++ b/src/mongo/bson/bsonobj.cpp @@ -39,7 +39,6 @@ #include "mongo/util/hex.h" #include "mongo/util/log.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { @@ -655,7 +654,7 @@ public: bool operator()(const char* s1, const char* s2) const; private: - LexNumCmp _cmp; + str::LexNumCmp _cmp; }; BSONIteratorSorted::ElementFieldCmp::ElementFieldCmp(bool isArray) : _cmp(!isArray) {} diff --git a/src/mongo/db/auth/action_set.cpp b/src/mongo/db/auth/action_set.cpp index 247a5dfac2c..84cefde250b 100644 --- a/src/mongo/db/auth/action_set.cpp +++ b/src/mongo/db/auth/action_set.cpp @@ -40,7 +40,6 @@ #include "mongo/bson/util/builder.h" #include "mongo/util/log.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { @@ -96,7 +95,7 @@ bool ActionSet::isSupersetOf(const ActionSet& other) const { Status ActionSet::parseActionSetFromString(const std::string& actionsString, ActionSet* result) { std::vector actionsList; - splitStringDelim(actionsString, &actionsList, ','); + str::splitStringDelim(actionsString, &actionsList, ','); std::vector unrecognizedActions; Status status = parseActionSetFromStringVector(actionsList, result, &unrecognizedActions); invariant(status); @@ -104,7 +103,7 @@ Status ActionSet::parseActionSetFromString(const std::string& actionsString, Act return Status::OK(); } std::string unrecognizedActionsString; - joinStringDelim(unrecognizedActions, &unrecognizedActionsString, ','); + str::joinStringDelim(unrecognizedActions, &unrecognizedActionsString, ','); return Status(ErrorCodes::FailedToParse, str::stream() << "Unrecognized action privilege strings: " << unrecognizedActionsString); diff --git a/src/mongo/db/auth/authorization_manager_impl.cpp b/src/mongo/db/auth/authorization_manager_impl.cpp index 10b4fd6bdc6..d97b1c5d4b9 100644 --- a/src/mongo/db/auth/authorization_manager_impl.cpp +++ b/src/mongo/db/auth/authorization_manager_impl.cpp @@ -157,7 +157,7 @@ public: Status setFromString(const std::string& str) { std::vector strList; - splitStringDelim(str, &strList, ','); + str::splitStringDelim(str, &strList, ','); std::vector out; for (const auto& nameStr : strList) { diff --git a/src/mongo/db/auth/authz_manager_external_state_s.cpp b/src/mongo/db/auth/authz_manager_external_state_s.cpp index fe73ae30754..fdb23453592 100644 --- a/src/mongo/db/auth/authz_manager_external_state_s.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_s.cpp @@ -47,7 +47,6 @@ #include "mongo/stdx/memory.h" #include "mongo/util/net/ssl_types.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { diff --git a/src/mongo/db/auth/sasl_commands.cpp b/src/mongo/db/auth/sasl_commands.cpp index b9886aaa4f0..c733cbb632b 100644 --- a/src/mongo/db/auth/sasl_commands.cpp +++ b/src/mongo/db/auth/sasl_commands.cpp @@ -55,7 +55,6 @@ #include "mongo/util/log.h" #include "mongo/util/sequence_util.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { namespace { diff --git a/src/mongo/db/auth/user_document_parser.cpp b/src/mongo/db/auth/user_document_parser.cpp index 20387c19892..1c5da7795be 100644 --- a/src/mongo/db/auth/user_document_parser.cpp +++ b/src/mongo/db/auth/user_document_parser.cpp @@ -43,7 +43,6 @@ #include "mongo/db/namespace_string.h" #include "mongo/util/log.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { @@ -478,7 +477,7 @@ Status V2UserDocumentParser::initializeUserPrivilegesFromUserDocument(const BSON } if (unrecognizedActions.size()) { std::string unrecognizedActionsString; - joinStringDelim(unrecognizedActions, &unrecognizedActionsString, ','); + str::joinStringDelim(unrecognizedActions, &unrecognizedActionsString, ','); warning() << "Encountered unrecognized actions \" " << unrecognizedActionsString << "\" while parsing user document for " << user->getName(); } diff --git a/src/mongo/db/auth/user_management_commands_parser.cpp b/src/mongo/db/auth/user_management_commands_parser.cpp index 8a03d8a4b7d..29f4bc53574 100644 --- a/src/mongo/db/auth/user_management_commands_parser.cpp +++ b/src/mongo/db/auth/user_management_commands_parser.cpp @@ -49,7 +49,6 @@ #include "mongo/db/jsobj.h" #include "mongo/stdx/unordered_set.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { namespace auth { @@ -513,7 +512,7 @@ Status parseAndValidatePrivilegeArray(const BSONArray& privileges, } if (unrecognizedActions.size()) { std::string unrecognizedActionsString; - joinStringDelim(unrecognizedActions, &unrecognizedActionsString, ','); + str::joinStringDelim(unrecognizedActions, &unrecognizedActionsString, ','); return Status(ErrorCodes::FailedToParse, str::stream() << "Unrecognized action privilege strings: " << unrecognizedActionsString); diff --git a/src/mongo/db/catalog/rename_collection_test.cpp b/src/mongo/db/catalog/rename_collection_test.cpp index 3756072fcae..30aca29717f 100644 --- a/src/mongo/db/catalog/rename_collection_test.cpp +++ b/src/mongo/db/catalog/rename_collection_test.cpp @@ -61,7 +61,6 @@ #include "mongo/unittest/unittest.h" #include "mongo/util/assert_util.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace { @@ -987,9 +986,9 @@ TEST_F(RenameCollectionTest, RenameDifferentDatabaseStayTempTrueSourceNotTempora void _checkOplogEntries(const std::vector& actualOplogEntries, const std::vector& expectedOplogEntries) { std::string actualOplogEntriesStr; - joinStringDelim(actualOplogEntries, &actualOplogEntriesStr, ','); + str::joinStringDelim(actualOplogEntries, &actualOplogEntriesStr, ','); std::string expectedOplogEntriesStr; - joinStringDelim(expectedOplogEntries, &expectedOplogEntriesStr, ','); + str::joinStringDelim(expectedOplogEntries, &expectedOplogEntriesStr, ','); ASSERT_EQUALS(expectedOplogEntries.size(), actualOplogEntries.size()) << "Incorrect number of oplog entries written to oplog. Actual: " << actualOplogEntriesStr diff --git a/src/mongo/db/concurrency/lock_manager.cpp b/src/mongo/db/concurrency/lock_manager.cpp index 237e182d8eb..0b12fa9a575 100644 --- a/src/mongo/db/concurrency/lock_manager.cpp +++ b/src/mongo/db/concurrency/lock_manager.cpp @@ -43,7 +43,7 @@ #include "mongo/db/concurrency/locker.h" #include "mongo/util/assert_util.h" #include "mongo/util/log.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" #include "mongo/util/timer.h" namespace mongo { diff --git a/src/mongo/db/curop.cpp b/src/mongo/db/curop.cpp index 068de93ec44..2111f168edf 100644 --- a/src/mongo/db/curop.cpp +++ b/src/mongo/db/curop.cpp @@ -54,7 +54,7 @@ #include "mongo/util/hex.h" #include "mongo/util/log.h" #include "mongo/util/net/socket_utils.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { @@ -615,7 +615,7 @@ string OpDebug::report(Client* client, if (clientMetadata) { auto appName = clientMetadata.get().getApplicationName(); if (!appName.empty()) { - s << " appName: \"" << escape(appName) << '\"'; + s << " appName: \"" << str::escape(appName) << '\"'; } } @@ -687,7 +687,7 @@ string OpDebug::report(Client* client, if (!errInfo.isOK()) { s << " ok:" << 0; if (!errInfo.reason().empty()) { - s << " errMsg:\"" << escape(redact(errInfo.reason())) << "\""; + s << " errMsg:\"" << str::escape(redact(errInfo.reason())) << "\""; } s << " errName:" << errInfo.code(); s << " errCode:" << static_cast(errInfo.code()); diff --git a/src/mongo/db/fts/fts_basic_tokenizer.cpp b/src/mongo/db/fts/fts_basic_tokenizer.cpp index 0a46b562955..a7dab749790 100644 --- a/src/mongo/db/fts/fts_basic_tokenizer.cpp +++ b/src/mongo/db/fts/fts_basic_tokenizer.cpp @@ -38,7 +38,6 @@ #include "mongo/db/fts/tokenizer.h" #include "mongo/stdx/memory.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { namespace fts { @@ -69,7 +68,7 @@ bool BasicFTSTokenizer::moveNext() { continue; } - string word = tolowerString(token.data); + string word = str::toLower(token.data); // Stop words are case-sensitive so we need them to be lower cased to check // against the stop word list diff --git a/src/mongo/db/fts/fts_element_iterator.cpp b/src/mongo/db/fts/fts_element_iterator.cpp index 7589904c56e..ebca711dd2b 100644 --- a/src/mongo/db/fts/fts_element_iterator.cpp +++ b/src/mongo/db/fts/fts_element_iterator.cpp @@ -31,7 +31,6 @@ #include "mongo/db/fts/fts_spec.h" #include "mongo/db/fts/fts_util.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" #include diff --git a/src/mongo/db/fts/fts_language.cpp b/src/mongo/db/fts/fts_language.cpp index 518c8a8e9f4..faa54e79333 100644 --- a/src/mongo/db/fts/fts_language.cpp +++ b/src/mongo/db/fts/fts_language.cpp @@ -40,7 +40,6 @@ #include "mongo/util/assert_util.h" #include "mongo/util/str.h" #include "mongo/util/string_map.h" -#include "mongo/util/stringutils.h" namespace mongo { diff --git a/src/mongo/db/fts/fts_query_impl.cpp b/src/mongo/db/fts/fts_query_impl.cpp index 4fc03b24746..fffc4362fbb 100644 --- a/src/mongo/db/fts/fts_query_impl.cpp +++ b/src/mongo/db/fts/fts_query_impl.cpp @@ -36,7 +36,6 @@ #include "mongo/db/fts/fts_tokenizer.h" #include "mongo/stdx/memory.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { diff --git a/src/mongo/db/fts/fts_query_parser.cpp b/src/mongo/db/fts/fts_query_parser.cpp index 4d86580374b..a346e03451b 100644 --- a/src/mongo/db/fts/fts_query_parser.cpp +++ b/src/mongo/db/fts/fts_query_parser.cpp @@ -31,7 +31,6 @@ #include "mongo/db/fts/fts_query_parser.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { diff --git a/src/mongo/db/fts/fts_spec.cpp b/src/mongo/db/fts/fts_spec.cpp index ec320a562f6..20560ccdad5 100644 --- a/src/mongo/db/fts/fts_spec.cpp +++ b/src/mongo/db/fts/fts_spec.cpp @@ -38,7 +38,6 @@ #include "mongo/db/fts/fts_util.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { diff --git a/src/mongo/db/fts/fts_spec_legacy.cpp b/src/mongo/db/fts/fts_spec_legacy.cpp index b5e61b2f535..53169f5e213 100644 --- a/src/mongo/db/fts/fts_spec_legacy.cpp +++ b/src/mongo/db/fts/fts_spec_legacy.cpp @@ -31,7 +31,6 @@ #include "mongo/db/bson/dotted_path_support.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { @@ -42,9 +41,6 @@ namespace fts { // text indexes. // -using std::map; -using std::string; - namespace dps = ::mongo::dotted_path_support; namespace { @@ -81,7 +77,7 @@ void FTSSpec::_scoreStringV1(const Tools& tools, if (t.type != Token::TEXT) continue; - string term = tolowerString(t.data); + std::string term = str::toLower(t.data); if (tools.stopwords->isStopWord(term)) continue; term = tools.stemmer->stem(term).toString(); @@ -99,7 +95,7 @@ void FTSSpec::_scoreStringV1(const Tools& tools, } for (ScoreHelperMap::const_iterator i = terms.begin(); i != terms.end(); ++i) { - const string& term = i->first; + const std::string& term = i->first; const ScoreHelperStruct& data = i->second; // in order to adjust weights as a function of term count as it @@ -195,7 +191,7 @@ void FTSSpec::_scoreDocumentV1(const BSONObj& obj, TermFrequencyMap* term_freqs) } StatusWith FTSSpec::_fixSpecV1(const BSONObj& spec) { - map m; + std::map m; BSONObj keyPattern; { @@ -240,24 +236,24 @@ StatusWith FTSSpec::_fixSpecV1(const BSONObj& spec) { BSONObj weights; { BSONObjBuilder b; - for (map::iterator i = m.begin(); i != m.end(); ++i) { - if (i->second <= 0 || i->second >= MAX_WORD_WEIGHT) { + for (const auto& kv : m) { + if (kv.second <= 0 || kv.second >= MAX_WORD_WEIGHT) { return {ErrorCodes::CannotCreateIndex, str::stream() << "text index weight must be in the exclusive interval (0," << MAX_WORD_WEIGHT << ") but found: " - << i->second}; + << kv.second}; } - b.append(i->first, i->second); + b.append(kv.first, kv.second); } weights = b.obj(); } - string default_language(spec.getStringField("default_language")); + std::string default_language(spec.getStringField("default_language")); if (default_language.empty()) default_language = "english"; - string language_override(spec.getStringField("language_override")); + std::string language_override(spec.getStringField("language_override")); if (language_override.empty()) language_override = "language"; diff --git a/src/mongo/db/fts/fts_unicode_tokenizer.cpp b/src/mongo/db/fts/fts_unicode_tokenizer.cpp index f4db4881cb5..ab27d3a5c6a 100644 --- a/src/mongo/db/fts/fts_unicode_tokenizer.cpp +++ b/src/mongo/db/fts/fts_unicode_tokenizer.cpp @@ -38,7 +38,6 @@ #include "mongo/db/fts/tokenizer.h" #include "mongo/stdx/memory.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { namespace fts { diff --git a/src/mongo/db/fts/tokenizer.cpp b/src/mongo/db/fts/tokenizer.cpp index 2847f7486a8..3de9eb00689 100644 --- a/src/mongo/db/fts/tokenizer.cpp +++ b/src/mongo/db/fts/tokenizer.cpp @@ -31,7 +31,6 @@ #include "mongo/db/fts/tokenizer.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { diff --git a/src/mongo/db/kill_sessions_common.h b/src/mongo/db/kill_sessions_common.h index 95361aa5cfe..2200183fe73 100644 --- a/src/mongo/db/kill_sessions_common.h +++ b/src/mongo/db/kill_sessions_common.h @@ -38,7 +38,7 @@ #include "mongo/db/operation_context.h" #include "mongo/db/session_killer.h" #include "mongo/stdx/unordered_set.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { diff --git a/src/mongo/db/mongod_options.cpp b/src/mongo/db/mongod_options.cpp index 93debb74db2..62d28f73b50 100644 --- a/src/mongo/db/mongod_options.cpp +++ b/src/mongo/db/mongod_options.cpp @@ -55,7 +55,6 @@ #include "mongo/util/net/ssl_options.h" #include "mongo/util/options_parser/startup_options.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" #include "mongo/util/version.h" namespace mongo { @@ -451,7 +450,7 @@ Status storeMongodOptions(const moe::Environment& params) { for (const std::string& whitelistEntry : params["security.clusterIpSourceWhitelist"].as>()) { std::vector intermediates; - splitStringDelim(whitelistEntry, &intermediates, ','); + str::splitStringDelim(whitelistEntry, &intermediates, ','); std::copy(intermediates.begin(), intermediates.end(), std::back_inserter(*mongodGlobalParams.whitelistedClusterNetwork)); diff --git a/src/mongo/db/pipeline/document_path_support.cpp b/src/mongo/db/pipeline/document_path_support.cpp index cd641cdc07b..d89f122463c 100644 --- a/src/mongo/db/pipeline/document_path_support.cpp +++ b/src/mongo/db/pipeline/document_path_support.cpp @@ -38,7 +38,7 @@ #include "mongo/db/pipeline/document.h" #include "mongo/db/pipeline/field_path.h" #include "mongo/db/pipeline/value.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { namespace document_path_support { @@ -81,7 +81,7 @@ void visitAllValuesAtPathHelper(Document doc, // positional specifications, if applicable. For example, it will consume "0" and "1" from the // path "a.0.1.b" if the value at "a" is an array with arrays inside it. while (fieldPathIndex < path.getPathLength() && nextValue.isArray()) { - if (auto index = parseUnsignedBase10Integer(path.getFieldName(fieldPathIndex))) { + if (auto index = str::parseUnsignedBase10Integer(path.getFieldName(fieldPathIndex))) { nextValue = nextValue[*index]; ++fieldPathIndex; } else { diff --git a/src/mongo/db/pipeline/document_source_match.cpp b/src/mongo/db/pipeline/document_source_match.cpp index 0a269db2451..b89c04b3a87 100644 --- a/src/mongo/db/pipeline/document_source_match.cpp +++ b/src/mongo/db/pipeline/document_source_match.cpp @@ -42,7 +42,7 @@ #include "mongo/db/pipeline/expression.h" #include "mongo/db/pipeline/lite_parsed_document_source.h" #include "mongo/stdx/memory.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index 03339229f1e..727f6d52449 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -86,7 +86,7 @@ #include "mongo/scripting/engine.h" #include "mongo/stdx/memory.h" #include "mongo/util/log.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { diff --git a/src/mongo/db/query/getmore_request.cpp b/src/mongo/db/query/getmore_request.cpp index 361dcf398db..e577671f2fd 100644 --- a/src/mongo/db/query/getmore_request.cpp +++ b/src/mongo/db/query/getmore_request.cpp @@ -40,7 +40,7 @@ #include "mongo/db/namespace_string.h" #include "mongo/db/repl/bson_extract_optime.h" #include "mongo/util/assert_util.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { diff --git a/src/mongo/db/query/parsed_distinct.cpp b/src/mongo/db/query/parsed_distinct.cpp index b570b160a94..646fc2be778 100644 --- a/src/mongo/db/query/parsed_distinct.cpp +++ b/src/mongo/db/query/parsed_distinct.cpp @@ -57,7 +57,7 @@ namespace { std::string getProjectedDottedField(const std::string& field, bool* isIDOut) { // Check if field contains an array index. std::vector res; - mongo::splitStringDelim(field, &res, '.'); + str::splitStringDelim(field, &res, '.'); // Since we could exit early from the loop, // we should check _id here and set '*isIDOut' accordingly. @@ -78,7 +78,7 @@ std::string getProjectedDottedField(const std::string& field, bool* isIDOut) { // string // to the end of projectedField. std::string projectedField; - mongo::joinStringDelim(prefixStrings, &projectedField, '.'); + str::joinStringDelim(prefixStrings, &projectedField, '.'); return projectedField; } } diff --git a/src/mongo/db/repl/repl_set_config.cpp b/src/mongo/db/repl/repl_set_config.cpp index 347e15df311..6b67b047733 100644 --- a/src/mongo/db/repl/repl_set_config.cpp +++ b/src/mongo/db/repl/repl_set_config.cpp @@ -39,7 +39,7 @@ #include "mongo/db/mongod_options.h" #include "mongo/db/server_options.h" #include "mongo/stdx/functional.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { namespace repl { @@ -707,7 +707,7 @@ StatusWith ReplSetConfig::findCustomWriteMode(StringData patt if (iter == _customWriteConcernModes.end()) { return StatusWith( ErrorCodes::UnknownReplWriteConcern, - str::stream() << "No write concern mode named '" << escape(patternName.toString()) + str::stream() << "No write concern mode named '" << str::escape(patternName.toString()) << "' found in replica set configuration"); } return StatusWith(iter->second); diff --git a/src/mongo/db/s/balancer/balancer_policy.cpp b/src/mongo/db/s/balancer/balancer_policy.cpp index 32c79756d7c..a12893339d1 100644 --- a/src/mongo/db/s/balancer/balancer_policy.cpp +++ b/src/mongo/db/s/balancer/balancer_policy.cpp @@ -36,7 +36,7 @@ #include "mongo/s/catalog/type_shard.h" #include "mongo/s/catalog/type_tags.h" #include "mongo/util/log.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { diff --git a/src/mongo/db/s/get_database_version_command.cpp b/src/mongo/db/s/get_database_version_command.cpp index 16e63db0498..71fc3e4b8ad 100644 --- a/src/mongo/db/s/get_database_version_command.cpp +++ b/src/mongo/db/s/get_database_version_command.cpp @@ -39,7 +39,7 @@ #include "mongo/db/commands.h" #include "mongo/db/s/database_sharding_state.h" #include "mongo/s/request_types/get_database_version_gen.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { namespace { diff --git a/src/mongo/db/s/get_shard_version_command.cpp b/src/mongo/db/s/get_shard_version_command.cpp index bededaabe3b..87ea9653eb1 100644 --- a/src/mongo/db/s/get_shard_version_command.cpp +++ b/src/mongo/db/s/get_shard_version_command.cpp @@ -42,7 +42,7 @@ #include "mongo/db/s/sharding_state.h" #include "mongo/s/grid.h" #include "mongo/util/log.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { namespace { diff --git a/src/mongo/db/s/set_shard_version_command.cpp b/src/mongo/db/s/set_shard_version_command.cpp index 2be706a5428..d77baa5ec17 100644 --- a/src/mongo/db/s/set_shard_version_command.cpp +++ b/src/mongo/db/s/set_shard_version_command.cpp @@ -51,7 +51,7 @@ #include "mongo/s/grid.h" #include "mongo/s/request_types/set_shard_version_request.h" #include "mongo/util/log.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { namespace { diff --git a/src/mongo/db/s/unset_sharding_command.cpp b/src/mongo/db/s/unset_sharding_command.cpp index fa6f102a609..61ceb352b0a 100644 --- a/src/mongo/db/s/unset_sharding_command.cpp +++ b/src/mongo/db/s/unset_sharding_command.cpp @@ -39,7 +39,7 @@ #include "mongo/db/operation_context.h" #include "mongo/db/s/sharded_connection_info.h" #include "mongo/util/log.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { namespace { diff --git a/src/mongo/db/update/path_support.cpp b/src/mongo/db/update/path_support.cpp index 5b470c0dc94..6b9fc80a284 100644 --- a/src/mongo/db/update/path_support.cpp +++ b/src/mongo/db/update/path_support.cpp @@ -35,7 +35,6 @@ #include "mongo/bson/mutable/element.h" #include "mongo/util/assert_util.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { namespace pathsupport { @@ -99,7 +98,7 @@ Status findLongestPrefix(const FieldRef& prefix, break; case Array: - numericPart = parseUnsignedBase10Integer(prefixPart); + numericPart = str::parseUnsignedBase10Integer(prefixPart); if (!numericPart) { viable = false; } else { @@ -172,7 +171,7 @@ StatusWith createPathAt(const FieldRef& prefix, size_t i = idxFound; bool inArray = false; if (elemFound.getType() == mongo::Array) { - boost::optional newIdx = parseUnsignedBase10Integer(prefix.getPart(idxFound)); + boost::optional newIdx = str::parseUnsignedBase10Integer(prefix.getPart(idxFound)); if (!newIdx) { return Status(ErrorCodes::PathNotViable, str::stream() << "Cannot create field '" << prefix.getPart(idxFound) diff --git a/src/mongo/db/update/update_driver.cpp b/src/mongo/db/update/update_driver.cpp index d50a3c9f26f..a897f5739cd 100644 --- a/src/mongo/db/update/update_driver.cpp +++ b/src/mongo/db/update/update_driver.cpp @@ -46,7 +46,6 @@ #include "mongo/db/update/storage_validation.h" #include "mongo/util/embedded_builder.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { diff --git a/src/mongo/db/update/update_leaf_node.cpp b/src/mongo/db/update/update_leaf_node.cpp index 2739ec1efd8..5d1f8931b53 100644 --- a/src/mongo/db/update/update_leaf_node.cpp +++ b/src/mongo/db/update/update_leaf_node.cpp @@ -31,7 +31,7 @@ #include "mongo/db/update/update_leaf_node.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { @@ -44,7 +44,7 @@ void UpdateLeafNode::checkViability(mutablebson::Element element, // 'pathTaken' leads to an object, so we know it will be possible to create 'pathToCreate' // at that path. } else if (element.getType() == BSONType::Array && - parseUnsignedBase10Integer(pathToCreate.getPart(0))) { + str::parseUnsignedBase10Integer(pathToCreate.getPart(0))) { // 'pathTaken' leads to an array, so we know we can add elements at that path so long as the // next component is a valid array index. We don't check, but we expect that the index will // be out of bounds. (Otherwise it would be part of 'pathTaken' and we wouldn't need to diff --git a/src/mongo/db/update/update_object_node.cpp b/src/mongo/db/update/update_object_node.cpp index e71f273bdff..3ca3a85f797 100644 --- a/src/mongo/db/update/update_object_node.cpp +++ b/src/mongo/db/update/update_object_node.cpp @@ -37,7 +37,7 @@ #include "mongo/db/update/update_array_node.h" #include "mongo/db/update/update_leaf_node.h" #include "mongo/stdx/memory.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { @@ -89,7 +89,7 @@ mutablebson::Element getChild(mutablebson::Element element, StringData field) { if (element.getType() == BSONType::Object) { return element[field]; } else if (element.getType() == BSONType::Array) { - auto indexFromField = parseUnsignedBase10Integer(field); + auto indexFromField = str::parseUnsignedBase10Integer(field); if (indexFromField) { return element.findNthChild(*indexFromField); } diff --git a/src/mongo/dbtests/basictests.cpp b/src/mongo/dbtests/basictests.cpp index 6a07c011e69..c6a53840094 100644 --- a/src/mongo/dbtests/basictests.cpp +++ b/src/mongo/dbtests/basictests.cpp @@ -35,7 +35,7 @@ #include "mongo/dbtests/dbtests.h" #include "mongo/util/base64.h" #include "mongo/util/queue.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" #include "mongo/util/text.h" #include "mongo/util/thread_safe_string.h" #include "mongo/util/timer.h" diff --git a/src/mongo/dbtests/jsobjtests.cpp b/src/mongo/dbtests/jsobjtests.cpp index 3ef6d5c2eaf..65b4b142ac1 100644 --- a/src/mongo/dbtests/jsobjtests.cpp +++ b/src/mongo/dbtests/jsobjtests.cpp @@ -50,7 +50,7 @@ #include "mongo/util/allocator.h" #include "mongo/util/embedded_builder.h" #include "mongo/util/log.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" #include "mongo/util/timer.h" namespace mongo { @@ -126,7 +126,9 @@ BSONObj nested2dotted(const BSONObj& obj) { return b.obj(); } -FieldCompareResult compareDottedFieldNames(const string& l, const string& r, const LexNumCmp& cmp) { +FieldCompareResult compareDottedFieldNames(const string& l, + const string& r, + const str::LexNumCmp& cmp) { static int maxLoops = 1024 * 1024; size_t lstart = 0; @@ -783,7 +785,7 @@ public: BSONObj obj = BSON("str" << input); const string output = obj.firstElement().String(); - ASSERT_EQUALS(escape(output), escape(input)); // for better failure output + ASSERT_EQUALS(str::escape(output), str::escape(input)); // for better failure output ASSERT_EQUALS(output, input); } }; @@ -1550,7 +1552,7 @@ public: class CompareDottedFieldNamesTest { public: void t(FieldCompareResult res, const string& l, const string& r) { - LexNumCmp cmp(true); + str::LexNumCmp cmp(true); ASSERT_EQUALS(res, compareDottedFieldNames(l, r, cmp)); ASSERT_EQUALS(-1 * res, compareDottedFieldNames(r, l, cmp)); } @@ -1571,7 +1573,7 @@ public: class CompareDottedArrayFieldNamesTest { public: void t(FieldCompareResult res, const string& l, const string& r) { - LexNumCmp cmp(false); // Specify numeric comparison for array field names. + str::LexNumCmp cmp(false); // Specify numeric comparison for array field names. ASSERT_EQUALS(res, compareDottedFieldNames(l, r, cmp)); ASSERT_EQUALS(-1 * res, compareDottedFieldNames(r, l, cmp)); } diff --git a/src/mongo/idl/server_parameter_with_storage.h b/src/mongo/idl/server_parameter_with_storage.h index 81b1517135e..0da90e950f7 100644 --- a/src/mongo/idl/server_parameter_with_storage.h +++ b/src/mongo/idl/server_parameter_with_storage.h @@ -45,7 +45,7 @@ #include "mongo/idl/server_parameter.h" #include "mongo/platform/atomic_proxy.h" #include "mongo/platform/atomic_word.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" #include "mongo/util/synchronized_value.h" namespace mongo { @@ -81,7 +81,7 @@ template <> inline StatusWith> coerceFromString>( StringData str) { std::vector v; - splitStringDelim(str.toString(), &v, ','); + str::splitStringDelim(str.toString(), &v, ','); return v; } diff --git a/src/mongo/logger/parse_log_component_settings.cpp b/src/mongo/logger/parse_log_component_settings.cpp index 5c9f1688f32..7a8ee40f7cc 100644 --- a/src/mongo/logger/parse_log_component_settings.cpp +++ b/src/mongo/logger/parse_log_component_settings.cpp @@ -42,7 +42,6 @@ #include "mongo/util/assert_util.h" #include "mongo/util/log.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { namespace logger { diff --git a/src/mongo/platform/decimal128.cpp b/src/mongo/platform/decimal128.cpp index 69ef39d593d..94581933375 100644 --- a/src/mongo/platform/decimal128.cpp +++ b/src/mongo/platform/decimal128.cpp @@ -47,11 +47,21 @@ #undef _WCHAR_T #include "mongo/base/static_assert.h" +#include "mongo/base/string_data.h" #include "mongo/config.h" #include "mongo/util/assert_util.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace { + +std::string toAsciiLowerCase(mongo::StringData input) { + std::string res = input.toString(); + for (char& c : res) { + c = tolower(c); + } + return res; +} + void validateInputString(mongo::StringData input, std::uint32_t* signalingFlags) { // Input must be of these forms: // * Valid decimal (standard or scientific notation): diff --git a/src/mongo/s/catalog/mongo_version_range.cpp b/src/mongo/s/catalog/mongo_version_range.cpp index f1aa116ddeb..c92fcb0b749 100644 --- a/src/mongo/s/catalog/mongo_version_range.cpp +++ b/src/mongo/s/catalog/mongo_version_range.cpp @@ -31,7 +31,7 @@ #include "mongo/s/catalog/mongo_version_range.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { @@ -92,7 +92,7 @@ bool MongoVersionRange::parseBSONElement(const BSONElement& el, string* errMsg) return false; } - if (versionCmp(minVersion, maxVersion) > 0) { + if (str::versionCmp(minVersion, maxVersion) > 0) { string swap = minVersion; minVersion = maxVersion; maxVersion = swap; @@ -131,7 +131,8 @@ bool MongoVersionRange::isInRange(StringData version) const { return true; if (version.find(maxVersion) == 0) return true; - if (versionCmp(minVersion, version) <= 0 && versionCmp(maxVersion, version) >= 0) { + if (str::versionCmp(minVersion, version) <= 0 && + str::versionCmp(maxVersion, version) >= 0) { return true; } } @@ -140,8 +141,8 @@ bool MongoVersionRange::isInRange(StringData version) const { } bool isInMongoVersionRanges(StringData version, const vector& ranges) { - for (vector::const_iterator it = ranges.begin(); it != ranges.end(); ++it) { - if (it->isInRange(version)) + for (const auto& r : ranges) { + if (r.isInRange(version)) return true; } diff --git a/src/mongo/s/mongos_options.cpp b/src/mongo/s/mongos_options.cpp index 0cfa74fb7d0..f00243433e8 100644 --- a/src/mongo/s/mongos_options.cpp +++ b/src/mongo/s/mongos_options.cpp @@ -49,7 +49,6 @@ #include "mongo/util/options_parser/startup_options.h" #include "mongo/util/startup_test.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { @@ -145,10 +144,10 @@ Status storeMongosOptions(const moe::Environment& params) { if (!resolvedSomeSeedSever) { if (!hostbyname(configdbConnectionString.getValue().getSetName().c_str()).empty()) { warning() << "The replica set name \"" - << escape(configdbConnectionString.getValue().getSetName()) + << str::escape(configdbConnectionString.getValue().getSetName()) << "\" resolves as a host name, but none of the servers in the seed list do. " "Did you reverse the replica set name and the seed list in " - << escape(configdbConnectionString.getValue().toString()) << "?"; + << str::escape(configdbConnectionString.getValue().toString()) << "?"; } } diff --git a/src/mongo/s/server.cpp b/src/mongo/s/server.cpp index c75e286f3ea..9a8e6ebe71a 100644 --- a/src/mongo/s/server.cpp +++ b/src/mongo/s/server.cpp @@ -110,7 +110,7 @@ #include "mongo/util/quick_exit.h" #include "mongo/util/signal_handlers.h" #include "mongo/util/stacktrace.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" #include "mongo/util/text.h" #include "mongo/util/version.h" diff --git a/src/mongo/scripting/mozjs/wrapconstrainedmethod.h b/src/mongo/scripting/mozjs/wrapconstrainedmethod.h index e95f41dda7c..12a94458896 100644 --- a/src/mongo/scripting/mozjs/wrapconstrainedmethod.h +++ b/src/mongo/scripting/mozjs/wrapconstrainedmethod.h @@ -35,7 +35,7 @@ #include "mongo/scripting/mozjs/objectwrapper.h" #include "mongo/scripting/mozjs/valuewriter.h" #include "mongo/util/assert_util.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" namespace mongo { namespace mozjs { diff --git a/src/mongo/shell/dbshell.cpp b/src/mongo/shell/dbshell.cpp index 46cf674fea5..f80ac260ec6 100644 --- a/src/mongo/shell/dbshell.cpp +++ b/src/mongo/shell/dbshell.cpp @@ -68,7 +68,7 @@ #include "mongo/util/signal_handlers.h" #include "mongo/util/stacktrace.h" #include "mongo/util/startup_test.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" #include "mongo/util/text.h" #include "mongo/util/version.h" @@ -844,7 +844,7 @@ int _main(int argc, char* argv[], char** envp) { // Parse the output of getURIFromArgs which will determine if --host passed in a URI MongoURI parsedURI; parsedURI = uassertStatusOK(MongoURI::parse(getURIFromArgs( - cmdlineURI, escape(shellGlobalParams.dbhost), escape(shellGlobalParams.port)))); + cmdlineURI, str::escape(shellGlobalParams.dbhost), str::escape(shellGlobalParams.port)))); // TODO: add in all of the relevant shellGlobalParams to parsedURI parsedURI.setOptionIfNecessary("compressors"s, shellGlobalParams.networkMessageCompressors); @@ -855,14 +855,14 @@ int _main(int argc, char* argv[], char** envp) { if (const auto authMechanisms = parsedURI.getOption("authMechanism")) { std::stringstream ss; - ss << "DB.prototype._defaultAuthenticationMechanism = \"" << escape(authMechanisms.get()) - << "\";" << std::endl; + ss << "DB.prototype._defaultAuthenticationMechanism = \"" + << str::escape(authMechanisms.get()) << "\";" << std::endl; mongo::shell_utils::dbConnect += ss.str(); } if (const auto gssapiServiveName = parsedURI.getOption("gssapiServiceName")) { std::stringstream ss; - ss << "DB.prototype._defaultGssapiServiceName = \"" << escape(gssapiServiveName.get()) + ss << "DB.prototype._defaultGssapiServiceName = \"" << str::escape(gssapiServiveName.get()) << "\";" << std::endl; mongo::shell_utils::dbConnect += ss.str(); } diff --git a/src/mongo/shell/shell_utils_launcher.cpp b/src/mongo/shell/shell_utils_launcher.cpp index 3b3d128335e..34aa7c61d7e 100644 --- a/src/mongo/shell/shell_utils_launcher.cpp +++ b/src/mongo/shell/shell_utils_launcher.cpp @@ -71,7 +71,7 @@ #include "mongo/util/quick_exit.h" #include "mongo/util/scopeguard.h" #include "mongo/util/signal_win32.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" #include "mongo/util/text.h" #ifndef _WIN32 @@ -525,7 +525,7 @@ boost::filesystem::path ProgramRunner::findProgram(const string& prog) { // PATH entries are separated by colons. Per POSIX 2013, there is no way to escape a colon in // an entry. - splitStringDelim(path, &pathEntries, ':'); + str::splitStringDelim(path, &pathEntries, ':'); for (const std::string& pathEntry : pathEntries) { boost::filesystem::path potentialBinary = boost::filesystem::path(pathEntry) / p; diff --git a/src/mongo/transport/service_executor_adaptive.cpp b/src/mongo/transport/service_executor_adaptive.cpp index edc0cdb0c75..9b9d3e9c734 100644 --- a/src/mongo/transport/service_executor_adaptive.cpp +++ b/src/mongo/transport/service_executor_adaptive.cpp @@ -44,7 +44,7 @@ #include "mongo/util/log.h" #include "mongo/util/processinfo.h" #include "mongo/util/scopeguard.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" #include diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript index 626a6116c32..18f096b148b 100644 --- a/src/mongo/util/SConscript +++ b/src/mongo/util/SConscript @@ -263,9 +263,9 @@ env.CppUnitTest( ) env.CppUnitTest( - target="stringutils_test", + target="str_test", source=[ - "stringutils_test.cpp", + "str_test.cpp", ], LIBDEPS=[ "$BUILD_DIR/mongo/base", diff --git a/src/mongo/util/net/hostandport.cpp b/src/mongo/util/net/hostandport.cpp index 19786d0f375..5c30ef22aa8 100644 --- a/src/mongo/util/net/hostandport.cpp +++ b/src/mongo/util/net/hostandport.cpp @@ -40,7 +40,6 @@ #include "mongo/db/server_options.h" #include "mongo/util/assert_util.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { @@ -175,7 +174,7 @@ Status HostAndPort::initialize(StringData s) { if (hostPart.empty()) { return Status(ErrorCodes::FailedToParse, str::stream() << "Empty host component parsing HostAndPort from \"" - << escape(s.toString()) + << str::escape(s.toString()) << "\""); } @@ -190,7 +189,7 @@ Status HostAndPort::initialize(StringData s) { return Status(ErrorCodes::FailedToParse, str::stream() << "Port number " << port << " out of range parsing HostAndPort from \"" - << escape(s.toString()) + << str::escape(s.toString()) << "\""); } } else { diff --git a/src/mongo/util/processinfo_solaris.cpp b/src/mongo/util/processinfo_solaris.cpp index e65357b9ae4..91f73e41dd9 100644 --- a/src/mongo/util/processinfo_solaris.cpp +++ b/src/mongo/util/processinfo_solaris.cpp @@ -50,7 +50,6 @@ #include "mongo/util/processinfo.h" #include "mongo/util/scopeguard.h" #include "mongo/util/str.h" -#include "mongo/util/stringutils.h" namespace mongo { @@ -169,7 +168,7 @@ void ProcessInfo::SystemInfo::collectSystemInfo() { if (str::startsWith(osName, "Oracle Solaris")) { std::vector versionComponents; - splitStringDelim(osVersion, &versionComponents, '.'); + str::splitStringDelim(osVersion, &versionComponents, '.'); if (versionComponents.size() > 1) { unsigned majorInt, minorInt; diff --git a/src/mongo/util/stacktrace_posix.cpp b/src/mongo/util/stacktrace_posix.cpp index ac3fadeb549..9eaed27e06c 100644 --- a/src/mongo/util/stacktrace_posix.cpp +++ b/src/mongo/util/stacktrace_posix.cpp @@ -44,7 +44,7 @@ #include "mongo/db/jsobj.h" #include "mongo/util/hex.h" #include "mongo/util/log.h" -#include "mongo/util/stringutils.h" +#include "mongo/util/str.h" #include "mongo/util/version.h" #if defined(MONGO_CONFIG_HAVE_EXECINFO_BACKTRACE) @@ -353,7 +353,7 @@ void processLoadSegment(const dl_phdr_info& info, const ElfW(Phdr) & phdr, BSONO ElfW(Ehdr) eHeader; memcpy(&eHeader, reinterpret_cast(info.dlpi_addr) + phdr.p_vaddr, sizeof(eHeader)); - std::string quotedFileName = "\"" + escape(info.dlpi_name) + "\""; + std::string quotedFileName = "\"" + str::escape(info.dlpi_name) + "\""; if (memcmp(&eHeader.e_ident[0], ELFMAG, SELFMAG)) { warning() << "Bad ELF magic number in image of " << quotedFileName; diff --git a/src/mongo/util/str.cpp b/src/mongo/util/str.cpp new file mode 100644 index 00000000000..7209fd90e2e --- /dev/null +++ b/src/mongo/util/str.cpp @@ -0,0 +1,239 @@ +/** + * Copyright (C) 2018-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * 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 Server Side 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. + */ + +#include "mongo/platform/basic.h" + +#include + +#include "mongo/base/parse_number.h" +#include "mongo/util/hex.h" +#include "mongo/util/str.h" + +namespace mongo::str { + +void splitStringDelim(const std::string& str, std::vector* res, char delim) { + if (str.empty()) + return; + + size_t beg = 0; + size_t pos = str.find(delim); + while (pos != str.npos) { + res->push_back(str.substr(beg, pos - beg)); + beg = ++pos; + pos = str.find(delim, beg); + } + res->push_back(str.substr(beg)); +} + +void joinStringDelim(const std::vector& strs, std::string* res, char delim) { + for (auto it = strs.begin(); it != strs.end(); ++it) { + if (it != strs.begin()) + res->push_back(delim); + res->append(*it); + } +} + +LexNumCmp::LexNumCmp(bool lexOnly) : _lexOnly(lexOnly) {} + +int LexNumCmp::cmp(StringData sd1, StringData sd2, bool lexOnly) { + bool startWord = true; + + size_t s1 = 0; + size_t s2 = 0; + + while (s1 < sd1.size() && s2 < sd2.size()) { + bool d1 = (sd1[s1] == '.'); + bool d2 = (sd2[s2] == '.'); + if (d1 && !d2) + return -1; + if (d2 && !d1) + return 1; + if (d1 && d2) { + ++s1; + ++s2; + startWord = true; + continue; + } + + bool p1 = (sd1[s1] == (char)255); + bool p2 = (sd2[s2] == (char)255); + + if (p1 && !p2) + return 1; + if (p2 && !p1) + return -1; + + if (!lexOnly) { + bool n1 = isdigit(sd1[s1]); + bool n2 = isdigit(sd2[s2]); + + if (n1 && n2) { + // get rid of leading 0s + if (startWord) { + while (s1 < sd1.size() && sd1[s1] == '0') + s1++; + while (s2 < sd2.size() && sd2[s2] == '0') + s2++; + } + + size_t e1 = s1; + size_t e2 = s2; + + while (e1 < sd1.size() && isdigit(sd1[e1])) + e1++; + while (e2 < sd2.size() && isdigit(sd2[e2])) + e2++; + + size_t len1 = e1 - s1; + size_t len2 = e2 - s2; + + int result; + // if one is longer than the other, return + if (len1 > len2) { + return 1; + } else if (len2 > len1) { + return -1; + } + // if the lengths are equal, just strcmp + else { + result = strncmp(sd1.rawData() + s1, sd2.rawData() + s2, len1); + if (result) + return (result > 0) ? 1 : -1; + } + + // otherwise, the numbers are equal + s1 = e1; + s2 = e2; + startWord = false; + continue; + } + + if (n1) + return 1; + + if (n2) + return -1; + } + + if (sd1[s1] > sd2[s2]) + return 1; + + if (sd2[s2] > sd1[s1]) + return -1; + + s1++; + s2++; + startWord = false; + } + + if (s1 < sd1.size() && sd1[s1]) + return 1; + if (s2 < sd2.size() && sd2[s2]) + return -1; + return 0; +} + +int LexNumCmp::cmp(StringData s1, StringData s2) const { + return cmp(s1, s2, _lexOnly); +} +bool LexNumCmp::operator()(StringData s1, StringData s2) const { + return cmp(s1, s2) < 0; +} + +int versionCmp(const StringData rhs, const StringData lhs) { + if (rhs == lhs) + return 0; + + // handle "1.2.3-" and "1.2.3-pre" + if (rhs.size() < lhs.size()) { + if (strncmp(rhs.rawData(), lhs.rawData(), rhs.size()) == 0 && lhs[rhs.size()] == '-') + return +1; + } else if (rhs.size() > lhs.size()) { + if (strncmp(rhs.rawData(), lhs.rawData(), lhs.size()) == 0 && rhs[lhs.size()] == '-') + return -1; + } + + return LexNumCmp::cmp(rhs, lhs, false); +} + +std::string escape(StringData sd, bool escape_slash) { + StringBuilder ret; + ret.reset(sd.size()); + for (const auto& c : sd) { + switch (c) { + case '"': + ret << "\\\""; + break; + case '\\': + ret << "\\\\"; + break; + case '/': + ret << (escape_slash ? "\\/" : "/"); + break; + case '\b': + ret << "\\b"; + break; + case '\f': + ret << "\\f"; + break; + case '\n': + ret << "\\n"; + break; + case '\r': + ret << "\\r"; + break; + case '\t': + ret << "\\t"; + break; + default: + if (c >= 0 && c <= 0x1f) { + // For c < 0x7f, ASCII value == Unicode code point. + ret << "\\u00" << toHexLower(&c, 1); + } else { + ret << c; + } + } + } + return ret.str(); +} + +boost::optional parseUnsignedBase10Integer(StringData fieldName) { + // Do not accept positions like '-4' or '+4' + if (!std::isdigit(fieldName[0])) { + return boost::none; + } + unsigned int index; + auto status = parseNumberFromStringWithBase(fieldName, 10, &index); + if (status.isOK()) { + return static_cast(index); + } + return boost::none; +} + +} // namespace mongo::str diff --git a/src/mongo/util/str.h b/src/mongo/util/str.h index f3950adc244..bddfff282b2 100644 --- a/src/mongo/util/str.h +++ b/src/mongo/util/str.h @@ -35,8 +35,12 @@ * TODO: De-inline. */ +#include +#include +#include #include #include +#include #include "mongo/base/string_data.h" #include "mongo/bson/util/builder.h" @@ -286,4 +290,58 @@ inline int caseInsensitiveCompare(const char* s1, const char* s2) { #endif } +void splitStringDelim(const std::string& str, std::vector* res, char delim); + +void joinStringDelim(const std::vector& strs, std::string* res, char delim); + +inline std::string toLower(StringData input) { + std::string::size_type sz = input.size(); + + std::unique_ptr line(new char[sz + 1]); + char* copy = line.get(); + + for (std::string::size_type i = 0; i < sz; i++) { + char c = input[i]; + copy[i] = (char)tolower((int)c); + } + copy[sz] = 0; + return copy; +} + +/** Functor for combining lexical and numeric comparisons. */ +class LexNumCmp { +public: + /** @param lexOnly - compare all characters lexically, including digits. */ + LexNumCmp(bool lexOnly); + /** + * Non numeric characters are compared lexicographically; numeric substrings + * are compared numerically; dots separate ordered comparable subunits. + * For convenience, character 255 is greater than anything else. + * @param lexOnly - compare all characters lexically, including digits. + */ + static int cmp(StringData s1, StringData s2, bool lexOnly); + int cmp(StringData s1, StringData s2) const; + bool operator()(StringData s1, StringData s2) const; + +private: + bool _lexOnly; +}; + +// TODO: Sane-ify core std::string functionality +// For now, this needs to be near the LexNumCmp or else +int versionCmp(StringData rhs, StringData lhs); + +/** + * A method to escape whitespace and control characters in strings. For example, the string "\t" + * goes to "\\t". If `escape_slash` is true, then "/" goes to "\\/". + */ +std::string escape(StringData s, bool escape_slash = false); + +/** + * Converts 'integer' from a base-10 string to a size_t value or returns boost::none if 'integer' + * is not a valid base-10 string. A valid string is not allowed to have anything but decimal + * numerals, not even a +/- prefix or leading/trailing whitespace. + */ +boost::optional parseUnsignedBase10Integer(StringData integer); + } // namespace mongo::str diff --git a/src/mongo/util/str_test.cpp b/src/mongo/util/str_test.cpp new file mode 100644 index 00000000000..68d06b7535c --- /dev/null +++ b/src/mongo/util/str_test.cpp @@ -0,0 +1,273 @@ +/** + * Copyright (C) 2018-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * 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 Server Side 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. + */ + +#include "mongo/unittest/unittest.h" + +#include "mongo/util/hex.h" +#include "mongo/util/str.h" + +namespace mongo::str { + +using std::string; + +TEST(StringUtilsTest, Basic) { + // + // Basic version comparison tests with different version string types + // + + // Equal + ASSERT(versionCmp("1.2.3", "1.2.3") == 0); + + // Basic + ASSERT(versionCmp("1.2.3", "1.2.4") < 0); + ASSERT(versionCmp("1.2.3", "1.2.20") < 0); + ASSERT(versionCmp("1.2.3", "1.20.3") < 0); + ASSERT(versionCmp("2.2.3", "10.2.3") < 0); + + // Post-fixed + ASSERT(versionCmp("1.2.3", "1.2.3-") > 0); + ASSERT(versionCmp("1.2.3", "1.2.3-pre") > 0); + ASSERT(versionCmp("1.2.3", "1.2.4-") < 0); + ASSERT(versionCmp("1.2.3-", "1.2.3") < 0); + ASSERT(versionCmp("1.2.3-pre", "1.2.3") < 0); +} + +TEST(StringUtilsTest, Simple1) { + ASSERT_EQUALS(0, LexNumCmp::cmp("a.b.c", "a.b.c", false)); +} + +void assertCmp(int expected, StringData s1, StringData s2, bool lexOnly = false) { + LexNumCmp cmp(lexOnly); + ASSERT_EQUALS(expected, cmp.cmp(s1, s2, lexOnly)); + ASSERT_EQUALS(expected, cmp.cmp(s1, s2)); + ASSERT_EQUALS(expected < 0, cmp(s1, s2)); +} + +TEST(StringUtilsTest, Simple2) { + ASSERT(!isdigit((char)255)); + + assertCmp(0, "a", "a"); + assertCmp(-1, "a", "aa"); + assertCmp(1, "aa", "a"); + assertCmp(-1, "a", "b"); + assertCmp(1, "100", "50"); + assertCmp(-1, "50", "100"); + assertCmp(1, "b", "a"); + assertCmp(0, "aa", "aa"); + assertCmp(-1, "aa", "ab"); + assertCmp(1, "ab", "aa"); + assertCmp(1, "0", "a"); + assertCmp(1, "a0", "aa"); + assertCmp(-1, "a", "0"); + assertCmp(-1, "aa", "a0"); + assertCmp(0, "0", "0"); + assertCmp(0, "10", "10"); + assertCmp(-1, "1", "10"); + assertCmp(1, "10", "1"); + assertCmp(1, "11", "10"); + assertCmp(-1, "10", "11"); + assertCmp(1, "f11f", "f10f"); + assertCmp(-1, "f10f", "f11f"); + assertCmp(-1, "f11f", "f111"); + assertCmp(1, "f111", "f11f"); + assertCmp(-1, "f12f", "f12g"); + assertCmp(1, "f12g", "f12f"); + assertCmp(1, "aa{", "aab"); + assertCmp(-1, "aa{", "aa1"); + assertCmp(-1, "a1{", "a11"); + assertCmp(1, "a1{a", "a1{"); + assertCmp(-1, "a1{", "a1{a"); + assertCmp(1, "21", "11"); + assertCmp(-1, "11", "21"); + + assertCmp(-1, "a.0", "a.1"); + assertCmp(-1, "a.0.b", "a.1"); + + assertCmp(-1, "b.", "b.|"); + assertCmp(-1, "b.0e", (string("b.") + (char)255).c_str()); + assertCmp(-1, "b.", "b.0e"); + + assertCmp(0, "238947219478347782934718234", "238947219478347782934718234"); + assertCmp(0, "000238947219478347782934718234", "238947219478347782934718234"); + assertCmp(1, "000238947219478347782934718235", "238947219478347782934718234"); + assertCmp(-1, "238947219478347782934718234", "238947219478347782934718234.1"); + assertCmp(0, "238", "000238"); + assertCmp(0, "002384", "0002384"); + assertCmp(0, "00002384", "0002384"); + assertCmp(0, "0", "0"); + assertCmp(0, "0000", "0"); + assertCmp(0, "0", "000"); + assertCmp(-1, "0000", "0.0"); + assertCmp(1, "2380", "238"); + assertCmp(1, "2385", "2384"); + assertCmp(1, "2385", "02384"); + assertCmp(1, "2385", "002384"); + assertCmp(-1, "123.234.4567", "00238"); + assertCmp(0, "123.234", "00123.234"); + assertCmp(0, "a.123.b", "a.00123.b"); + assertCmp(1, "a.123.b", "a.b.00123.b"); + assertCmp(-1, "a.00.0", "a.0.1"); + assertCmp(0, "01.003.02", "1.3.2"); + assertCmp(-1, "1.3.2", "10.300.20"); + assertCmp(0, "10.300.20", "000000000000010.0000300.000000020"); + assertCmp(0, "0000a", "0a"); + assertCmp(-1, "a", "0a"); + assertCmp(-1, "000a", "001a"); + assertCmp(0, "010a", "0010a"); + + assertCmp(-1, "a0", "a00"); + assertCmp(0, "a.0", "a.00"); + assertCmp(-1, "a.b.c.d0", "a.b.c.d00"); + assertCmp(1, "a.b.c.0.y", "a.b.c.00.x"); + + assertCmp(-1, "a", "a-"); + assertCmp(1, "a-", "a"); + assertCmp(0, "a-", "a-"); + + assertCmp(-1, "a", "a-c"); + assertCmp(1, "a-c", "a"); + assertCmp(0, "a-c", "a-c"); + + assertCmp(1, "a-c.t", "a.t"); + assertCmp(-1, "a.t", "a-c.t"); + assertCmp(0, "a-c.t", "a-c.t"); + + assertCmp(1, "ac.t", "a.t"); + assertCmp(-1, "a.t", "ac.t"); + assertCmp(0, "ac.t", "ac.t"); +} + +TEST(StringUtilsTest, LexOnly) { + assertCmp(-1, "0", "00", true); + assertCmp(1, "1", "01", true); + assertCmp(-1, "1", "11", true); + assertCmp(1, "2", "11", true); +} + +TEST(StringUtilsTest, Substring1) { + assertCmp(0, "1234", "1234", false); + assertCmp(0, StringData("1234"), StringData("1234"), false); + assertCmp(0, StringData("1234", 4), StringData("1234", 4), false); + assertCmp(-1, StringData("123", 3), StringData("1234", 4), false); + + + assertCmp(0, StringData("0001", 3), StringData("0000", 3), false); +} + +TEST(StringUtilsTest, VariousConversions) { + ASSERT_EQUALS(std::string("0"), integerToHex(0)); + ASSERT_EQUALS(std::string("1"), integerToHex(1)); + ASSERT_EQUALS(std::string("1337"), integerToHex(0x1337)); + ASSERT_EQUALS(std::string("FFFFD499"), integerToHex(-11111)); + ASSERT_EQUALS(std::string("F1FE60C4"), integerToHex(-234987324)); + ASSERT_EQUALS(std::string("80000000"), integerToHex(std::numeric_limits::min())); + ASSERT_EQUALS(std::string("7FFFFFFF"), integerToHex(std::numeric_limits::max())); + ASSERT_EQUALS(std::string("7FFFFFFFFFFFFFFF"), + integerToHex(std::numeric_limits::max())); + ASSERT_EQUALS(std::string("8000000000000000"), + integerToHex(std::numeric_limits::min())); +} + +TEST(StringUtilsTest, unsignedFixedLengthHex) { + ASSERT_EQUALS(unsignedIntToFixedLengthHex(std::numeric_limits::max()), + std::string("FFFFFFFF")); + ASSERT_EQUALS(unsignedIntToFixedLengthHex(0), std::string("00000000")); + ASSERT_EQUALS(unsignedIntToFixedLengthHex(123), std::string("0000007B")); +} + +TEST(StringUtilsTest, CanParseZero) { + boost::optional result = parseUnsignedBase10Integer("0"); + ASSERT(result && *result == 0); +} + +TEST(StringUtilsTest, CanParseDoubleZero) { + boost::optional result = parseUnsignedBase10Integer("00"); + ASSERT(result && *result == 0); +} + +TEST(StringUtilsTest, PositivePrefixFailsToParse) { + boost::optional result = parseUnsignedBase10Integer("+0"); + ASSERT(!result); +} + +TEST(StringUtilsTest, NegativePrefixFailsToParse) { + boost::optional result = parseUnsignedBase10Integer("-0"); + ASSERT(!result); +} + +TEST(StringUtilsTest, CanParseIntValue) { + boost::optional result = parseUnsignedBase10Integer("10"); + ASSERT(result && *result == 10); +} + +TEST(StringUtilsTest, CanParseIntValueWithLeadingZeros) { + boost::optional result = parseUnsignedBase10Integer("0010"); + ASSERT(result && *result == 10); +} + +TEST(StringUtilsTest, TrailingLetterFailsToParse) { + boost::optional result = parseUnsignedBase10Integer("5a"); + ASSERT(!result); +} + +TEST(StringUtilsTest, LeadingLetterFailsToParse) { + boost::optional result = parseUnsignedBase10Integer("a5"); + ASSERT(!result); +} + +TEST(StringUtilsTest, LetterWithinNumberFailsToParse) { + boost::optional result = parseUnsignedBase10Integer("5a5"); + ASSERT(!result); +} + +TEST(StringUtilsTest, HexStringFailsToParse) { + boost::optional result = parseUnsignedBase10Integer("0xfeed"); + ASSERT(!result); +} + +TEST(StringUtilsTest, BinaryStringFailsToParse) { + boost::optional result = parseUnsignedBase10Integer("0b11010010"); + ASSERT(!result); +} + +TEST(StringUtilsTest, LeadingWhitespaceFailsToParse) { + boost::optional result = parseUnsignedBase10Integer(" 10"); + ASSERT(!result); +} + +TEST(StringUtilsTest, TrailingWhitespaceFailsToParse) { + boost::optional result = parseUnsignedBase10Integer("10 "); + ASSERT(!result); +} + +TEST(StringUtilsTest, WhitespaceWithinNumberFailsToParse) { + boost::optional result = parseUnsignedBase10Integer(" 10"); + ASSERT(!result); +} +} // namespace mongo::str diff --git a/src/mongo/util/stringutils.cpp b/src/mongo/util/stringutils.cpp deleted file mode 100644 index 8cffc75d0e0..00000000000 --- a/src/mongo/util/stringutils.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * 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 - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * 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 Server Side 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. - */ - -#include "mongo/platform/basic.h" - -#include - -#include "mongo/util/stringutils.h" - -#include "mongo/base/parse_number.h" -#include "mongo/util/hex.h" - -namespace mongo { - -using std::string; -using std::vector; - -void splitStringDelim(const string& str, vector* res, char delim) { - if (str.empty()) - return; - - size_t beg = 0; - size_t pos = str.find(delim); - while (pos != string::npos) { - res->push_back(str.substr(beg, pos - beg)); - beg = ++pos; - pos = str.find(delim, beg); - } - res->push_back(str.substr(beg)); -} - -void joinStringDelim(const vector& strs, string* res, char delim) { - for (vector::const_iterator it = strs.begin(); it != strs.end(); ++it) { - if (it != strs.begin()) - res->push_back(delim); - res->append(*it); - } -} - -LexNumCmp::LexNumCmp(bool lexOnly) : _lexOnly(lexOnly) {} - -int LexNumCmp::cmp(StringData sd1, StringData sd2, bool lexOnly) { - bool startWord = true; - - size_t s1 = 0; - size_t s2 = 0; - - while (s1 < sd1.size() && s2 < sd2.size()) { - bool d1 = (sd1[s1] == '.'); - bool d2 = (sd2[s2] == '.'); - if (d1 && !d2) - return -1; - if (d2 && !d1) - return 1; - if (d1 && d2) { - ++s1; - ++s2; - startWord = true; - continue; - } - - bool p1 = (sd1[s1] == (char)255); - bool p2 = (sd2[s2] == (char)255); - - if (p1 && !p2) - return 1; - if (p2 && !p1) - return -1; - - if (!lexOnly) { - bool n1 = isdigit(sd1[s1]); - bool n2 = isdigit(sd2[s2]); - - if (n1 && n2) { - // get rid of leading 0s - if (startWord) { - while (s1 < sd1.size() && sd1[s1] == '0') - s1++; - while (s2 < sd2.size() && sd2[s2] == '0') - s2++; - } - - size_t e1 = s1; - size_t e2 = s2; - - while (e1 < sd1.size() && isdigit(sd1[e1])) - e1++; - while (e2 < sd2.size() && isdigit(sd2[e2])) - e2++; - - size_t len1 = e1 - s1; - size_t len2 = e2 - s2; - - int result; - // if one is longer than the other, return - if (len1 > len2) { - return 1; - } else if (len2 > len1) { - return -1; - } - // if the lengths are equal, just strcmp - else { - result = strncmp(sd1.rawData() + s1, sd2.rawData() + s2, len1); - if (result) - return (result > 0) ? 1 : -1; - } - - // otherwise, the numbers are equal - s1 = e1; - s2 = e2; - startWord = false; - continue; - } - - if (n1) - return 1; - - if (n2) - return -1; - } - - if (sd1[s1] > sd2[s2]) - return 1; - - if (sd2[s2] > sd1[s1]) - return -1; - - s1++; - s2++; - startWord = false; - } - - if (s1 < sd1.size() && sd1[s1]) - return 1; - if (s2 < sd2.size() && sd2[s2]) - return -1; - return 0; -} - -int LexNumCmp::cmp(StringData s1, StringData s2) const { - return cmp(s1, s2, _lexOnly); -} -bool LexNumCmp::operator()(StringData s1, StringData s2) const { - return cmp(s1, s2) < 0; -} - -int versionCmp(const StringData rhs, const StringData lhs) { - if (rhs == lhs) - return 0; - - // handle "1.2.3-" and "1.2.3-pre" - if (rhs.size() < lhs.size()) { - if (strncmp(rhs.rawData(), lhs.rawData(), rhs.size()) == 0 && lhs[rhs.size()] == '-') - return +1; - } else if (rhs.size() > lhs.size()) { - if (strncmp(rhs.rawData(), lhs.rawData(), lhs.size()) == 0 && rhs[lhs.size()] == '-') - return -1; - } - - return LexNumCmp::cmp(rhs, lhs, false); -} - -std::string escape(StringData sd, bool escape_slash) { - StringBuilder ret; - ret.reset(sd.size()); - for (const auto& c : sd) { - switch (c) { - case '"': - ret << "\\\""; - break; - case '\\': - ret << "\\\\"; - break; - case '/': - ret << (escape_slash ? "\\/" : "/"); - break; - case '\b': - ret << "\\b"; - break; - case '\f': - ret << "\\f"; - break; - case '\n': - ret << "\\n"; - break; - case '\r': - ret << "\\r"; - break; - case '\t': - ret << "\\t"; - break; - default: - if (c >= 0 && c <= 0x1f) { - // For c < 0x7f, ASCII value == Unicode code point. - ret << "\\u00" << toHexLower(&c, 1); - } else { - ret << c; - } - } - } - return ret.str(); -} - -boost::optional parseUnsignedBase10Integer(StringData fieldName) { - // Do not accept positions like '-4' or '+4' - if (!std::isdigit(fieldName[0])) { - return boost::none; - } - unsigned int index; - auto status = parseNumberFromStringWithBase(fieldName, 10, &index); - if (status.isOK()) { - return static_cast(index); - } - return boost::none; -} - -} // namespace mongo diff --git a/src/mongo/util/stringutils.h b/src/mongo/util/stringutils.h deleted file mode 100644 index dc9110fc112..00000000000 --- a/src/mongo/util/stringutils.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * 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 - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * 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 Server Side 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. - */ - -#pragma once - -#include - -#include -#include -#include -#include - -#include "mongo/base/string_data.h" - -namespace mongo { - -// see also mongo/util/str.h - perhaps move these there? -// see also text.h - -void splitStringDelim(const std::string& str, std::vector* res, char delim); - -void joinStringDelim(const std::vector& strs, std::string* res, char delim); - -inline std::string tolowerString(StringData input) { - std::string::size_type sz = input.size(); - - std::unique_ptr line(new char[sz + 1]); - char* copy = line.get(); - - for (std::string::size_type i = 0; i < sz; i++) { - char c = input[i]; - copy[i] = (char)tolower((int)c); - } - copy[sz] = 0; - return copy; -} - -inline std::string toAsciiLowerCase(StringData input) { - size_t sz = input.size(); - std::unique_ptr line(new char[sz + 1]); - char* res = line.get(); - for (size_t i = 0; i < sz; i++) { - char c = input[i]; - if (c >= 'A' && c <= 'Z') { - res[i] = c + 32; - } else { - res[i] = c; - } - } - res[sz] = 0; - return res; -} - -/** Functor for combining lexical and numeric comparisons. */ -class LexNumCmp { -public: - /** @param lexOnly - compare all characters lexically, including digits. */ - LexNumCmp(bool lexOnly); - /** - * Non numeric characters are compared lexicographically; numeric substrings - * are compared numerically; dots separate ordered comparable subunits. - * For convenience, character 255 is greater than anything else. - * @param lexOnly - compare all characters lexically, including digits. - */ - static int cmp(StringData s1, StringData s2, bool lexOnly); - int cmp(StringData s1, StringData s2) const; - bool operator()(StringData s1, StringData s2) const; - -private: - bool _lexOnly; -}; - -// TODO: Sane-ify core std::string functionality -// For now, this needs to be near the LexNumCmp or else -int versionCmp(const StringData rhs, const StringData lhs); - -/** - * A method to escape whitespace and control characters in strings. For example, the string "\t" - * goes to "\\t". If `escape_slash` is true, then "/" goes to "\\/". - */ -std::string escape(StringData s, bool escape_slash = false); - -/** - * Converts 'integer' from a base-10 string to a size_t value or returns boost::none if 'integer' - * is not a valid base-10 string. A valid string is not allowed to have anything but decimal - * numerals, not even a +/- prefix or leading/trailing whitespace. - */ -boost::optional parseUnsignedBase10Integer(StringData integer); - -} // namespace mongo diff --git a/src/mongo/util/stringutils_test.cpp b/src/mongo/util/stringutils_test.cpp deleted file mode 100644 index 675e7cb78f1..00000000000 --- a/src/mongo/util/stringutils_test.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * 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 - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * 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 Server Side 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. - */ - -#include "mongo/unittest/unittest.h" - -#include "mongo/util/hex.h" -#include "mongo/util/stringutils.h" - -namespace mongo { - -using std::string; - -TEST(StringUtilsTest, Basic) { - // - // Basic version comparison tests with different version string types - // - - // Equal - ASSERT(versionCmp("1.2.3", "1.2.3") == 0); - - // Basic - ASSERT(versionCmp("1.2.3", "1.2.4") < 0); - ASSERT(versionCmp("1.2.3", "1.2.20") < 0); - ASSERT(versionCmp("1.2.3", "1.20.3") < 0); - ASSERT(versionCmp("2.2.3", "10.2.3") < 0); - - // Post-fixed - ASSERT(versionCmp("1.2.3", "1.2.3-") > 0); - ASSERT(versionCmp("1.2.3", "1.2.3-pre") > 0); - ASSERT(versionCmp("1.2.3", "1.2.4-") < 0); - ASSERT(versionCmp("1.2.3-", "1.2.3") < 0); - ASSERT(versionCmp("1.2.3-pre", "1.2.3") < 0); -} - -TEST(StringUtilsTest, Simple1) { - ASSERT_EQUALS(0, LexNumCmp::cmp("a.b.c", "a.b.c", false)); -} - -void assertCmp(int expected, StringData s1, StringData s2, bool lexOnly = false) { - mongo::LexNumCmp cmp(lexOnly); - ASSERT_EQUALS(expected, cmp.cmp(s1, s2, lexOnly)); - ASSERT_EQUALS(expected, cmp.cmp(s1, s2)); - ASSERT_EQUALS(expected < 0, cmp(s1, s2)); -} - -TEST(StringUtilsTest, Simple2) { - ASSERT(!isdigit((char)255)); - - assertCmp(0, "a", "a"); - assertCmp(-1, "a", "aa"); - assertCmp(1, "aa", "a"); - assertCmp(-1, "a", "b"); - assertCmp(1, "100", "50"); - assertCmp(-1, "50", "100"); - assertCmp(1, "b", "a"); - assertCmp(0, "aa", "aa"); - assertCmp(-1, "aa", "ab"); - assertCmp(1, "ab", "aa"); - assertCmp(1, "0", "a"); - assertCmp(1, "a0", "aa"); - assertCmp(-1, "a", "0"); - assertCmp(-1, "aa", "a0"); - assertCmp(0, "0", "0"); - assertCmp(0, "10", "10"); - assertCmp(-1, "1", "10"); - assertCmp(1, "10", "1"); - assertCmp(1, "11", "10"); - assertCmp(-1, "10", "11"); - assertCmp(1, "f11f", "f10f"); - assertCmp(-1, "f10f", "f11f"); - assertCmp(-1, "f11f", "f111"); - assertCmp(1, "f111", "f11f"); - assertCmp(-1, "f12f", "f12g"); - assertCmp(1, "f12g", "f12f"); - assertCmp(1, "aa{", "aab"); - assertCmp(-1, "aa{", "aa1"); - assertCmp(-1, "a1{", "a11"); - assertCmp(1, "a1{a", "a1{"); - assertCmp(-1, "a1{", "a1{a"); - assertCmp(1, "21", "11"); - assertCmp(-1, "11", "21"); - - assertCmp(-1, "a.0", "a.1"); - assertCmp(-1, "a.0.b", "a.1"); - - assertCmp(-1, "b.", "b.|"); - assertCmp(-1, "b.0e", (string("b.") + (char)255).c_str()); - assertCmp(-1, "b.", "b.0e"); - - assertCmp(0, "238947219478347782934718234", "238947219478347782934718234"); - assertCmp(0, "000238947219478347782934718234", "238947219478347782934718234"); - assertCmp(1, "000238947219478347782934718235", "238947219478347782934718234"); - assertCmp(-1, "238947219478347782934718234", "238947219478347782934718234.1"); - assertCmp(0, "238", "000238"); - assertCmp(0, "002384", "0002384"); - assertCmp(0, "00002384", "0002384"); - assertCmp(0, "0", "0"); - assertCmp(0, "0000", "0"); - assertCmp(0, "0", "000"); - assertCmp(-1, "0000", "0.0"); - assertCmp(1, "2380", "238"); - assertCmp(1, "2385", "2384"); - assertCmp(1, "2385", "02384"); - assertCmp(1, "2385", "002384"); - assertCmp(-1, "123.234.4567", "00238"); - assertCmp(0, "123.234", "00123.234"); - assertCmp(0, "a.123.b", "a.00123.b"); - assertCmp(1, "a.123.b", "a.b.00123.b"); - assertCmp(-1, "a.00.0", "a.0.1"); - assertCmp(0, "01.003.02", "1.3.2"); - assertCmp(-1, "1.3.2", "10.300.20"); - assertCmp(0, "10.300.20", "000000000000010.0000300.000000020"); - assertCmp(0, "0000a", "0a"); - assertCmp(-1, "a", "0a"); - assertCmp(-1, "000a", "001a"); - assertCmp(0, "010a", "0010a"); - - assertCmp(-1, "a0", "a00"); - assertCmp(0, "a.0", "a.00"); - assertCmp(-1, "a.b.c.d0", "a.b.c.d00"); - assertCmp(1, "a.b.c.0.y", "a.b.c.00.x"); - - assertCmp(-1, "a", "a-"); - assertCmp(1, "a-", "a"); - assertCmp(0, "a-", "a-"); - - assertCmp(-1, "a", "a-c"); - assertCmp(1, "a-c", "a"); - assertCmp(0, "a-c", "a-c"); - - assertCmp(1, "a-c.t", "a.t"); - assertCmp(-1, "a.t", "a-c.t"); - assertCmp(0, "a-c.t", "a-c.t"); - - assertCmp(1, "ac.t", "a.t"); - assertCmp(-1, "a.t", "ac.t"); - assertCmp(0, "ac.t", "ac.t"); -} - -TEST(StringUtilsTest, LexOnly) { - assertCmp(-1, "0", "00", true); - assertCmp(1, "1", "01", true); - assertCmp(-1, "1", "11", true); - assertCmp(1, "2", "11", true); -} - -TEST(StringUtilsTest, Substring1) { - assertCmp(0, "1234", "1234", false); - assertCmp(0, StringData("1234"), StringData("1234"), false); - assertCmp(0, StringData("1234", 4), StringData("1234", 4), false); - assertCmp(-1, StringData("123", 3), StringData("1234", 4), false); - - - assertCmp(0, StringData("0001", 3), StringData("0000", 3), false); -} - -TEST(StringUtilsTest, VariousConversions) { - ASSERT_EQUALS(std::string("0"), integerToHex(0)); - ASSERT_EQUALS(std::string("1"), integerToHex(1)); - ASSERT_EQUALS(std::string("1337"), integerToHex(0x1337)); - ASSERT_EQUALS(std::string("FFFFD499"), integerToHex(-11111)); - ASSERT_EQUALS(std::string("F1FE60C4"), integerToHex(-234987324)); - ASSERT_EQUALS(std::string("80000000"), integerToHex(std::numeric_limits::min())); - ASSERT_EQUALS(std::string("7FFFFFFF"), integerToHex(std::numeric_limits::max())); - ASSERT_EQUALS(std::string("7FFFFFFFFFFFFFFF"), - integerToHex(std::numeric_limits::max())); - ASSERT_EQUALS(std::string("8000000000000000"), - integerToHex(std::numeric_limits::min())); -} - -TEST(StringUtilsTest, unsignedFixedLengthHex) { - ASSERT_EQUALS(unsignedIntToFixedLengthHex(std::numeric_limits::max()), - std::string("FFFFFFFF")); - ASSERT_EQUALS(unsignedIntToFixedLengthHex(0), std::string("00000000")); - ASSERT_EQUALS(unsignedIntToFixedLengthHex(123), std::string("0000007B")); -} - -TEST(StringUtilsTest, CanParseZero) { - boost::optional result = parseUnsignedBase10Integer("0"); - ASSERT(result && *result == 0); -} - -TEST(StringUtilsTest, CanParseDoubleZero) { - boost::optional result = parseUnsignedBase10Integer("00"); - ASSERT(result && *result == 0); -} - -TEST(StringUtilsTest, PositivePrefixFailsToParse) { - boost::optional result = parseUnsignedBase10Integer("+0"); - ASSERT(!result); -} - -TEST(StringUtilsTest, NegativePrefixFailsToParse) { - boost::optional result = parseUnsignedBase10Integer("-0"); - ASSERT(!result); -} - -TEST(StringUtilsTest, CanParseIntValue) { - boost::optional result = parseUnsignedBase10Integer("10"); - ASSERT(result && *result == 10); -} - -TEST(StringUtilsTest, CanParseIntValueWithLeadingZeros) { - boost::optional result = parseUnsignedBase10Integer("0010"); - ASSERT(result && *result == 10); -} - -TEST(StringUtilsTest, TrailingLetterFailsToParse) { - boost::optional result = parseUnsignedBase10Integer("5a"); - ASSERT(!result); -} - -TEST(StringUtilsTest, LeadingLetterFailsToParse) { - boost::optional result = parseUnsignedBase10Integer("a5"); - ASSERT(!result); -} - -TEST(StringUtilsTest, LetterWithinNumberFailsToParse) { - boost::optional result = parseUnsignedBase10Integer("5a5"); - ASSERT(!result); -} - -TEST(StringUtilsTest, HexStringFailsToParse) { - boost::optional result = parseUnsignedBase10Integer("0xfeed"); - ASSERT(!result); -} - -TEST(StringUtilsTest, BinaryStringFailsToParse) { - boost::optional result = parseUnsignedBase10Integer("0b11010010"); - ASSERT(!result); -} - -TEST(StringUtilsTest, LeadingWhitespaceFailsToParse) { - boost::optional result = parseUnsignedBase10Integer(" 10"); - ASSERT(!result); -} - -TEST(StringUtilsTest, TrailingWhitespaceFailsToParse) { - boost::optional result = parseUnsignedBase10Integer("10 "); - ASSERT(!result); -} - -TEST(StringUtilsTest, WhitespaceWithinNumberFailsToParse) { - boost::optional result = parseUnsignedBase10Integer(" 10"); - ASSERT(!result); -} -} // namespace mongo -- cgit v1.2.1