Mercurial > code
changeset 670:2d4a781b517c
misc: remove everything C++
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 24 Mar 2022 07:22:08 +0100 |
parents | 72e143a85525 |
children | 2bee2b6b6386 |
files | CMakeLists.txt cpp/CMakeLists.txt cpp/is_boolean/CMakeLists.txt cpp/is_boolean/is_boolean.hpp cpp/is_boolean/test/main.cpp cpp/is_number/CMakeLists.txt cpp/is_number/is_number.hpp cpp/is_number/test/main.cpp cpp/join/CMakeLists.txt cpp/join/join.hpp cpp/join/test/main.cpp cpp/json_util/CMakeLists.txt cpp/json_util/json_util.cpp cpp/json_util/json_util.hpp cpp/json_util/test/main.cpp cpp/options/CMakeLists.txt cpp/options/options.hpp cpp/options/test/main.cpp cpp/pexec/CMakeLists.txt cpp/pexec/pexec.hpp cpp/pexec/test/main.cpp cpp/to_int/CMakeLists.txt cpp/to_int/test/main.cpp cpp/to_int/to_int.hpp |
diffstat | 24 files changed, 0 insertions(+), 1958 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -# -# CMakeLists.txt -- code building for common code -# -# Copyright (c) 2013-2019 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -cmake_minimum_required(VERSION 3.5) -project(code) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED On) - -if (CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_FLAGS "-Wall -Wextra -pedantic ${CMAKE_CXX_FLAGS}") - set(CMAKE_CXX_FLAGS_DEBUG "-Werror ${CMAKE_CXX_FLAGS_DEBUG}") -endif () - -find_package(Doxygen) -find_package(Boost REQUIRED COMPONENTS unit_test_framework) - -add_subdirectory(extern/libjson) - -enable_testing() - -# -# code_define_module -# ------------------------------------------------------------------- -# -# code_define_module( -# NAME lowercase name -# SOURCES source files -# LIBRARIES (Optional) libraries -# INCLUDES (Optional) include directories -# FLAGS (Optional) flags -# ) -# -# Create a test for the given module. -# -# This macro adds a new option WITH_<uppercase NAME> to test the module. -# -# If the module has a file test/main.cpp in its directory, a target test-<NAME> is created. -# -function(code_define_module) - set(oneValueArgs NAME) - set(multiValueArgs SOURCES LIBRARIES INCLUDES FLAGS) - - cmake_parse_arguments(MOD "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if (NOT MOD_NAME) - message(FATAL_ERROR "Argument NAME is not set") - endif () - - # Create the option for enabling the test. - string(TOUPPER ${MOD_NAME} optionname) - option(WITH_${optionname} "Enable ${MOD_NAME}" On) - - if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp AND WITH_${optionname}) - add_executable(test-${MOD_NAME} ${MOD_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp) - set_target_properties( - test-${MOD_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} - RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR} - RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR} - RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR} - RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_BINARY_DIR} - ) - target_compile_definitions( - test-${MOD_NAME} - PRIVATE - BOOST_TEST_DYN_LINK - ${MOD_FLAGS} - ) - target_include_directories( - test-${MOD_NAME} - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${MOD_INCLUDES} - ) - target_link_libraries( - test-${MOD_NAME} - Boost::dynamic_linking - Boost::disable_autolinking - Boost::unit_test_framework - ${MOD_LIBRARIES} - ) - - # Register the test. - add_test( - NAME ${MOD_NAME} - COMMAND test-${MOD_NAME} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - ) - endif () -endfunction() - -if (DOXYGEN_FOUND) - set(DOXYGEN_PROJECT_NAME code) - set(DOXYGEN_STRIP_FROM_PATH ${code_SOURCE_DIR}/cpp) - set(DOXYGEN_FILE_PATTERNS "*.hpp") - set(DOXYGEN_WARN_NO_PARAMDOC YES) - set(DOXYGEN_WARN_AS_ERROR YES) - set(DOXYGEN_QUIET YES) - - doxygen_add_docs( - doxygen - ${code_SOURCE_DIR}/cpp - WORKING_DIRECTORY ${code_SOURCE_DIR} - ) - - add_custom_target(docs ALL DEPENDS doxygen) -endif () - -add_subdirectory(cpp)
--- a/cpp/CMakeLists.txt Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -# -# CMakeLists.txt -- code building for common code -# -# Copyright (c) 2013-2019 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -add_subdirectory(is_boolean) -add_subdirectory(is_number) -add_subdirectory(join) -add_subdirectory(json_util) -add_subdirectory(options) -add_subdirectory(pexec) -add_subdirectory(to_int)
--- a/cpp/is_boolean/CMakeLists.txt Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -# -# CMakeLists.txt -- code building for common code -# -# Copyright (c) 2016-2019 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -code_define_module( - NAME is-boolean - SOURCES is_boolean.hpp -)
--- a/cpp/is_boolean/is_boolean.hpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * is_number.hpp -- check if string is a boolean - * - * Copyright (c) 2016-2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IS_BOOLEAN_HPP -#define IS_BOOLEAN_HPP - -#include <algorithm> -#include <cctype> -#include <string> - -/** - * Check if the value is a boolean, 1, yes and true are accepted. - * - * \param value the value (will be change to uppercase) - * \return true if is boolean - * \note this function is case-insensitive - */ -inline auto is_boolean(std::string value) noexcept -> bool -{ - std::transform(value.begin(), value.end(), value.begin(), [] (auto c) noexcept { - return toupper(c); - }); - - return value == "1" || value == "YES" || value == "TRUE" || value == "ON"; -} - -#endif // !IS_BOOLEAN_HPP
--- a/cpp/is_boolean/test/main.cpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * main.cpp -- test is_boolean functions - * - * Copyright (c) 2013-2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#define BOOST_TEST_MODULE "is-number" -#include <boost/test/unit_test.hpp> - -#include "is_boolean.hpp" - -BOOST_AUTO_TEST_CASE(simple_is_boolean) -{ - BOOST_REQUIRE(is_boolean("true")); - BOOST_REQUIRE(is_boolean("True")); - BOOST_REQUIRE(is_boolean("TRUE")); - BOOST_REQUIRE(is_boolean("TruE")); - BOOST_REQUIRE(is_boolean("yes")); - BOOST_REQUIRE(is_boolean("Yes")); - BOOST_REQUIRE(is_boolean("YES")); - BOOST_REQUIRE(is_boolean("YeS")); - BOOST_REQUIRE(is_boolean("on")); - BOOST_REQUIRE(is_boolean("On")); - BOOST_REQUIRE(is_boolean("oN")); - BOOST_REQUIRE(is_boolean("ON")); - BOOST_REQUIRE(is_boolean("1")); - BOOST_REQUIRE(!is_boolean("false")); - BOOST_REQUIRE(!is_boolean("lol")); - BOOST_REQUIRE(!is_boolean("")); - BOOST_REQUIRE(!is_boolean("0")); -}
--- a/cpp/is_number/CMakeLists.txt Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -# -# CMakeLists.txt -- code building for common code -# -# Copyright (c) 2016-2019 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -code_define_module( - NAME is-number - SOURCES is_number.hpp -)
--- a/cpp/is_number/is_number.hpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * is_number.hpp -- check if string is a number - * - * Copyright (c) 2016-2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IS_NUMBER_HPP -#define IS_NUMBER_HPP - -#include <cstdlib> -#include <string> - -/** - * Check if the string is an integer. - * - * \param value the input - * \param base the optional base - * \return true if integer - */ -inline auto is_int(const std::string& str, int base = 10) noexcept -> bool -{ - if (str.empty()) - return false; - - char* ptr; - - std::strtol(str.c_str(), &ptr, base); - - return *ptr == 0; -} - -/** - * Check if the string is real. - * - * \param value the value - * \return true if real - */ -inline auto is_real(const std::string &str) noexcept -> bool -{ - if (str.empty()) - return false; - - char* ptr; - - std::strtod(str.c_str(), &ptr); - - return *ptr == 0; -} - -/** - * Check if the string is a number. - * - * \param value the value - * \return true if it is a number - */ -inline auto is_number(const std::string& str) noexcept -> bool -{ - return is_int(str) || is_real(str); -} - -#endif // !IS_NUMBER_HPP
--- a/cpp/is_number/test/main.cpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * main.cpp -- test is_number functions - * - * Copyright (c) 2016-2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#define BOOST_TEST_MODULE "is-number" -#include <boost/test/unit_test.hpp> - -#include "is_number.hpp" - -BOOST_AUTO_TEST_CASE(simple_is_int) -{ - BOOST_TEST(is_int("123")); - BOOST_TEST(is_int("-126")); - BOOST_TEST(!is_int("")); - BOOST_TEST(!is_int("bdf")); - BOOST_TEST(!is_int("false")); -} - -BOOST_AUTO_TEST_CASE(simple_is_real) -{ - BOOST_TEST(is_real("123")); - BOOST_TEST(is_real("-126")); - BOOST_TEST(is_real("56.28")); - BOOST_TEST(is_real("1e5")); - BOOST_TEST(!is_real("")); - BOOST_TEST(!is_real("bdf")); - BOOST_TEST(!is_real("false")); -} - -BOOST_AUTO_TEST_CASE(simple_is_number) -{ - BOOST_TEST(is_number("123")); - BOOST_TEST(is_number("-126")); - BOOST_TEST(is_number("56.28")); - BOOST_TEST(is_number("1e5")); - BOOST_TEST(!is_number("")); - BOOST_TEST(!is_number("bdf")); - BOOST_TEST(!is_number("false")); -}
--- a/cpp/join/CMakeLists.txt Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -# -# CMakeLists.txt -- code building for common code -# -# Copyright (c) 2013-2019 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -code_define_module( - NAME join - SOURCES join.hpp -)
--- a/cpp/join/join.hpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * join.hpp -- join lists into a string - * - * Copyright (c) 2013-2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/** - * \file join.hpp - * \brief Join function - */ - -#include <initializer_list> -#include <sstream> -#include <string> - -/** - * Join values by a separator and return a string. - * - * \param first the first iterator - * \param last the last iterator - * \param delim the optional delimiter - * \return the string - */ -template <typename InputIt, typename DelimType = char> -auto join(InputIt first, InputIt last, DelimType delim = ':') -> std::string -{ - std::ostringstream oss; - - if (first != last) { - oss << *first; - - while (++first != last) - oss << delim << *first; - } - - return oss.str(); -} - -/** - * Convenient overload. - * - * \param list the initializer list - * \param delim the delimiter - * \return the string - */ -template <typename T, typename DelimType = char> -auto join(std::initializer_list<T> list, DelimType delim = ':') -> std::string -{ - return join(list.begin(), list.end(), delim); -}
--- a/cpp/join/test/main.cpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * main.cpp -- test join function - * - * Copyright (c) 2013-2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#define BOOST_TEST_MODULE "Join" -#include <boost/test/unit_test.hpp> - -#include "join.hpp" - -BOOST_AUTO_TEST_CASE(empty) -{ - std::string expected = ""; - std::string result = join<int>({}); - - BOOST_REQUIRE_EQUAL(expected, result); -} - -BOOST_AUTO_TEST_CASE(one) -{ - std::string expected = "1"; - std::string result = join({1}); - - BOOST_REQUIRE_EQUAL(expected, result); -} - -BOOST_AUTO_TEST_CASE(two) -{ - std::string expected = "1:2"; - std::string result = join({1, 2}); - - BOOST_REQUIRE_EQUAL(expected, result); -} - -BOOST_AUTO_TEST_CASE(delimiterString) -{ - std::string expected = "1;;2;;3"; - std::string result = join({1, 2, 3}, ";;"); - - BOOST_REQUIRE_EQUAL(expected, result); -} - -BOOST_AUTO_TEST_CASE(delimiterChar) -{ - std::string expected = "1@2@3@4"; - std::string result = join({1, 2, 3, 4}, '@'); - - BOOST_REQUIRE_EQUAL(expected, result); -}
--- a/cpp/json_util/CMakeLists.txt Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -# -# CMakeLists.txt -- json_util module -# -# Copyright (c) 2019 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -project(json-util) - -code_define_module( - NAME json-util - LIBRARIES libjson - SOURCES - ${json-util_SOURCE_DIR}/json_util.hpp - ${json-util_SOURCE_DIR}/json_util.cpp -)
--- a/cpp/json_util/json_util.cpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +0,0 @@ -/* - * json_util.cpp -- utilities for JSON - * - * Copyright (c) 2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <limits> -#include <type_traits> - -#include "json_util.hpp" - -using nlohmann::json; - -namespace json_util { - -namespace { - -template <typename Int> -auto clampi(const json& value) noexcept -> std::optional<Int> -{ - static_assert(std::is_signed<Int>::value, "Int must be signed"); - - if (!value.is_number_integer()) - return std::nullopt; - - const auto ret = value.get<std::int64_t>(); - - if (ret < std::numeric_limits<Int>::min() || ret > std::numeric_limits<Int>::max()) - return std::nullopt; - - return static_cast<Int>(ret); -} - -template <typename Int> -auto clampu(const json& value) noexcept -> std::optional<Int> -{ - static_assert(std::is_unsigned<Int>::value, "Int must be unsigned"); - - if (!value.is_number_unsigned()) - return std::nullopt; - - const auto ret = value.get<std::uint64_t>(); - - if (ret > std::numeric_limits<Int>::max()) - return std::nullopt; - - return static_cast<Int>(ret); -} - -} // !namespace - -auto type_traits<bool>::get(const json& value) noexcept -> std::optional<bool> -{ - if (!value.is_boolean()) - return std::nullopt; - - return value.get<bool>(); -} - -auto type_traits<double>::get(const json& value) noexcept -> std::optional<double> -{ - if (!value.is_number_float()) - return std::nullopt; - - return value.get<double>(); -} - -auto type_traits<std::string>::get(const json& value) -> std::optional<std::string> -{ - if (!value.is_string()) - return std::nullopt; - - return value.get<std::string>(); -} - -auto type_traits<std::string_view>::get(const json& value) -> std::optional<std::string_view> -{ - if (!value.is_string()) - return std::nullopt; - - return value.get<std::string_view>(); -} - -auto type_traits<std::int8_t>::get(const json& value) -> std::optional<std::int8_t> -{ - return clampi<std::int8_t>(value); -} - -auto type_traits<std::int16_t>::get(const json& value) -> std::optional<std::int16_t> -{ - return clampi<std::int16_t>(value); -} - -auto type_traits<std::int32_t>::get(const json& value) -> std::optional<std::int32_t> -{ - return clampi<std::int32_t>(value); -} - -auto type_traits<std::int64_t>::get(const json& value) noexcept -> std::optional<std::int64_t> -{ - if (!value.is_number_integer()) - return std::nullopt; - - return value.get<std::int64_t>(); -} - -auto type_traits<std::uint8_t>::get(const json& value) -> std::optional<std::uint8_t> -{ - return clampu<std::uint8_t>(value); -} - -auto type_traits<std::uint16_t>::get(const json& value) -> std::optional<std::uint16_t> -{ - return clampu<std::uint16_t>(value); -} - -auto type_traits<std::uint32_t>::get(const json& value) -> std::optional<std::uint32_t> -{ - return clampu<std::uint32_t>(value); -} - -auto type_traits<std::uint64_t>::get(const json& value) noexcept -> std::optional<std::uint64_t> -{ - if (!value.is_number_unsigned()) - return std::nullopt; - - return value.get<std::uint64_t>(); -} - -auto pretty(const json& value, int indent) -> std::string -{ - switch (value.type()) { - case json::value_t::null: - return "null"; - case json::value_t::string: - return value.get<std::string>(); - case json::value_t::boolean: - return value.get<bool>() ? "true" : "false"; - case json::value_t::number_integer: - return std::to_string(value.get<std::int64_t>()); - case json::value_t::number_unsigned: - return std::to_string(value.get<std::uint64_t>()); - case json::value_t::number_float: - return std::to_string(value.get<double>()); - default: - return value.dump(indent); - } -} - -} // !json_util
--- a/cpp/json_util/json_util.hpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,319 +0,0 @@ -/* - * json_util.hpp -- utilities for JSON - * - * Copyright (c) 2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef JSON_UTIL_HPP -#define JSON_UTIL_HPP - -/** - * \file json_util.hpp - * \brief Utilities for JSON. - */ - -#include <cstdint> -#include <optional> -#include <string> - -#include <json.hpp> - -/** - * \brief Utilities for JSON. - */ -namespace json_util { - -/** - * \brief Describe how to convert a JSON value. - * - * This traits must be specialized for every type you want to convert from JSON - * to its native type. - * - * You only need to implement the get function with the following signature: - * - * ```cpp - * static std::optional<T> get(const nlohmann::json& value); - * ``` - * - * The implementation should not throw an exception but return a null optional - * instead. - * - * This traits is already specialized for the given types: - * - * - bool - * - double - * - std::uint(8, 16, 32, 64)_t - * - std::string - */ -template <typename T> -struct type_traits; - -/** - * \brief Specialization for `bool`. - */ -template <> -struct type_traits<bool> { - /** - * Convert the JSON value to bool. - * - * \param value the value - * \return the bool or empty if not a boolean type - */ - static auto get(const nlohmann::json& value) noexcept -> std::optional<bool>; -}; - -/** - * \brief Specialization for `double`. - */ -template <> -struct type_traits<double> { - /** - * Convert the JSON value to bool. - * - * \param value the value - * \return the double or empty if not a double type - */ - static auto get(const nlohmann::json& value) noexcept -> std::optional<double>; -}; - -/** - * \brief Specialization for `std::string`. - */ -template <> -struct type_traits<std::string> { - /** - * Convert the JSON value to std::string. - * - * \param value the value - * \return the string or empty if not a string type - */ - static auto get(const nlohmann::json& value) -> std::optional<std::string>; -}; - -/** - * \brief Specialization for `std::string_view`. - */ -template <> -struct type_traits<std::string_view> { - /** - * Convert the JSON value to std::string. - * - * \param value the value - * \return the string or empty if not a string type - */ - static auto get(const nlohmann::json& value) -> std::optional<std::string_view>; -}; - -/** - * \brief Specialization for `std::int8_t`. - */ -template <> -struct type_traits<std::int8_t> { - /** - * Convert the JSON value to std::int8_t. - * - * \param value the value - * \return the value or empty if value does not fit between the range - */ - static auto get(const nlohmann::json& value) -> std::optional<std::int8_t>; -}; - -/** - * \brief Specialization for `std::int16_t`. - */ -template <> -struct type_traits<std::int16_t> { - /** - * Convert the JSON value to std::int16_t. - * - * \param value the value - * \return the value or empty if value does not fit between the range - */ - static auto get(const nlohmann::json& value) -> std::optional<std::int16_t>; -}; - -/** - * \brief Specialization for `std::int32_t`. - */ -template <> -struct type_traits<std::int32_t> { - /** - * Convert the JSON value to std::int32_t. - * - * \param value the value - * \return the value or empty if value does not fit between the range - */ - static auto get(const nlohmann::json& value) -> std::optional<std::int32_t>; -}; - -/** - * \brief Specialization for `std::int64_t`. - */ -template <> -struct type_traits<std::int64_t> { - /** - * Convert the JSON value to std::int64_t. - * - * \param value the value - * \return the int or empty if not a int type - */ - static auto get(const nlohmann::json& value) noexcept -> std::optional<std::int64_t>; -}; - -/** - * \brief Specialization for `std::uint8_t`. - */ -template <> -struct type_traits<std::uint8_t> { - /** - * Convert the JSON value to std::uint8_t. - * - * \param value the value - * \return the value or empty if value does not fit between the range - */ - static auto get(const nlohmann::json& value) -> std::optional<std::uint8_t>; -}; - -/** - * \brief Specialization for `std::uint16_t`. - */ -template <> -struct type_traits<std::uint16_t> { - /** - * Convert the JSON value to std::uint16_t. - * - * \param value the value - * \return the value or empty if value does not fit between the range - */ - static auto get(const nlohmann::json& value) -> std::optional<std::uint16_t>; -}; - -/** - * \brief Specialization for `std::int32_t`. - */ -template <> -struct type_traits<std::uint32_t> { - /** - * Convert the JSON value to std::uint32_t. - * - * \param value the value - * \return the value or empty if value does not fit between the range - */ - static auto get(const nlohmann::json& value) -> std::optional<std::uint32_t>; -}; - -/** - * \brief Specialization for `std::uint64_t`. - */ -template <> -struct type_traits<std::uint64_t> { - /** - * Convert the JSON value to std::uint64_t. - * - * \param value the value - * \return the int or empty if not a int type - */ - static auto get(const nlohmann::json& value) noexcept -> std::optional<std::uint64_t>; -}; - -/** - * \brief Convenient JSON object parser - * - * This class helps destructuring insecure JSON input by returning optional - * values if they are not present or invalid. - */ -class deserializer : public nlohmann::json { -public: - /** - * Inherited constructor. - */ - using nlohmann::json::json; - - /** - * Get a value from the document object. - * - * \param key the property key - * \return the value or std::nullopt if not found or not convertible - */ - template <typename Type> - auto get(std::string_view key) const noexcept -> std::optional<Type> - { - const auto it = find(key); - - if (it == end()) - return std::nullopt; - - return type_traits<Type>::get(*it); - } - - /** - * Get a value from the document object or return def if: - * - * - Key is absent from the document - * - Object property is not the same type - * - * \param key the property key - * \param def the default value - * \return the object or def - * \throw any exception from nlohmann::json constructor - */ - template <typename Type, typename DefaultValue> - auto get_or(std::string_view key, DefaultValue&& def) const -> Type - { - const auto it = find(key); - - if (it == end()) - return std::forward<DefaultValue>(def); - if (nlohmann::json(std::forward<DefaultValue>(def)).type() != it->type()) - return std::forward<DefaultValue>(def); - - return it->get<Type>(); - } - - /** - * Get an optional value from the document object. - * - * If the value is undefined, the default value is returned. Otherwise, if - * the value is not in the given type, std::nullopt is returned. - * - * \param key the property key - * \param def the default value if property is undefined - * \return the value, std::nullopt or def - */ - template <typename Type, typename DefaultValue> - auto optional(std::string_view key, DefaultValue&& def) const noexcept -> std::optional<Type> - { - const auto it = find(key); - - if (it == end()) - return std::optional<Type>(std::forward<DefaultValue>(def)); - - return type_traits<Type>::get(*it); - } -}; - -/** - * Print the value as human readable. - * - * \note This only works on flat objects. - * \param value the value - * \param indent the optional indent for objects/arrays - * \return the string - */ -auto pretty(const nlohmann::json& value, int indent = 4) -> std::string; - -} // !json_util - -#endif // !JSON_UTIL_HPP
--- a/cpp/json_util/test/main.cpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,208 +0,0 @@ -/* - * main.cpp -- main test file for json_util - * - * Copyright (c) 2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#define BOOST_TEST_MODULE "json_util" -#include <boost/test/unit_test.hpp> - -#include <json_util.hpp> - -namespace json_util { - -class test_fixture { -protected: - deserializer document_{ - { "boolean", true }, - { "int", -1234 }, - { "int2", 1234 }, - { "uint", 1234U }, - { "string", "str" } - }; -}; - -BOOST_FIXTURE_TEST_SUITE(test_fixture_suite, test_fixture) - -BOOST_AUTO_TEST_SUITE(get) - -BOOST_AUTO_TEST_CASE(boolean) -{ - const auto v = document_.get<bool>("boolean"); - - BOOST_TEST(v.has_value()); - BOOST_TEST(*v); - BOOST_TEST(!document_.get<bool>("int")); - BOOST_TEST(!document_.get<bool>("int")); - BOOST_TEST(!document_.get<bool>("uint")); - BOOST_TEST(!document_.get<bool>("string")); -} - -BOOST_AUTO_TEST_CASE(integer) -{ - const auto v = document_.get<int>("int"); - - BOOST_TEST(v.has_value()); - BOOST_TEST(*v == -1234); - BOOST_TEST(!document_.get<int>("bool")); - BOOST_TEST(!document_.get<int>("string")); -} - -BOOST_AUTO_TEST_CASE(unsigned_integer) -{ - const auto v = document_.get<unsigned>("uint"); - - BOOST_TEST(v.has_value()); - BOOST_TEST(*v == 1234U); - BOOST_TEST(!document_.get<unsigned>("bool")); - BOOST_TEST(!document_.get<unsigned>("int")); - BOOST_TEST(!document_.get<unsigned>("string")); -} - -BOOST_AUTO_TEST_CASE(string) -{ - const auto v = document_.get<std::string>("string"); - - BOOST_TEST(v.has_value()); - BOOST_TEST(*v == "str"); - BOOST_TEST(!document_.get<std::string>("bool")); - BOOST_TEST(!document_.get<std::string>("int")); - BOOST_TEST(!document_.get<std::string>("uint")); -} - -BOOST_AUTO_TEST_CASE(string_view) -{ - const auto v = document_.get<std::string_view>("string"); - - BOOST_TEST(v.has_value()); - BOOST_TEST(*v == "str"); - BOOST_TEST(!document_.get<std::string_view>("bool")); - BOOST_TEST(!document_.get<std::string_view>("int")); - BOOST_TEST(!document_.get<std::string_view>("uint")); -} - -BOOST_AUTO_TEST_SUITE_END() - -BOOST_AUTO_TEST_SUITE(optional_not_present) - -BOOST_AUTO_TEST_CASE(boolean) -{ - BOOST_TEST(*document_.optional<bool>("undefined", true)); - BOOST_TEST(!*document_.optional<bool>("undefined", false)); -} - -BOOST_AUTO_TEST_CASE(integer) -{ - BOOST_TEST(*document_.optional<int>("undefined", 1234) == 1234); -} - -BOOST_AUTO_TEST_CASE(unsigned_integer) -{ - BOOST_TEST(*document_.optional<unsigned>("undefined", 1234U) == 1234U); -} - -BOOST_AUTO_TEST_CASE(string) -{ - BOOST_TEST(*document_.optional<std::string>("undefined", "foo") == "foo"); -} - -BOOST_AUTO_TEST_CASE(string_view) -{ - BOOST_TEST(*document_.optional<std::string_view>("undefined", "foo") == "foo"); -} - -BOOST_AUTO_TEST_SUITE_END() - -BOOST_AUTO_TEST_SUITE(optional_invalid) - -BOOST_AUTO_TEST_CASE(boolean) -{ - BOOST_TEST(!document_.optional<bool>("int", true)); - BOOST_TEST(!document_.optional<bool>("uint", true)); - BOOST_TEST(!document_.optional<bool>("string", true)); -} - -BOOST_AUTO_TEST_CASE(integer) -{ - BOOST_TEST(!document_.optional<int>("boolean", 1234)); - BOOST_TEST(!document_.optional<int>("string", 1234)); -} - -BOOST_AUTO_TEST_CASE(unsigned_integer) -{ - BOOST_TEST(!document_.optional<unsigned>("boolean", 1234)); - BOOST_TEST(!document_.optional<unsigned>("int", 1234)); - BOOST_TEST(!document_.optional<unsigned>("string", 1234)); -} - -BOOST_AUTO_TEST_CASE(string) -{ - BOOST_TEST(!document_.optional<std::string>("boolean", "foo")); - BOOST_TEST(!document_.optional<std::string>("int", "foo")); - BOOST_TEST(!document_.optional<std::string>("uint", "foo")); -} - -BOOST_AUTO_TEST_CASE(string_view) -{ - BOOST_TEST(!document_.optional<std::string_view>("boolean", "foo")); - BOOST_TEST(!document_.optional<std::string_view>("int", "foo")); - BOOST_TEST(!document_.optional<std::string_view>("uint", "foo")); -} - -BOOST_AUTO_TEST_SUITE_END() - -BOOST_AUTO_TEST_SUITE(get_or) - -BOOST_AUTO_TEST_CASE(boolean) -{ - BOOST_TEST(document_.get_or<bool>("boolean", false)); - BOOST_TEST(document_.get_or<bool>("int", true)); - BOOST_TEST(document_.get_or<bool>("undefined", true)); -} - -BOOST_AUTO_TEST_CASE(integer) -{ - BOOST_TEST(document_.get_or<int>("int", 3320) == -1234); - BOOST_TEST(document_.get_or<int>("int2", 3320) == 1234); - BOOST_TEST(document_.get_or<int>("boolean", 3320) == 3320); - BOOST_TEST(document_.get_or<int>("undefined", 3320) == 3320); -} - -BOOST_AUTO_TEST_CASE(unsigned_integer) -{ - BOOST_TEST(document_.get_or<unsigned>("uint", 3320U) == 1234U); - BOOST_TEST(document_.get_or<unsigned>("boolean", 3320U) == 3320); - BOOST_TEST(document_.get_or<unsigned>("undefined", 3320U) == 3320); -} - -BOOST_AUTO_TEST_CASE(string) -{ - BOOST_TEST(document_.get_or<std::string>("string", "hello") == "str"); - BOOST_TEST(document_.get_or<std::string>("boolean", "hello") == "hello"); - BOOST_TEST(document_.get_or<std::string>("undefined", "hello") == "hello"); -} - -BOOST_AUTO_TEST_CASE(string_view) -{ - BOOST_TEST(document_.get_or<std::string_view>("string", "hello") == "str"); - BOOST_TEST(document_.get_or<std::string_view>("boolean", "hello") == "hello"); - BOOST_TEST(document_.get_or<std::string_view>("undefined", "hello") == "hello"); -} - -BOOST_AUTO_TEST_SUITE_END() - -BOOST_AUTO_TEST_SUITE_END() - -} // !json_util
--- a/cpp/options/CMakeLists.txt Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -# -# CMakeLists.txt -- code building for common code -# -# Copyright (c) 2019 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -code_define_module( - NAME options - SOURCES options.hpp -)
--- a/cpp/options/options.hpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -/* - * options.hpp -- C++ similar interface to getopt(3) - * - * Copyright (c) 2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef OPTIONS_HPP -#define OPTIONS_HPP - -/** - * \file options.hpp - * \brief C++ similar interface to getopt(3). - */ - -#include <initializer_list> -#include <stdexcept> -#include <string> -#include <string_view> -#include <tuple> -#include <unordered_map> -#include <vector> - -/** - * \brief C++ similar interface to getopt(3). - */ -namespace options { - -/** - * Store the positional arguments and options. - */ -using pack = std::tuple< - std::vector<std::string>, - std::unordered_multimap<char, std::string> ->; - -/** - * Parse a collection of options and arguments. - * - * This function uses the same format as getopt(3) function, you need specify - * each option in the fmt string and add a colon after the option character if - * it requires a value. - * - * If a -- option appears in the argument list, it stops option parsing and all - * next tokens are considered arguments even if they start with an hyphen. - * - * If the exlamation mark appears in the fmt argument, the function will stop - * parsing tokens immediately when one argument is not an option. - * - * This function explicitly takes references to it and end parameters to allow - * the user to determine the number of tokens actually parsed. - * - * Example of format strings: - * - * - "abc": are all three boolean options, - * - "c:v": v is a boolean option c requires a value. - * - * Example of invocation: - * - * - `mycli -v -a`: is similar to `-va` if both 'v' and 'a' are boolean options, - * - `mycli -v -- -c`: -c will be a positional argument rather than an option - * but '-v' is still an option. - * - * \tparam InputIt must dereference a string type (literal, std::string_view or - * std::string) - * \param it the first item - * \param end the next item - * \param fmt the format string - * \return the result - */ -template <typename InputIt> -inline auto parse(InputIt&& it, InputIt&& end, std::string_view fmt) -> pack -{ - pack result; - - for (; it != end; ++it) { - const std::string_view token(*it); - - /* - * Special token that stops parsing options, all next tokens - * will be considered as positional arguments. - */ - if (token == "--") { - for (++it; it != end; ++it) - std::get<0>(result).push_back(std::string(*it)); - break; - } - - // Is this a positional argument? - if (token.compare(0U, 1U, "-") != 0) { - // Stop parsing in case of '!' in format string. - if (fmt.find('!') != std::string_view::npos) - break; - - std::get<0>(result).push_back(std::string(token)); - continue; - } - - const auto sub = token.substr(1); - - for (std::size_t i = 0U; i < sub.size(); ++i) { - const auto idx = fmt.find(sub[i]); - - if (idx == std::string_view::npos) - throw std::runtime_error("invalid option"); - - // This is a boolean value. - if (fmt.compare(idx + 1U, 1U, ":") != 0) { - std::get<1>(result).emplace(sub[i], ""); - continue; - } - - /* - * The value is adjacent to the option (e.g. - * -csuper.conf). - */ - if (idx + 1U < sub.size()) { - std::get<1>(result).emplace(sub[i], std::string(sub.substr(i + 1))); - break; - } - - // Option is the next token (e.g. -c super.conf). - if (++it == end || std::string_view(*it).compare(0U, 1U, "-") == 0) - throw std::runtime_error("option require a value"); - - std::get<1>(result).emplace(sub[i], std::string(*it)); - } - } - - return result; -} - -/** - * Convenient overload with an initializer_list. - * - * \tparam StringType must be either a std::string or std::string_view - * \param args the arguments - * \param fmt the format string - * \return the result - */ -template <typename String> -inline auto parse(std::initializer_list<String> args, std::string_view fmt) -> pack -{ - auto begin = args.begin(); - auto end = args.end(); - - return parse(begin, end, fmt); -} - -/** - * Convenient overload for main() arguments. - * - * \param argc the number of arguments - * \param argv the arguments - * \param fmt the format string - * \return the result - */ -inline auto parse(int argc, char** argv, std::string_view fmt) -> pack -{ - std::vector<std::string_view> args(argc); - - for (int i = 0; i < argc; ++i) - args[i] = argv[i]; - - auto begin = args.begin(); - auto end = args.end(); - - return parse(begin, end, fmt); -} - - -} // !options - -#endif // !OPTIONS_HPP
--- a/cpp/options/test/main.cpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -/* - * main.cpp -- test options functions - * - * Copyright (c) 2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#define BOOST_TEST_MODULE "options" -#include <boost/test/unit_test.hpp> - -#include "options.hpp" - -BOOST_AUTO_TEST_CASE(boolean) -{ - const auto [ args, options ] = options::parse({"-v"}, "v"); - - BOOST_TEST(args.size() == 0U); - BOOST_TEST(options.size() == 1U); - BOOST_TEST(options.count('v')); - BOOST_TEST(options.find('v')->second.empty()); -} - -BOOST_AUTO_TEST_CASE(boolean_repeat_detached) -{ - const auto [ args, options ] = options::parse({"-v", "-v"}, "v"); - - BOOST_TEST(args.size() == 0U); - BOOST_TEST(options.size() == 2U); - BOOST_TEST(options.count('v') == 2U); -} - -BOOST_AUTO_TEST_CASE(boolean_repeat_adjacent) -{ - const auto [ args, options ] = options::parse({"-vv"}, "v"); - - BOOST_TEST(args.size() == 0U); - BOOST_TEST(options.size() == 2U); - BOOST_TEST(options.count('v') == 2U); -} - -BOOST_AUTO_TEST_CASE(parameter_detached) -{ - const auto [ args, options ] = options::parse({"-c", "config"}, "c:"); - - BOOST_TEST(args.size() == 0U); - BOOST_TEST(options.size() == 1u); - BOOST_TEST(options.count('c')); - BOOST_TEST(options.find('c')->second == "config"); -} - -BOOST_AUTO_TEST_CASE(parameter_adjacent) -{ - const auto [ args, options ] = options::parse({"-cconfig"}, "c:"); - - BOOST_TEST(args.size() == 0U); - BOOST_TEST(options.size() == 1U); - BOOST_TEST(options.count('c')); - BOOST_TEST(options.find('c')->second == "config"); -} - -BOOST_AUTO_TEST_CASE(mixed_detached) -{ - const auto [ args, options ] = options::parse({"-vc", "config"}, "vc:"); - - BOOST_TEST(args.size() == 0U); - BOOST_TEST(options.size() == 2U); - BOOST_TEST(options.count('v')); - BOOST_TEST(options.find('v')->second.empty()); - BOOST_TEST(options.count('c')); - BOOST_TEST(options.find('c')->second == "config"); -} - -BOOST_AUTO_TEST_CASE(mixed_adjacent) -{ - const auto [ args, options ] = options::parse({"-vcconfig"}, "vc:"); - - BOOST_TEST(args.size() == 0U); - BOOST_TEST(options.size() == 2U); - BOOST_TEST(options.count('v')); - BOOST_TEST(options.find('v')->second.empty()); - BOOST_TEST(options.count('c')); - BOOST_TEST(options.find('c')->second == "config"); -} - -BOOST_AUTO_TEST_CASE(mixed_repeat) -{ - const auto [ args, options ] = options::parse({"-vvcconfig"}, "vc:"); - - BOOST_TEST(args.size() == 0U); - BOOST_TEST(options.size() == 3U); - BOOST_TEST(options.count('v') == 2U); - BOOST_TEST(options.find('v')->second.empty()); - BOOST_TEST(options.count('c')); - BOOST_TEST(options.find('c')->second == "config"); -} - -BOOST_AUTO_TEST_CASE(arguments) -{ - const auto [ args, options ] = options::parse({"-c", "config", "install", "-v"}, "vc:"); - - BOOST_TEST(args.size() == 1U); - BOOST_TEST(args[0] == "install"); - BOOST_TEST(options.size() == 2U); - BOOST_TEST(options.count('v') == 1U); - BOOST_TEST(options.find('v')->second.empty()); - BOOST_TEST(options.count('c')); - BOOST_TEST(options.find('c')->second == "config"); -} - -BOOST_AUTO_TEST_CASE(stop) -{ - const auto [ args, options ] = options::parse({"rm", "-f", "--", "-p"}, "f"); - - BOOST_TEST(args.size() == 2U); - BOOST_TEST(args[0] == "rm"); - BOOST_TEST(args[1] == "-p"); - BOOST_TEST(options.size() == 1U); - BOOST_TEST(options.count('f') == 1U); - BOOST_TEST(options.find('f')->second.empty()); -} - -BOOST_AUTO_TEST_CASE(exclam) -{ - const auto [ args, options ] = options::parse({"-v", "install", "-p"}, "pv!"); - - BOOST_TEST(args.size() == 0U); - BOOST_TEST(options.size() == 1U); - BOOST_TEST(options.count('v') == 1U); - BOOST_TEST(options.find('v')->second.empty()); - BOOST_TEST(options.count('p') == 0U); -} - -BOOST_AUTO_TEST_SUITE(errors) - -BOOST_AUTO_TEST_CASE(invalid_option) -{ - BOOST_REQUIRE_THROW(options::parse({"-x"}, "v"), std::runtime_error); -} - -BOOST_AUTO_TEST_CASE(value_required) -{ - BOOST_REQUIRE_THROW(options::parse({"-c", "-v"}, "vc:"), std::runtime_error); -} - -BOOST_AUTO_TEST_CASE(value_required_detached) -{ - BOOST_REQUIRE_THROW(options::parse({"-v", "-c"}, "vc:"), std::runtime_error); -} - -BOOST_AUTO_TEST_CASE(value_required_adjacent) -{ - BOOST_REQUIRE_THROW(options::parse({"-vc"}, "vc:"), std::runtime_error); -} - -BOOST_AUTO_TEST_SUITE_END()
--- a/cpp/pexec/CMakeLists.txt Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -# -# CMakeLists.txt -- code building for common code -# -# Copyright (c) 2016-2019 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -code_define_module( - NAME pexec - SOURCES pexec.hpp -)
--- a/cpp/pexec/pexec.hpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * pexec.hpp -- wrap an unsafe function and return an optional - * - * Copyright (c) 2016-2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <functional> -#include <optional> - -template <typename Func, typename... Args> -auto pexec(Func&& func, Args&&... args) -{ - using type = std::invoke_result_t<Func, Args...>; - - try { - return std::optional<type>(std::invoke(std::forward<Func>(func), std::forward<Args>(args)...)); - } catch (...) { - return std::optional<type>(); - } -}
--- a/cpp/pexec/test/main.cpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * main.cpp -- test pexec function - * - * Copyright (c) 2016-2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#define BOOST_TEST_MODULE "pexec" -#include <boost/test/unit_test.hpp> - -#include "pexec.hpp" - -namespace { - -int add(int x, int y) -{ - return x + y; -} - -int fail(double) -{ - throw std::runtime_error("failed"); -} - -class math { -public: - int add(int x, int y) const noexcept - { - return x + y; - } - - int fail(double) const - { - throw std::runtime_error("failed"); - } -}; - -BOOST_AUTO_TEST_SUITE(free) - -BOOST_AUTO_TEST_CASE(simple) -{ - BOOST_TEST(pexec(add, 10, 20).value() == 30); -} - -BOOST_AUTO_TEST_CASE(error) -{ - BOOST_TEST(!pexec(fail, 5.5)); -} - -BOOST_AUTO_TEST_SUITE_END() - -BOOST_AUTO_TEST_SUITE(member) - -BOOST_AUTO_TEST_CASE(simple) -{ - math m; - - BOOST_TEST(pexec(&math::add, &m, 10, 20).value() == 30); - BOOST_TEST(pexec(&math::add, std::ref(m), 10, 20).value() == 30); - BOOST_TEST(pexec(&math::add, m, 10, 20).value() == 30); -} - -BOOST_AUTO_TEST_CASE(error) -{ - math m; - - BOOST_TEST(!pexec(&math::fail, &m, 5.5)); - BOOST_TEST(!pexec(&math::fail, std::ref(m), 5.5)); - BOOST_TEST(!pexec(&math::fail, m, 5.5)); -} - -BOOST_AUTO_TEST_SUITE_END() - -} // !namespace
--- a/cpp/to_int/CMakeLists.txt Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -# -# CMakeLists.txt -- code building for common code -# -# Copyright (c) 2017-2019 David Demelier <markand@malikania.fr> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -code_define_module( - NAME to-int - SOURCES to_int.hpp -)
--- a/cpp/to_int/test/main.cpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * main.cpp -- test to_int functions - * - * Copyright (c) 2017-2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#define BOOST_TEST_MODULE "to-int" -#include <boost/test/unit_test.hpp> - -#include "to_int.hpp" - -BOOST_AUTO_TEST_SUITE(valid) - -BOOST_AUTO_TEST_CASE(signed_to_int) -{ - BOOST_TEST(*to_int("10") == 10); - BOOST_TEST(*to_int<std::int8_t>("-10") == -10); - BOOST_TEST(*to_int<std::int8_t>("10") == 10); - BOOST_TEST(*to_int<std::int16_t>("-1000") == -1000); - BOOST_TEST(*to_int<std::int16_t>("1000") == 1000); - BOOST_TEST(*to_int<std::int32_t>("-1000") == -1000); - BOOST_TEST(*to_int<std::int32_t>("1000") == 1000); -} - -BOOST_AUTO_TEST_CASE(signed_to_int64) -{ - BOOST_TEST(*to_int<std::int64_t>("-9223372036854775807") == -9223372036854775807LL); - BOOST_TEST(*to_int<std::int64_t>("9223372036854775807") == 9223372036854775807LL); -} - -BOOST_AUTO_TEST_CASE(unsigned_to_uint) -{ - BOOST_TEST(*to_uint("10") == 10U); - BOOST_TEST(*to_uint<std::uint8_t>("10") == 10U); - BOOST_TEST(*to_uint<std::uint16_t>("1000") == 1000U); - BOOST_TEST(*to_uint<std::uint32_t>("1000") == 1000U); -} - -BOOST_AUTO_TEST_CASE(unsigned_to_uint64) -{ - BOOST_TEST(*to_uint<std::uint64_t>("18446744073709551615") == 18446744073709551615ULL); -} - -BOOST_AUTO_TEST_SUITE_END() - -BOOST_AUTO_TEST_SUITE(errors) - -BOOST_AUTO_TEST_CASE(invalid_argument) -{ - BOOST_TEST(!to_int("plopation")); - BOOST_TEST(!to_uint("plopation")); -} - -BOOST_AUTO_TEST_CASE(out_of_range) -{ - BOOST_TEST(!to_int<std::int8_t>("1000")); - BOOST_TEST(!to_int<std::int8_t>("-1000")); - BOOST_TEST(!to_uint<std::uint8_t>("1000")); - BOOST_TEST(!to_uint<std::uint8_t>("-1000")); -} - -BOOST_AUTO_TEST_SUITE_END()
--- a/cpp/to_int/to_int.hpp Sat Oct 03 16:20:03 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * to_int.hpp -- safely convert string to integers - * - * Copyright (c) 2017-2019 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef TO_INT_HPP -#define TO_INT_HPP - -/** - * \file to_int.hpp - * \brief Safely convert string to integers. - */ - -#include <cstdlib> -#include <limits> -#include <optional> -#include <string> -#include <type_traits> - -/** - * Convert the given string into a signed integer. - * - * \param str the string to convert - * \param min the minimum value allowed - * \param max the maximum value allowed - * \return the value or std::none if not convertible - */ -template <typename T = int> -auto to_int(const std::string& str, - T min = std::numeric_limits<T>::min(), - T max = std::numeric_limits<T>::max()) noexcept -> std::optional<T> -{ - static_assert(std::is_signed<T>::value, "must be signed"); - - char* end; - auto v = std::strtoll(str.c_str(), &end, 10); - - if (*end != '\0' || v < min || v > max) - return std::nullopt; - - return static_cast<T>(v); -} - -/** - * Convert the given string into a unsigned integer. - * - * \note invalid numbers are valid as well - * \param str the string to convert - * \param min the minimum value allowed - * \param max the maximum value allowed - * \return the value or std::none if not convertible - */ -template <typename T = unsigned> -auto to_uint(const std::string& str, - T min = std::numeric_limits<T>::min(), - T max = std::numeric_limits<T>::max()) noexcept -> std::optional<T> -{ - static_assert(std::is_unsigned<T>::value, "must be unsigned"); - - char* end; - auto v = std::strtoull(str.c_str(), &end, 10); - - if (*end != '\0' || v < min || v > max) - return std::nullopt; - - return static_cast<T>(v); -} - -#endif // !TO_INT_HPP