From e4df39ab9f8e14cf16858cb5d293d0b5cd079b0f Mon Sep 17 00:00:00 2001 From: Jon Kenkel Date: Tue, 15 Feb 2022 23:04:07 -0500 Subject: [PATCH 1/2] Exclude Visual Studio cmake directories --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4223e50..06c35d3 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,6 @@ Thumbs.db /thirdparty/include-what-you-use /Default.xml /documentation/ -/build/ \ No newline at end of file +/build/ +/.vs/ +/out/ From cfd8221b1da1ebd12820f05c16c6ab43dc4747c1 Mon Sep 17 00:00:00 2001 From: Jon Kenkel Date: Tue, 15 Feb 2022 23:07:32 -0500 Subject: [PATCH 2/2] Removed custom string class With the custom string class, there is no way to use `RegisterVariable` with a `std::string` variable. This does break using a string `csys::Arg` and having the callable accept a `const char*` parameter. --- CMakeLists.txt | 2 +- include/csys/argument_parser.h | 102 ++++++++++++------------- include/csys/arguments.h | 38 +++++----- include/csys/command.h | 40 +++++----- include/csys/string.h | 131 ++++++++++----------------------- include/csys/system.h | 30 ++++---- include/csys/system.inl | 22 +++--- tests/test_string_argument.cpp | 57 +++++++------- tests/test_system.cpp | 5 +- 9 files changed, 187 insertions(+), 240 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6a7f99..586c7b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ cmake_minimum_required(VERSION 3.1...3.18) include(cmake/csys_utils.cmake) # Configure library version -set(CSYS_MAJOR_VERSION 1) +set(CSYS_MAJOR_VERSION 2) set(CSYS_MINOR_VERSION 0) set(CSYS_PATCH_VERSION 0) set(CSYS_VERSION diff --git a/include/csys/argument_parser.h b/include/csys/argument_parser.h index b27aba7..1b34d7c 100644 --- a/include/csys/argument_parser.h +++ b/include/csys/argument_parser.h @@ -116,7 +116,7 @@ namespace csys * \param start * Start in 'input' to where this argument should be parsed from */ - inline ArgumentParser(String &input, size_t &start); + inline ArgumentParser(std::string &input, size_t &start); T m_Value; //!< Value of parsed argument }; @@ -129,16 +129,16 @@ namespace csys template<> \ struct CSYS_API ArgumentParser \ { \ - inline ArgumentParser(String &input, size_t &start); \ - TYPE m_Value = 0; \ + inline ArgumentParser(std::string &input, size_t &start); \ + TYPE m_Value{}; \ }; \ - inline ArgumentParser::ArgumentParser(String &input, size_t &start) + inline ArgumentParser::ArgumentParser(std::string &input, size_t &start) /*! * \brief * Macro for getting the sub-string within a range, used for readability */ -#define ARG_PARSE_SUBSTR(range) input.m_String.substr(range.first, range.second - range.first) +#define ARG_PARSE_SUBSTR(range) input.substr(range.first, range.second - range.first) /*! * \brief @@ -147,7 +147,7 @@ namespace csys #define ARG_PARSE_GENERAL_SPEC(TYPE, TYPE_NAME, FUNCTION) \ ARG_PARSE_BASE_SPEC(TYPE) \ { \ - auto range = input.NextPoi(start); \ + auto range = NextPoi(input, start); \ try \ { \ m_Value = (TYPE)FUNCTION(ARG_PARSE_SUBSTR(range), &range.first); \ @@ -155,21 +155,21 @@ namespace csys catch (const std::out_of_range&) \ { \ throw Exception(std::string("Argument too large for ") + TYPE_NAME, \ - input.m_String.substr(range.first, range.second)); \ + input.substr(range.first, range.second)); \ } \ catch (const std::invalid_argument&) \ { \ throw Exception(std::string("Missing or invalid ") + TYPE_NAME + " argument", \ - input.m_String.substr(range.first, range.second)); } \ + input.substr(range.first, range.second)); } \ } /*! * \brief * Template specialization for string argument parsing */ - ARG_PARSE_BASE_SPEC(csys::String) + ARG_PARSE_BASE_SPEC(std::string) { - m_Value.m_String.clear(); // Empty string before using + m_Value.clear(); // Empty string before using // Lambda for getting a word from the string and checking for reserved chars static auto GetWord = [](std::string &str, size_t start, size_t end) @@ -200,11 +200,11 @@ namespace csys }; // Go to the start of the string argument - auto range = input.NextPoi(start); + auto range = NextPoi(input, start); // If its a single string - if (input.m_String[range.first] != '"') - m_Value = GetWord(input.m_String, range.first, range.second); + if (input[range.first] != '"') + m_Value = GetWord(input, range.first, range.second); // Multi word string else { @@ -212,28 +212,28 @@ namespace csys while (true) { // Get the next non-escaped " - range.second = input.m_String.find('"', range.first); - while (range.second != std::string::npos && Reserved::IsEscaped(input.m_String, range.second)) - range.second = input.m_String.find('"', range.second + 1); + range.second = input.find('"', range.first); + while (range.second != std::string::npos && Reserved::IsEscaped(input, range.second)) + range.second = input.find('"', range.second + 1); // Check for closing " if (range.second == std::string::npos) { - range.second = input.m_String.size(); + range.second = input.size(); throw Exception("Could not find closing '\"'", ARG_PARSE_SUBSTR(range)); } // Add word to already existing string - m_Value.m_String += GetWord(input.m_String, range.first, range.second); + m_Value += GetWord(input, range.first, range.second); // Go to next word range.first = range.second + 1; // End of string check - if (range.first < input.m_String.size() && !std::isspace(input.m_String[range.first]) && input.m_String[range.first] != '\0') + if (range.first < input.size() && !std::isspace(input[range.first])) { // joining two strings together - if (input.m_String[range.first] == '"') + if (input[range.first] == '"') ++range.first; } else @@ -258,26 +258,26 @@ namespace csys static const char *s_true = "true"; // Get argument - auto range = input.NextPoi(start); + auto range = NextPoi(input, start); // check if the length is between the len of "true" and "false" - input.m_String[range.first] = char(std::tolower(input.m_String[range.first])); + input[range.first] = char(std::tolower(input[range.first])); // true branch - if (range.second - range.first == 4 && input.m_String[range.first] == 't') + if (range.second - range.first == 4 && input[range.first] == 't') { // Go through comparing grabbed arg to "true" char by char, bail if not the same for (size_t i = range.first + 1; i < range.second; ++i) - if ((input.m_String[i] = char(std::tolower(input.m_String[i]))) != s_true[i - range.first]) + if ((input[i] = char(std::tolower(input[i]))) != s_true[i - range.first]) throw Exception(s_err_msg + std::string(", expected true"), ARG_PARSE_SUBSTR(range)); m_Value = true; } // false branch - else if (range.second - range.first == 5 && input.m_String[range.first] == 'f') + else if (range.second - range.first == 5 && input[range.first] == 'f') { // Go through comparing grabbed arg to "false" char by char, bail if not the same for (size_t i = range.first + 1; i < range.second; ++i) - if ((input.m_String[i] = char(std::tolower(input.m_String[i]))) != s_false[i - range.first]) + if ((input[i] = char(std::tolower(input[i]))) != s_false[i - range.first]) throw Exception(s_err_msg + std::string(", expected false"), ARG_PARSE_SUBSTR(range)); m_Value = false; } @@ -293,7 +293,7 @@ namespace csys ARG_PARSE_BASE_SPEC(char) { // Grab the argument - auto range = input.NextPoi(start); + auto range = NextPoi(input, start); size_t len = range.second - range.first; // Check if its 3 or more letters @@ -303,18 +303,18 @@ namespace csys else if (len == 2) { // Check if the first char is \ and the second is a reserved char - if (!Reserved::IsEscaping(input.m_String, range.first)) + if (!Reserved::IsEscaping(input, range.first)) throw Exception("Too many chars were given", ARG_PARSE_SUBSTR(range)); // is correct - m_Value = input.m_String[range.first + 1]; + m_Value = input[range.first + 1]; } // if its one char and reserved - else if (Reserved::IsReservedChar(input.m_String[range.first])) + else if (Reserved::IsReservedChar(input[range.first])) throw Exception(s_ErrMsgReserved, ARG_PARSE_SUBSTR(range)); // one char, not reserved else - m_Value = input.m_String[range.first]; + m_Value = input[range.first]; } /*! @@ -324,7 +324,7 @@ namespace csys ARG_PARSE_BASE_SPEC(unsigned char) { // Grab the argument - auto range = input.NextPoi(start); + auto range = NextPoi(input, start); size_t len = range.second - range.first; // Check if its 3 or more letters @@ -334,18 +334,18 @@ namespace csys else if (len == 2) { // Check if the first char is \ and the second is a reserved char - if (!Reserved::IsEscaping(input.m_String, range.first)) + if (!Reserved::IsEscaping(input, range.first)) throw Exception("Too many chars were given", ARG_PARSE_SUBSTR(range)); // is correct - m_Value = static_cast(input.m_String[range.first + 1]); + m_Value = static_cast(input[range.first + 1]); } // if its one char and reserved - else if (Reserved::IsReservedChar(input.m_String[range.first])) + else if (Reserved::IsReservedChar(input[range.first])) throw Exception(s_ErrMsgReserved, ARG_PARSE_SUBSTR(range)); // one char, not reserved else - m_Value = static_cast(input.m_String[range.first]); + m_Value = static_cast(input[range.first]); } /*! @@ -432,7 +432,7 @@ namespace csys * \param start * Start of this argument */ - ArgumentParser(String &input, size_t &start); + ArgumentParser(std::string &input, size_t &start); std::vector m_Value; //!< Vector of data parsed }; @@ -448,57 +448,57 @@ namespace csys * Start of this argument */ template - ArgumentParser>::ArgumentParser(String &input, size_t &start) + ArgumentParser>::ArgumentParser(std::string &input, size_t &start) { // Clean out vector before use m_Value.clear(); // Grab the start of the vector argument - auto range = input.NextPoi(start); + auto range = NextPoi(input, start); // Empty - if (range.first == input.End()) return; + if (range.first == EndPoi(input)) return; // Not starting with [ - if (input.m_String[range.first] != '[') + if (input[range.first] != '[') throw Exception("Invalid vector argument missing opening [", ARG_PARSE_SUBSTR(range)); // Erase [ - input.m_String[range.first] = ' '; + input[range.first] = ' '; while (true) { // Get next argument in vector - range = input.NextPoi(range.first); + range = NextPoi(input, range.first); // No more, empty vector - if (range.first == input.End()) return; + if (range.first == EndPoi(input)) return; // Is a nested vector, go deeper - else if (input.m_String[range.first] == '[') + else if (input[range.first] == '[') m_Value.push_back(ArgumentParser(input, range.first).m_Value); else { // Find first non-escaped ] - range.second = input.m_String.find(']', range.first); - while (range.second != std::string::npos && Reserved::IsEscaped(input.m_String, range.second)) - range.second = input.m_String.find(']', range.second + 1); + range.second = input.find(']', range.first); + while (range.second != std::string::npos && Reserved::IsEscaped(input, range.second)) + range.second = input.find(']', range.second + 1); // Check for closing ] if (range.second == std::string::npos) { - range.second = input.m_String.size(); + range.second = input.size(); throw Exception("Invalid vector argument missing closing ]", ARG_PARSE_SUBSTR(range)); } // Erase ] - input.m_String[range.second] = ' '; + input[range.second] = ' '; start = range.first; // Parse all arguments contained within the vector while (true) { // If end of parsing, get out - if ((range.first = input.NextPoi(range.first).first) >= range.second) + if ((range.first = NextPoi(input, range.first).first) >= range.second) { start = range.first; return; diff --git a/include/csys/arguments.h b/include/csys/arguments.h index 4d97566..2cd1279 100644 --- a/include/csys/arguments.h +++ b/include/csys/arguments.h @@ -22,9 +22,9 @@ namespace csys template<> \ struct CSYS_API ArgData \ { \ - explicit ArgData(String name) : m_Name(std::move(name)), m_Value() {} \ - const String m_Name; \ - String m_TypeName = TYPE_NAME; \ + explicit ArgData(std::string name) : m_Name(std::move(name)), m_Value() {} \ + const std::string m_Name; \ + std::string m_TypeName = TYPE_NAME; \ TYPE m_Value; \ }; @@ -51,16 +51,16 @@ namespace csys * \param name * Name of the argument */ - explicit ArgData(String name) : m_Name(std::move(name)), m_Value() + explicit ArgData(std::string name) : m_Name(std::move(name)), m_Value() { } - const String m_Name = ""; //!< Name of argument - String m_TypeName = "Unsupported Type"; //!< Name of type + const std::string m_Name = ""; //!< Name of argument + std::string m_TypeName = "Unsupported Type"; //!< Name of type T m_Value; //!< Actual value }; //! Supported types - SUPPORT_TYPE(String, "String") + SUPPORT_TYPE(std::string, "String") SUPPORT_TYPE(bool, "Boolean") @@ -101,12 +101,12 @@ namespace csys * \param name * Name for argument */ - explicit ArgData(String name) : m_Name(std::move(name)) + explicit ArgData(std::string name) : m_Name(std::move(name)) {} - const String m_Name; //!< Name of argument - String m_TypeName = std::string("Vector_Of_") + ArgData("").m_TypeName.m_String; //!< Type name - std::vector m_Value; //!< Vector of data + const std::string m_Name; //!< Name of argument + std::string m_TypeName = std::string("Vector_Of_") + ArgData("").m_TypeName; //!< Type name + std::vector m_Value; //!< Vector of data }; /*! @@ -136,7 +136,7 @@ namespace csys * \param name * Name of the argument */ - explicit Arg(const String &name) : m_Arg(name) + explicit Arg(const std::string &name) : m_Arg(name) { static_assert(is_supported_type_v, "ValueType 'T' is not supported, see 'Supported types' for more help"); @@ -152,13 +152,13 @@ namespace csys * \return * Returns this */ - Arg &Parse(String &input, size_t &start) + Arg &Parse(std::string &input, size_t &start) { size_t index = start; // Check if there are more arguments to be read in - if (input.NextPoi(index).first == input.End()) - throw Exception("Not enough arguments were given", input.m_String); + if (NextPoi(input, index).first == EndPoi(input)) + throw Exception("Not enough arguments were given", input); // Set value grabbed from input aka command line argument m_Arg.m_Value = ArgumentParser(input, start).m_Value; return *this; @@ -172,7 +172,7 @@ namespace csys */ std::string Info() { - return std::string(" [") + m_Arg.m_Name.m_String + ":" + m_Arg.m_TypeName.m_String + "]"; + return std::string(" [") + m_Arg.m_Name + ":" + m_Arg.m_TypeName + "]"; } ArgData m_Arg; //!< Data relating to this argument @@ -196,10 +196,10 @@ namespace csys * \return * Returns this */ - Arg &Parse(String &input, size_t &start) + Arg &Parse(std::string &input, size_t &start) { - if (input.NextPoi(start).first != input.End()) - throw Exception("Too many arguments were given", input.m_String); + if (NextPoi(input, start).first != EndPoi(input)) + throw Exception("Too many arguments were given", input); return *this; } }; diff --git a/include/csys/command.h b/include/csys/command.h index dc1b665..9b41cfa 100644 --- a/include/csys/command.h +++ b/include/csys/command.h @@ -35,7 +35,7 @@ namespace csys * \return * Returns item error if the parsing in someway was messed up, and none if there was no issue */ - virtual Item operator()(String &input) = 0; + virtual Item operator()(std::string &input) = 0; /*! * \brief @@ -87,10 +87,10 @@ namespace csys * \param args * Arguments to be used for parsing and passing into the function. Must be of type "Arg" */ - Command(String name, String description, Fn function, Args... args) : m_Name(std::move(name)), - m_Description(std::move(description)), - m_Function(function), - m_Arguments(args..., Arg()) + Command(std::string name, std::string description, Fn function, Args... args) : m_Name(std::move(name)), + m_Description(std::move(description)), + m_Function(function), + m_Arguments(args..., Arg()) {} /*! @@ -101,7 +101,7 @@ namespace csys * \return * Returns item error if the parsing in someway was messed up, and none if there was no issue */ - Item operator()(String &input) final + Item operator()(std::string &input) final { try { @@ -112,7 +112,7 @@ namespace csys catch (Exception &ae) { // Error happened with parsing - return Item(ERROR) << (m_Name.m_String + ": " + ae.what()); + return Item(ERROR) << (m_Name + ": " + ae.what()); } return Item(NONE); } @@ -125,8 +125,8 @@ namespace csys */ [[nodiscard]] std::string Help() final { - return m_Name.m_String + DisplayArguments(std::make_index_sequence{}) + "\n\t\t- " + - m_Description.m_String + "\n\n"; + return m_Name + DisplayArguments(std::make_index_sequence{}) + "\n\t\t- " + + m_Description + "\n\n"; } /*! @@ -162,7 +162,7 @@ namespace csys * String of arguments to be parsed */ template - void Call(String &input, const std::index_sequence &, const std::index_sequence &) + void Call(std::string &input, const std::index_sequence &, const std::index_sequence &) { size_t start = 0; @@ -188,8 +188,8 @@ namespace csys return (std::get(m_Arguments).Info() + ...); } - const String m_Name; //!< Name of command - const String m_Description; //!< Description of the command + const std::string m_Name; //!< Name of command + const std::string m_Description; //!< Description of the command std::function m_Function; //!< Function to be invoked as command std::tuple> m_Arguments; //!< Arguments to be passed into m_Function }; @@ -215,9 +215,9 @@ namespace csys * \param function * Function to run when command is called */ - Command(String name, String description, Fn function) : m_Name(std::move(name)), - m_Description(std::move(description)), - m_Function(function), m_Arguments(Arg()) + Command(std::string name, std::string description, Fn function) : m_Name(std::move(name)), + m_Description(std::move(description)), + m_Function(function), m_Arguments(Arg()) {} /*! @@ -228,7 +228,7 @@ namespace csys * \return * Returns item error if the parsing in someway was messed up, and none if there was no issue */ - Item operator()(String &input) final + Item operator()(std::string &input) final { // call the function size_t start = 0; @@ -240,7 +240,7 @@ namespace csys catch (Exception &ae) { // Command had something passed into it - return Item(ERROR) << (m_Name.m_String + ": " + ae.what()); + return Item(ERROR) << (m_Name + ": " + ae.what()); } // Call function @@ -256,7 +256,7 @@ namespace csys */ [[nodiscard]] std::string Help() final { - return m_Name.m_String + "\n\t\t- " + m_Description.m_String + "\n\n"; + return m_Name + "\n\t\t- " + m_Description + "\n\n"; } /*! @@ -282,8 +282,8 @@ namespace csys } private: - const String m_Name; //!< Name of command - const String m_Description; //!< Description of the command + const std::string m_Name; //!< Name of command + const std::string m_Description; //!< Description of the command std::function m_Function; //!< Function to be invoked as command std::tuple> m_Arguments; //!< Arguments to be passed into m_Function }; diff --git a/include/csys/string.h b/include/csys/string.h index 8a70312..a4a916c 100644 --- a/include/csys/string.h +++ b/include/csys/string.h @@ -12,99 +12,48 @@ namespace csys { /*! - * \brief - * Wrapper around std::string to be used with parsing a string argument - */ - struct CSYS_API String + * \brief + * Moves until first non-whitespace char, and continues until the end of the string or a whitespace has is + * found + * \param start + * Where to start scanning from. Will be set to pair.second + * \return + * Returns the first element and one passed the end of non-whitespace. In other words [first, second) + */ + inline std::pair NextPoi(const std::string& str, size_t &start) { - /*! - * \brief - * Default constructor - */ - String() = default; + size_t end = str.size(); + std::pair range(end + 1, end); + size_t pos = start; + + // Go to the first non-whitespace char + for (; pos < end; ++pos) + if (!std::isspace(str[pos])) + { + range.first = pos; + break; + } + + // Go to the first whitespace char + for (; pos < end; ++pos) + if (std::isspace(str[pos])) + { + range.second = pos; + break; + } + + start = range.second; + return range; + } - /*! - * \brief - * Conversion constructor from c-style string. A deep copy is made - * \param str - * String to be converted - */ - String(const char *str [[maybe_unused]]) : m_String(str ? str : "") - {} - - /*! - * \brief - * Conversion constructor from an std::string to csys::String. A deep copy is made - * \param str - * String to be converted - */ - String(std::string str) : m_String(std::move(str)) - {} - - /*! - * \brief - * Conversion constructor from csys::String to a c-style string - * \return - * Returns a pointer to the string contained within this string - */ - operator const char *() - { return m_String.c_str(); } - - /*! - * \brief - * Conversion constructor from csys::String to an std::string - * \return - * Returns a copy of this string - */ - operator std::string() - { return m_String; } - - /*! - * \brief - * Moves until first non-whitespace char, and continues until the end of the string or a whitespace has is - * found - * \param start - * Where to start scanning from. Will be set to pair.second - * \return - * Returns the first element and one passed the end of non-whitespace. In other words [first, second) - */ - std::pair NextPoi(size_t &start) const - { - size_t end = m_String.size(); - std::pair range(end + 1, end); - size_t pos = start; - - // Go to the first non-whitespace char - for (; pos < end; ++pos) - if (!std::isspace(m_String[pos]) && m_String[pos] != '\0') - { - range.first = pos; - break; - } - - // Go to the first whitespace char - for (; pos < end; ++pos) - if (std::isspace(m_String[pos]) || m_String[pos] == '\0') - { - range.second = pos; - break; - } - - start = range.second; - return range; - } - - /*! - * \brief - * Returns a value to be compared with the .first of the pair returned from NextPoi - * \return - * Returns size of string + 1 - */ - [[nodiscard]] size_t End() const - { return m_String.size() + 1; } - - std::string m_String; //!< String data member - }; + /*! + * \brief + * Returns a value to be compared with the .first of the pair returned from NextPoi + * \return + * Returns size of string + 1 + */ + [[nodiscard]] inline size_t EndPoi(const std::string& str) + { return str.size() + 1; } } #endif //CSYS_CSYS_STRING_H diff --git a/include/csys/system.h b/include/csys/system.h index 51ce00e..9c2f51b 100644 --- a/include/csys/system.h +++ b/include/csys/system.h @@ -57,7 +57,7 @@ namespace csys * System to be copied. */ System &operator=(const System &rhs); - + /*! * \brief * Parse given command line input and run it @@ -152,7 +152,7 @@ namespace csys * List of csys::Args that matches that of the argument list of 'function' */ template - void RegisterCommand(const String &name, const String &description, Fn function, Args... args) + void RegisterCommand(const std::string &name, const std::string &description, Fn function, Args... args) { // Check if function can be called with the given arguments and is not part of a class static_assert(std::is_invocable_v, "Arguments specified do not match that of the function"); @@ -160,24 +160,24 @@ namespace csys // Move to command size_t name_index = 0; - auto range = name.NextPoi(name_index); + auto range = NextPoi(name, name_index); // Command already registered - if (m_Commands.find(name.m_String) != m_Commands.end()) + if (m_Commands.find(name) != m_Commands.end()) throw csys::Exception("ERROR: Command already exists"); // Check if command has a name - else if (range.first == name.End()) + else if (range.first == EndPoi(name)) { Log(ERROR) << "Empty command name given" << csys::endl; return; } // Get command name - std::string command_name = name.m_String.substr(range.first, range.second - range.first); + std::string command_name = name.substr(range.first, range.second - range.first); // Command contains more than one word - if (name.NextPoi(name_index).first != name.End()) + if (NextPoi(name, name_index).first != EndPoi(name)) throw csys::Exception("ERROR: Whitespace separated command names are forbidden"); // Register for autocomplete. @@ -188,7 +188,7 @@ namespace csys } // Add commands to system - m_Commands[name.m_String] = std::make_unique>(name, description, function, args...); + m_Commands[name] = std::make_unique>(name, description, function, args...); // Make help command for command just added auto help = [this, command_name]() { @@ -218,7 +218,7 @@ namespace csys * Param 'var' is assumed to have a valid life-time up until it is unregistered or the program ends */ template - void RegisterVariable(const String &name, T &var, Arg... args) + void RegisterVariable(const std::string &name, T &var, Arg... args) { static_assert(std::is_constructible_v, "Type of var 'T' can not be constructed with types of 'Types'"); static_assert(sizeof... (Types) != 0, "Empty variadic list"); @@ -251,7 +251,7 @@ namespace csys * Param 'var' is assumed to have a valid life-time up until it is unregistered or the program ends */ template - void RegisterVariable(const String &name, T &var, void(*setter)(T&, Types...)) + void RegisterVariable(const std::string &name, T &var, void(*setter)(T&, Types...)) { // Register get command auto var_name = RegisterVariableAux(name, var); @@ -299,19 +299,19 @@ namespace csys protected: template - std::string RegisterVariableAux(const String &name, T &var) + std::string RegisterVariableAux(const std::string &name, T &var) { // Disable. m_RegisterCommandSuggestion = false; // Make sure only one word was passed in size_t name_index = 0; - auto range = name.NextPoi(name_index); - if (name.NextPoi(name_index).first != name.End()) + auto range = NextPoi(name, name_index); + if (NextPoi(name, name_index).first != EndPoi(name)) throw csys::Exception("ERROR: Whitespace separated variable names are forbidden"); // Get variable name - std::string var_name = name.m_String.substr(range.first, range.second - range.first); + std::string var_name = name.substr(range.first, range.second - range.first); // Get Command const auto GetFunction = [this, &var]() { @@ -332,7 +332,7 @@ namespace csys return var_name; } - void ParseCommandLine(const String &line); //!< Parse command line and execute command + void ParseCommandLine(const std::string &line); //!< Parse command line and execute command std::unordered_map> m_Commands; //!< Registered command container AutoComplete m_CommandSuggestionTree; //!< Autocomplete Ternary Search Tree for commands diff --git a/include/csys/system.inl b/include/csys/system.inl index bff3939..a786236 100644 --- a/include/csys/system.inl +++ b/include/csys/system.inl @@ -237,21 +237,21 @@ namespace csys // Private methods //////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// - CSYS_INLINE void System::ParseCommandLine(const String &line) + CSYS_INLINE void System::ParseCommandLine(const std::string &line) { // Get first non-whitespace char. size_t line_index = 0; - std::pair range = line.NextPoi(line_index); + std::pair range = NextPoi(line, line_index); // Just whitespace was passed in. Don't log as command. - if (range.first == line.End()) + if (range.first == EndPoi(line)) return; // Push to history. - m_CommandHistory.PushBack(line.m_String); + m_CommandHistory.PushBack(line); // Get name of command. - std::string command_name = line.m_String.substr(range.first, range.second - range.first); + std::string command_name = line.substr(range.first, range.second - range.first); // Set or get bool is_cmd_set = command_name == s_Set; @@ -261,22 +261,22 @@ namespace csys // Edge case for if user is just runs "help" command if (is_cmd_help) { - range = line.NextPoi(line_index); - if (range.first != line.End()) - command_name += " " + line.m_String.substr(range.first, range.second - range.first); + range = NextPoi(line, line_index); + if (range.first != EndPoi(line)) + command_name += " " + line.substr(range.first, range.second - range.first); } // Its a set or get command else if (is_cmd_set || is_cmd_get) { // Try to get variable name - if ((range = line.NextPoi(line_index)).first == line.End()) + if ((range = NextPoi(line, line_index)).first == EndPoi(line)) { Log(ERROR) << s_ErrorNoVar << endl; return; } else // Append variable name. - command_name += " " + line.m_String.substr(range.first, range.second - range.first); + command_name += " " + line.substr(range.first, range.second - range.first); } // Get runnable command @@ -287,7 +287,7 @@ namespace csys else { // Get the arguments. - String arguments = line.m_String.substr(range.second, line.m_String.size() - range.first); + std::string arguments = line.substr(range.second, line.size() - range.first); // Execute command. auto cmd_out = (*command->second)(arguments); diff --git a/tests/test_string_argument.cpp b/tests/test_string_argument.cpp index a0bd56b..ae3a3aa 100644 --- a/tests/test_string_argument.cpp +++ b/tests/test_string_argument.cpp @@ -12,81 +12,76 @@ TEST_CASE("String Argument") System s; // CORRECT USAGE SINGLE WORD - String strt; - s.RegisterCommand("0", "", [&strt](String str) + std::string strt; + s.RegisterCommand("0", "", [&strt](std::string str) { strt = str; // std::cout << "String -> " << str.m_String << std::endl; - }, Arg("")); - - s.RegisterCommand("1", "", [](const char *str) - { - CHECK(!strcmp(str, "One")); - }, Arg("")); + }, Arg("")); s.RegisterCommand("2", "", [](std::string str) { CHECK(str == "Two"); - }, Arg("")); + }, Arg("")); s.RegisterCommand("3", "", [](std::string str) { CHECK(str == ""); - }, Arg("")); + }, Arg("")); s.RunCommand("0 \" \""); // Zero\] -> Zero\] - CHECK((strt.m_String == " ")); + CHECK((strt == " ")); // single word strings s.RunCommand("0 Zero\\]"); // Zero\] -> Zero\] - CHECK((strt.m_String == "Zero]")); - strt.m_String.clear(); + CHECK((strt == "Zero]")); + strt.clear(); s.RunCommand("0 \"Zero\\\"\""); // Zero\] -> Zero\] - CHECK((strt.m_String == "Zero\"")); - strt.m_String.clear(); + CHECK((strt == "Zero\"")); + strt.clear(); s.RunCommand("0 \"Zero \\\" \\\\\""); // Zero\] -> Zero\] - CHECK((strt.m_String == "Zero \" \\")); - strt.m_String.clear(); + CHECK((strt == "Zero \" \\")); + strt.clear(); s.RunCommand("0 \"Zero\"\"One\"\" # \""); // Zero\] -> Zero\] - CHECK((strt.m_String == "ZeroOne # ")); - strt.m_String.clear(); + CHECK((strt == "ZeroOne # ")); + strt.clear(); // CORRECT USAGE MANY WORDS - s.RegisterCommand("0,1", "", [](String str, String str1) + s.RegisterCommand("0,1", "", [](std::string str, std::string str1) { - bool zero = str.m_String == "Zero"; - bool one = str1.m_String == "One"; + bool zero = str == "Zero"; + bool one = str1 == "One"; CHECK(zero); CHECK(one); - }, Arg(""), Arg("")); + }, Arg(""), Arg("")); // multi word strings s.RunCommand("0,1 \"Zero\" \"One\""); s.RunCommand("0,1 Zero One "); // CORRECT USAGE VECTOR OF MULTI WORD(S) - s.RegisterCommand("0,1,2", "", [](std::vector strs) + s.RegisterCommand("0,1,2", "", [](std::vector strs) { std::string ar[] = {"Zero", "One", "Two"}; // for(auto &str: strs) std::cout << str << std::endl; for (unsigned i = 0; i < 3; ++i) - if (strs[i].m_String != ar[i]) + if (strs[i] != ar[i]) { // std::cout << "CHECK: " << strs[i].m_String << " != " << ar[i] << std::endl; CHECK(false); return; } CHECK(true); - }, Arg>("")); + }, Arg>("")); // multi word strings s.RunCommand("0,1,2 [ \"Zero\" \"One\" \"Two\" ]"); // CORRECT USAGE VECTOR OF VECTOR OF MULTI WORD(S) - s.RegisterCommand("0,1,2,3", "", [](std::vector>) + s.RegisterCommand("0,1,2,3", "", [](std::vector>) { std::vector> arr = {{"One", "Two"}, {" |Three| |Yeet|"}, @@ -96,16 +91,16 @@ TEST_CASE("String Argument") // CHECK((strs[1][0].m_String == arr[1][0])); // CHECK((strs[2][0].m_String == arr[2][0])); // CHECK((strs[2][1].m_String == arr[2][1])); - }, Arg>>("")); + }, Arg>>("")); // multi word strings s.RunCommand("0,1,2,3 [ [\"Arg\"] ]"); - s.RegisterCommand("vecvecvec", "", [](std::vector>> strs) + s.RegisterCommand("vecvecvec", "", [](std::vector>> strs) { - bool c = strs[0][0][0].m_String == " " && strs[1][0][0].m_String == "Arg"; + bool c = strs[0][0][0] == " " && strs[1][0][0] == "Arg"; CHECK(c); - }, Arg>>>("")); + }, Arg>>>("")); s.RunCommand("vecvecvec [ \ [ \ diff --git a/tests/test_system.cpp b/tests/test_system.cpp index a037882..01f1201 100644 --- a/tests/test_system.cpp +++ b/tests/test_system.cpp @@ -12,6 +12,7 @@ TEST_CASE ("Test CSYS System Class") { test_flag = flag; }; float time_variable = 0; int temp_var = 0; + std::string temp_str = "hello"; // Test Command registration. temp.RegisterCommand("test", "Simple description", fn, csys::Arg("Test_Argument")); @@ -26,7 +27,7 @@ TEST_CASE ("Test CSYS System Class") // Registration. temp.RegisterVariable("time", time_variable, csys::Arg("")); temp.RegisterVariable("temp_var", temp_var, csys::Arg("")); - + temp.RegisterVariable("temp_str", temp_str, csys::Arg("")); temp.RegisterVariable("time_set", time_variable, setter); temp.RunCommand("set time_set 30"); @@ -39,6 +40,8 @@ TEST_CASE ("Test CSYS System Class") CHECK(time_variable == 15); temp.RunCommand("set temp_var 30"); CHECK(temp_var == 30); + temp.RunCommand("set temp_str buffalo"); + CHECK(temp_str == "buffalo"); // Test system variables. temp.UnregisterVariable("time");