| @@ -0,0 +1 @@ | |||
| build/ | |||
| @@ -0,0 +1,3 @@ | |||
| [submodule "cmake/modules"] | |||
| path = cmake/modules | |||
| url = b3rgmann@git.bergmann89.de:cpp/CmakeModules.git | |||
| @@ -0,0 +1,53 @@ | |||
| # Initialize CMake ################################################################################ | |||
| CMake_Minimum_Required ( VERSION 3.12.0 FATAL_ERROR ) | |||
| # Set CMAKE_BUILD_TYPE | |||
| If ( NOT CMAKE_BUILD_TYPE ) | |||
| Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE ) | |||
| EndIf ( NOT CMAKE_BUILD_TYPE ) | |||
| Set_Property ( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel ) | |||
| # Set CMAKE_MODULE_PATH | |||
| If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) | |||
| Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} | |||
| "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) | |||
| EndIf ( ) | |||
| If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) | |||
| Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} | |||
| "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) | |||
| EndIf ( ) | |||
| # Project ######################################################################################### | |||
| Include ( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppcore-var.cmake" ) | |||
| Project ( cppcore | |||
| DESCRIPTION "A simple library" | |||
| VERSION "${CPPCORE_VERSION}" ) | |||
| Include ( CTest ) | |||
| Include ( GNUInstallDirs ) | |||
| # Subdirectories | |||
| Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) | |||
| Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test ) | |||
| # Install | |||
| Include ( CMakePackageConfigHelpers ) | |||
| Write_Basic_Package_Version_File ( "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppcore-config-version.cmake" | |||
| VERSION ${CPPCORE_VERSION} | |||
| COMPATIBILITY AnyNewerVersion ) | |||
| Configure_File ( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppcore-config.cmake" | |||
| "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppcore-config.cmake" | |||
| @ONLY ) | |||
| Set ( ConfigPackageLocation "${CPPCORE_INSTALL_DIR_SHARE}/cmake" ) | |||
| Install ( EXPORT cppcore | |||
| NAMESPACE cppcore:: | |||
| DESTINATION ${ConfigPackageLocation} ) | |||
| Install ( FILES | |||
| "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppcore-config.cmake" | |||
| "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppcore-config-version.cmake" | |||
| DESTINATION | |||
| ${ConfigPackageLocation} | |||
| COMPONENT | |||
| Devel ) | |||
| @@ -0,0 +1,4 @@ | |||
| # cppcore-config.cmake - package configuration file | |||
| Get_Filename_Component ( CURRENT_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH ) | |||
| Include ( ${CURRENT_DIR}/cppcore.cmake ) | |||
| @@ -0,0 +1,20 @@ | |||
| # Version | |||
| Set ( CPPCORE_VERSION_MAJOR 1 ) | |||
| Set ( CPPCORE_VERSION_MINOR 0 ) | |||
| Set ( CPPCORE_VERSION_PATCH 0 ) | |||
| Set ( CPPCORE_VERSION_BUILD 0 ) | |||
| Set ( CPPCORE_VERSION_SHORT "${CPPCORE_VERSION_MAJOR}.${CPPCORE_VERSION_MINOR}" ) | |||
| Set ( CPPCORE_VERSION "${CPPCORE_VERSION_SHORT}.${CPPCORE_VERSION_PATCH}.${CPPCORE_VERSION_BUILD}" ) | |||
| Set ( CPPCORE_NAME "cppcore-${CPPCORE_VERSION_SHORT}" ) | |||
| Set ( CPPCORE_OUTPUTNAME "helloworld" ) | |||
| # Install directories | |||
| Set ( CPPCORE_INSTALL_DIR_INCLUDE "include/${CPPCORE_NAME}" ) | |||
| Set ( CPPCORE_INSTALL_DIR_LIB "lib" ) | |||
| Set ( CPPCORE_INSTALL_DIR_SHARE "share/${CPPCORE_NAME}" ) | |||
| # C Standard | |||
| Set ( CMAKE_C_STANDARD 11 ) | |||
| Set ( CMAKE_CXX_STANDARD 17 ) | |||
| Set ( CMAKE_C_STANDARD_REQUIRED ON ) | |||
| Set ( CMAKE_CXX_STANDARD_REQUIRED ON ) | |||
| @@ -0,0 +1 @@ | |||
| Subproject commit 1a32531aef2deeebd5637b1873bc4e976628801c | |||
| @@ -0,0 +1,6 @@ | |||
| #pragma once | |||
| #include <cppcore/conversion.h> | |||
| #include <cppcore/define.h> | |||
| #include <cppcore/misc.h> | |||
| #include <cppcore/threading.h> | |||
| @@ -0,0 +1,6 @@ | |||
| #pragma once | |||
| #include <cppcore/conversion/byteorder.h> | |||
| #include <cppcore/conversion/enum.h> | |||
| #include <cppcore/conversion/string.h> | |||
| #include <cppcore/conversion/time.h> | |||
| @@ -0,0 +1,107 @@ | |||
| #pragma once | |||
| #if defined(__linux__) | |||
| #include <endian.h> | |||
| #elif defined(__FreeBSD__) || defined(__NetBSD__) | |||
| #include <sys/endian.h> | |||
| #elif defined(__OpenBSD__) | |||
| #include <sys/types.h> | |||
| #define be16toh(x) betoh16(x) | |||
| #define be32toh(x) betoh32(x) | |||
| #define be64toh(x) betoh64(x) | |||
| #endif | |||
| namespace cppcore | |||
| { | |||
| namespace __impl | |||
| { | |||
| /** | |||
| * @brief Helper class to convert byte order. | |||
| */ | |||
| template<class T, size_t N = sizeof(T)> | |||
| struct byteorder_convert_helper; | |||
| /** | |||
| * @brief Trait class for byteorder conversions. | |||
| */ | |||
| struct byteorder_traits | |||
| { | |||
| template<typename T> | |||
| using convert_helper = byteorder_convert_helper<T>; | |||
| }; | |||
| } | |||
| /** | |||
| * @brief Convert the byte order of a any type from host byte order to network byte order. | |||
| * | |||
| * @tparam T Type to convert. | |||
| * @tparam T_traits Trait class to store needed types and helpers. | |||
| * | |||
| * @param[in] value Value to convert. | |||
| * | |||
| * @return Converted value. | |||
| */ | |||
| template<class T, typename T_traits = __impl::byteorder_traits> | |||
| constexpr decltype(auto) hton(const T& value); | |||
| /** | |||
| * @brief Convert the byte order of a any type from network byte order to host byte order. | |||
| * | |||
| * @tparam T Type to convert. | |||
| * @tparam T_traits Trait class to store needed types and helpers. | |||
| * | |||
| * @param[in] value Value to convert. | |||
| * | |||
| * @return Converted value. | |||
| */ | |||
| template<class T, typename T_traits = __impl::byteorder_traits> | |||
| constexpr decltype(auto) ntoh(const T& value); | |||
| /** | |||
| * @brief Class to convert byte order of any type. | |||
| * | |||
| * @tparam T_traits Trait class to store needed types and helpers. | |||
| */ | |||
| template<typename T_traits> | |||
| struct byteorder_t | |||
| { | |||
| using traits_type = T_traits; | |||
| /** | |||
| * @brief Convert the byte order of a any type from host byte order to network byte order. | |||
| * | |||
| * @tparam T Type to convert. | |||
| * | |||
| * @param[in] value Value to convert. | |||
| * | |||
| * @return Converted value. | |||
| */ | |||
| template<class T> | |||
| static constexpr decltype(auto) hton(const T& value); | |||
| /** | |||
| * @brief Convert the byte order of a any type from network byte order to host byte order. | |||
| * | |||
| * @tparam T Type to convert. | |||
| * | |||
| * @param[in] value Value to convert. | |||
| * | |||
| * @return Converted value. | |||
| */ | |||
| template<class T> | |||
| static constexpr decltype(auto) ntoh(const T& value); | |||
| }; | |||
| /** | |||
| * @brief Byte order helper class with default traits. | |||
| */ | |||
| struct byteorder | |||
| : public byteorder_t<__impl::byteorder_traits> | |||
| { }; | |||
| } | |||
| #include "byteorder.inl" | |||
| @@ -0,0 +1,87 @@ | |||
| #pragma once | |||
| #include "byteorder.h" | |||
| namespace cppcore | |||
| { | |||
| /* static */ | |||
| template<class T, typename T_traits> | |||
| constexpr decltype(auto) hton(const T& value) | |||
| { return byteorder_t<T_traits>::template hton<T>(value); } | |||
| template<class T, typename T_traits> | |||
| constexpr decltype(auto) ntoh(const T& value) | |||
| { return byteorder_t<T_traits>::template ntoh<T>(value); } | |||
| /* byteorder */ | |||
| template<typename T_traits> | |||
| template<class T> | |||
| constexpr decltype(auto) byteorder_t<T_traits> | |||
| ::hton(const T& value) | |||
| { return traits_type::template convert_helper<T>::hton(value); } | |||
| template<typename T_traits> | |||
| template<class T> | |||
| constexpr decltype(auto) byteorder_t<T_traits> | |||
| ::ntoh(const T& value) | |||
| { return traits_type::template convert_helper<T>::ntoh(value); } | |||
| namespace __impl | |||
| { | |||
| /** | |||
| * @brief Helper class to convert type of size with 1 byte. | |||
| */ | |||
| template<class T> | |||
| struct byteorder_convert_helper<T, 1> | |||
| { | |||
| static inline T hton(const T& t) | |||
| { return t; } | |||
| static inline T ntoh(const T& t) | |||
| { return t; } | |||
| }; | |||
| /** | |||
| * @brief Helper class to convert type of size with 2 byte. | |||
| */ | |||
| template<class T> | |||
| struct byteorder_convert_helper<T, 2> | |||
| { | |||
| static inline T hton(const T& t) | |||
| { return reinterpret_cast<T>(htobe16(reinterpret_cast<uint16_t>(t))); } | |||
| static inline T ntoh(const T& t) | |||
| { return reinterpret_cast<T>(be16toh(reinterpret_cast<uint16_t>(t))); } | |||
| }; | |||
| /** | |||
| * @brief Helper class to convert type of size with 4 byte. | |||
| */ | |||
| template<class T> | |||
| struct byteorder_convert_helper<T, 4> | |||
| { | |||
| static inline T hton(const T& t) | |||
| { return reinterpret_cast<T>(htobe32(reinterpret_cast<uint32_t>(t))); } | |||
| static inline T ntoh(const T& t) | |||
| { return reinterpret_cast<T>(be32toh(reinterpret_cast<uint32_t>(t))); } | |||
| }; | |||
| /** | |||
| * @brief Helper class to convert type of size with 8 byte. | |||
| */ | |||
| template<class T> | |||
| struct byteorder_convert_helper<T, 8> | |||
| { | |||
| static inline T hton(const T& t) | |||
| { return reinterpret_cast<T>(htobe64(reinterpret_cast<uint64_t>(t))); } | |||
| static inline T ntoh(const T& t) | |||
| { return reinterpret_cast<T>(be64toh(reinterpret_cast<uint64_t>(t))); } | |||
| }; | |||
| } | |||
| } | |||
| @@ -0,0 +1,166 @@ | |||
| #pragma once | |||
| #include <map> | |||
| #include <vector> | |||
| #include <cppcore/misc/compare.h> | |||
| #include <cppcore/misc/exception.h> | |||
| #include <cppcore/misc/type_helper.h> | |||
| // #include <cppcore/conversion/string.h> | |||
| #define cppcore_define_enum_value_traits(enum, ...) \ | |||
| namespace cppcore { \ | |||
| namespace __impl { \ | |||
| template<> \ | |||
| struct enum_value_traits<enum> \ | |||
| { \ | |||
| using enum_type = enum; \ | |||
| using enum_value_pair_type = std::pair<enum_type, std::string>; \ | |||
| using enum_value_vector_type = std::vector<enum_value_pair_type>; \ | |||
| \ | |||
| static decltype(auto) get_enum_values() \ | |||
| { \ | |||
| static const enum_value_vector_type value({ \ | |||
| __VA_ARGS__ \ | |||
| }); \ | |||
| return value; \ | |||
| } \ | |||
| }; } } | |||
| namespace cppcore | |||
| { | |||
| namespace __impl | |||
| { | |||
| /** | |||
| * @brief Traits class to strore enum to string pairs and the needed data types. | |||
| * | |||
| * @tparam T_enum Enum type. | |||
| */ | |||
| template<typename T_enum> | |||
| struct enum_value_traits | |||
| { | |||
| using enum_type = T_enum; | |||
| using enum_value_pair_type = std::pair<enum_type, std::string>; | |||
| using enum_value_vector_type = std::vector<enum_value_pair_type>; | |||
| /** | |||
| * @brief Returns a vector with all enum to string value paris. | |||
| */ | |||
| static decltype(auto) get_enum_values(); | |||
| }; | |||
| /** | |||
| * @brief Traits class for enum conersions to store the needed types and data. | |||
| * | |||
| * @tparam T_enum Enum type. | |||
| * @tparam T_traits Traits that stores a list with all enum to string values pairs. | |||
| */ | |||
| template< | |||
| typename T_enum, | |||
| typename T_traits = enum_value_traits<T_enum>> | |||
| struct enum_conversion_traits | |||
| { | |||
| public: | |||
| using enum_type = T_enum; | |||
| using traits_type = enum_value_traits<enum_type>; | |||
| using enum_to_string_map_type = std::map<enum_type, std::string>; | |||
| using string_to_enum_map_type = std::map<std::string, enum_type, op_less_invariant_string>; | |||
| /** | |||
| * @brief Returns a map with enum to string values. | |||
| */ | |||
| static inline decltype(auto) get_enum_to_string_map(); | |||
| /** | |||
| * @brief Returns a map with string to enum values. | |||
| */ | |||
| static inline decltype(auto) get_string_to_enum_map(); | |||
| private: | |||
| /** | |||
| * @brief Helper method to create the enum to string map. | |||
| */ | |||
| static inline decltype(auto) create_enum_to_string_map(); | |||
| /** | |||
| * @brief Helper method to create the string to enum map. | |||
| */ | |||
| static inline decltype(auto) create_string_to_enum_map(); | |||
| }; | |||
| } | |||
| /** | |||
| * @brief Class to convert enum values to and from string. | |||
| * | |||
| * @tparam T_enum Enum type. | |||
| * @tparam T_traits Traits type that stores the enum to value and the value to enum maps. | |||
| */ | |||
| template< | |||
| typename T_enum, | |||
| typename T_traits = __impl::enum_conversion_traits<T_enum>> | |||
| struct enum_conversion | |||
| { | |||
| using enum_type = T_enum; | |||
| using base_type = typename std::underlying_type<enum_type>::type; | |||
| using traits_type = T_traits; | |||
| /** | |||
| * @brief Convert the given enum value to a string. | |||
| * | |||
| * @param[in] value Enum value to convert to string. | |||
| * @param[in] add_numeric_value Append the numeric value to the converted enum value. | |||
| * | |||
| * @return Enum converted to string. | |||
| */ | |||
| static inline std::string to_string( | |||
| enum_type value, | |||
| bool add_numeric_value = false); | |||
| /** | |||
| * @brief Convert the given string to the enum value. | |||
| * | |||
| * @param[in] str String to convert to enum value. | |||
| * @param[out] value Value to store converted | |||
| * @param[in] accept_numeric_value Accept numeric values. | |||
| * | |||
| * @retval true If the conversion was successfull. | |||
| * @retval false If the string could not be converted. | |||
| */ | |||
| static inline bool try_to_enum( | |||
| const std::string& str, | |||
| enum_type& value, | |||
| bool accept_numeric_value = true); | |||
| /** | |||
| * @brief Convert the given string to the enum value. Throws an exception if the conversion failed. | |||
| * | |||
| * @param[in] str String to convert to enum value. | |||
| * @param[in] accept_numeric_value Accept numeric values. | |||
| * | |||
| * @return Enum value. | |||
| */ | |||
| static inline enum_type to_enum( | |||
| const std::string& str, | |||
| bool accept_numeric_value = true); | |||
| /** | |||
| * @brief Convert the given string to the enum value. Returns the passed default value if the conversion failed. | |||
| * | |||
| * @param[in] str String to convert to enum value. | |||
| * @param[in] default_value Default value to pass if the conversion failed. | |||
| * @param[in] accept_numeric_value Accept numeric values. | |||
| * | |||
| * @return Enum value. | |||
| */ | |||
| static inline enum_type to_enum_default( | |||
| const std::string& str, | |||
| enum_type default_value, | |||
| bool accept_numeric_value = true); | |||
| }; | |||
| } | |||
| #include "enum.inl" | |||
| @@ -0,0 +1,117 @@ | |||
| #pragma once | |||
| #include "enum.h" | |||
| namespace cppcore | |||
| { | |||
| namespace __impl | |||
| { | |||
| /* enum_conversion_traits */ | |||
| template<typename T_enum, typename T_traits> | |||
| decltype(auto) enum_conversion_traits<T_enum, T_traits> | |||
| ::get_enum_to_string_map() | |||
| { | |||
| static const auto value = create_enum_to_string_map(); | |||
| return value; | |||
| } | |||
| template<typename T_enum, typename T_traits> | |||
| decltype(auto) enum_conversion_traits<T_enum, T_traits> | |||
| ::get_string_to_enum_map() | |||
| { | |||
| static const auto value = create_string_to_enum_map(); | |||
| return value; | |||
| } | |||
| template<typename T_enum, typename T_traits> | |||
| decltype(auto) enum_conversion_traits<T_enum, T_traits> | |||
| ::create_enum_to_string_map() | |||
| { | |||
| auto& values = traits_type::get_enum_values(); | |||
| enum_to_string_map_type ret; | |||
| for (auto& p : values) | |||
| { | |||
| ret.emplace(p.first, p.second); | |||
| } | |||
| return ret; | |||
| } | |||
| template<typename T_enum, typename T_traits> | |||
| decltype(auto) enum_conversion_traits<T_enum, T_traits> | |||
| ::create_string_to_enum_map() | |||
| { | |||
| auto& values = traits_type::get_enum_values(); | |||
| string_to_enum_map_type ret; | |||
| for (auto& p : values) | |||
| { | |||
| ret.emplace(p.second, p.first); | |||
| } | |||
| return ret; | |||
| } | |||
| } | |||
| /* enum_conversion */ | |||
| template<typename T_enum, typename T_traits> | |||
| std::string enum_conversion<T_enum, T_traits> | |||
| ::to_string(enum_type value, bool add_numeric_value) | |||
| { | |||
| std::string ret; | |||
| auto& map = traits_type::get_enum_to_string_map(); | |||
| auto it = map.find(value); | |||
| if (it != map.end()) | |||
| { | |||
| ret = it->second; | |||
| if (add_numeric_value) | |||
| ret += '(' + std::to_string(static_cast<base_type>(value)) + ')'; // TODO | |||
| } | |||
| else | |||
| ret = std::to_string(static_cast<base_type>(value)); // TODO | |||
| return ret; | |||
| } | |||
| template<typename T_enum, typename T_traits> | |||
| bool enum_conversion<T_enum, T_traits> | |||
| ::try_to_enum(const std::string& str, enum_type& value, bool accept_numeric_value) | |||
| { | |||
| static const auto& map = traits_type::get_string_to_enum_map(); | |||
| auto it = map.find(str); | |||
| if (it != map.end()) | |||
| { | |||
| value = it->second; | |||
| return true; | |||
| } | |||
| if (!accept_numeric_value) | |||
| return false; | |||
| char *e = nullptr; | |||
| const char *c = str.c_str(); | |||
| value = static_cast<enum_type>(std::strtoull(c, &e, 0)); | |||
| return (c != e); | |||
| } | |||
| template<typename T_enum, typename T_traits> | |||
| T_enum enum_conversion<T_enum, T_traits> | |||
| ::to_enum(const std::string& str, bool accept_numeric_value) | |||
| { | |||
| using namespace ::std; | |||
| enum_type value; | |||
| if (!try_to_enum(str, value, accept_numeric_value)) | |||
| throw convert_exception("unable to convert '"s + str + "' to '"s + type_helper<enum_type>::name() + "'"s); | |||
| return value; | |||
| } | |||
| template<typename T_enum, typename T_traits> | |||
| T_enum enum_conversion<T_enum, T_traits> | |||
| ::to_enum_default(const std::string& str, enum_type default_value, bool accept_numeric_value) | |||
| { | |||
| enum_type value; | |||
| return try_to_enum(str, value, accept_numeric_value) | |||
| ? value | |||
| : default_value; | |||
| } | |||
| } | |||
| @@ -0,0 +1,223 @@ | |||
| #pragma once | |||
| #include <string> | |||
| #include <iostream> | |||
| namespace cppcore | |||
| { | |||
| namespace __impl | |||
| { | |||
| /** | |||
| * @brief Predicate class to convert any type to a string using a stream. | |||
| */ | |||
| template<typename T, typename Enable = void> | |||
| struct op_to_stream; | |||
| /** | |||
| * @brief Predicate class to convert any type to a string. | |||
| */ | |||
| template<typename T, typename Enable = void> | |||
| struct op_to_string; | |||
| /** | |||
| * @brief Predicate class to convert a string to any type. | |||
| */ | |||
| template<typename T, typename Enable = void> | |||
| struct op_from_string; | |||
| /** | |||
| * @brief Traits class to store needed data types. | |||
| */ | |||
| struct string_conversion_traits | |||
| { | |||
| template<typename T> | |||
| using to_stream_predicate_type = op_to_stream<T>; | |||
| template<typename T> | |||
| using to_string_predicate_type = op_to_string<T>; | |||
| template<typename T> | |||
| using from_string_predicate_type = op_from_string<T>; | |||
| }; | |||
| } | |||
| /** | |||
| * @brief Convert the passed value to string. | |||
| * | |||
| * @tparam T Type of the passed value. | |||
| * @tparam T_traits Traits type to use for conversion. | |||
| * | |||
| * @param[in] value Value to convert to string. | |||
| * | |||
| * @return Converted value. | |||
| */ | |||
| template<typename T, typename T_traits = __impl::string_conversion_traits> | |||
| inline std::string to_string(const T& value); | |||
| /** | |||
| * @brief Write the passed value as string representation to a stream. | |||
| * | |||
| * @tparam T Type of the passed value. | |||
| * @tparam T_traits Traits type to use for conversion. | |||
| * | |||
| * @param[in] value Value to convert to write to stream. | |||
| */ | |||
| template<typename T, typename T_traits = __impl::string_conversion_traits> | |||
| inline void to_string(std::ostream& os, const T& value); | |||
| /** | |||
| * @brief Try to convert the given string to the passed value. | |||
| * | |||
| * @tparam T Type of the value to convert the stirng to. | |||
| * @tparam T_traits Traits type to use for conversion. | |||
| * | |||
| * @param[in] s String to convert to value. | |||
| * @param[out] value Parameter to store vconverted value in. | |||
| * | |||
| * @retval true If the conversion was successful. | |||
| * @retval false If the conversion failed. | |||
| */ | |||
| template<typename T, typename T_traits = __impl::string_conversion_traits> | |||
| inline bool try_from_string(const std::string& s, T& value); | |||
| /** | |||
| * @brief Try to convert the given string to the passed type. Throws exception if conversion was failed. | |||
| * | |||
| * @tparam T Type of the value to convert the stirng to. | |||
| * @tparam T_traits Traits type to use for conversion. | |||
| * | |||
| * @param[in] s String to convert to value. | |||
| * | |||
| * @return Converted value. | |||
| */ | |||
| template<typename T, typename T_traits = __impl::string_conversion_traits> | |||
| inline T from_string(const std::string& s); | |||
| /** | |||
| * @brief Try to convert the given string to the passed type. Returns the passed default value if conversion was failed. | |||
| * | |||
| * @tparam T Type of the value to convert the stirng to. | |||
| * @tparam T_traits Traits type to use for conversion. | |||
| * | |||
| * @param[in] s String to convert to value. | |||
| * @param[in] default_value Default value to return if the conversion failed. | |||
| * | |||
| * @return Converted value. | |||
| */ | |||
| template<typename T, typename T_traits = __impl::string_conversion_traits> | |||
| inline T from_string_default(const std::string& s, const T& default_value); | |||
| /** | |||
| * @brief Split string at the passed seperator and calls the passed predicate for each element. | |||
| * | |||
| * @tparam T_predicate Type of predicate to execute for each element. | |||
| * | |||
| * @param s String to split. | |||
| * @param seperator Seperator to split string at. | |||
| * @param predicate Predicate to execute for each element. | |||
| * | |||
| * @return Value returned from the predicate. | |||
| */ | |||
| template<typename T_predicate> | |||
| inline bool string_split(const std::string& s, char seperator, const T_predicate& predicate); | |||
| /** | |||
| * @brief Class to handle string conversions. | |||
| * | |||
| * @tparam T_traits Traits to use for converting. | |||
| */ | |||
| template<typename T_traits> | |||
| struct string_conversion_t | |||
| { | |||
| using traits_type = T_traits; | |||
| /** | |||
| * @brief Convert the passed value to string. | |||
| * | |||
| * @tparam T Type of the passed value. | |||
| * | |||
| * @param[in] value Value to convert to string. | |||
| * | |||
| * @return Converted value. | |||
| */ | |||
| template<typename T> | |||
| static inline std::string to_string(const T& value); | |||
| /** | |||
| * @brief Write the passed value as string representation to a stream. | |||
| * | |||
| * @tparam T Type of the passed value. | |||
| * | |||
| * @param[in] value Value to convert to write to stream. | |||
| */ | |||
| template<typename T> | |||
| static inline void to_string(std::ostream& os, const T& value); | |||
| /** | |||
| * @brief Try to convert the given string to the passed value. | |||
| * | |||
| * @tparam T Type of the value to convert the stirng to. | |||
| * | |||
| * @param[in] s String to convert to value. | |||
| * @param[out] value Parameter to store vconverted value in. | |||
| * | |||
| * @retval true If the conversion was successful. | |||
| * @retval false If the conversion failed. | |||
| */ | |||
| template<typename T> | |||
| static inline bool try_from_string(const std::string& s, T& value); | |||
| /** | |||
| * @brief Try to convert the given string to the passed type. Throws exception if conversion was failed. | |||
| * | |||
| * @tparam T Type of the value to convert the stirng to. | |||
| * | |||
| * @param[in] s String to convert to value. | |||
| * | |||
| * @return Converted value. | |||
| */ | |||
| template<typename T> | |||
| static inline T from_string(const std::string& s); | |||
| /** | |||
| * @brief Try to convert the given string to the passed type. Returns the passed default value if conversion was failed. | |||
| * | |||
| * @tparam T Type of the value to convert the stirng to. | |||
| * | |||
| * @param[in] s String to convert to value. | |||
| * @param[in] default_value Default value to return if the conversion failed. | |||
| * | |||
| * @return Converted value. | |||
| */ | |||
| template<typename T> | |||
| static inline T from_string_default(const std::string& s, const T& default_value); | |||
| }; | |||
| /** | |||
| * @brief String conversion class with default traits. | |||
| */ | |||
| struct string_conversion | |||
| : public string_conversion_t<__impl::string_conversion_traits> | |||
| { }; | |||
| } | |||
| namespace std | |||
| { | |||
| /** | |||
| * @brief Operator overload to write value to stream that supports the to_string method, with stream parameter. | |||
| */ | |||
| template<typename T_char, typename T_traits, typename X> | |||
| inline auto operator<<(basic_ostream<T_char, T_traits>& os, X&& x) | |||
| -> decltype( | |||
| std::forward<X>(x).to_string(std::declval<basic_ostream<T_char, T_traits>&>()), | |||
| std::declval<basic_ostream<T_char, T_traits>&>()); | |||
| } | |||
| #include "string.inl" | |||
| @@ -0,0 +1,422 @@ | |||
| #pragma once | |||
| #include <cppcore/misc/exception.h> | |||
| #include <cppcore/misc/type_helper.h> | |||
| #include "enum.h" | |||
| #include "string.h" | |||
| #ifdef _GLIBCXX_VECTOR | |||
| #define CPPCORE_HAS_VECTOR | |||
| #endif | |||
| #ifdef _GLIBCXX_LIST | |||
| #define CPPCORE_HAS_LIST | |||
| #endif | |||
| namespace cppcore | |||
| { | |||
| /* global */ | |||
| template<typename T, typename T_traits> | |||
| inline std::string to_string(const T& value) | |||
| { return string_conversion_t<T_traits>::template to_string<T>(value); } | |||
| template<typename T, typename T_traits> | |||
| inline void to_string(std::ostream& os, const T& value) | |||
| { string_conversion_t<T_traits>::template to_string<T>(os, value); } | |||
| template<typename T, typename T_traits> | |||
| inline bool try_from_string(const std::string& s, T& value) | |||
| { return string_conversion_t<T_traits>::template try_from_string<T>(s, value); } | |||
| template<typename T, typename T_traits> | |||
| inline T from_string(const std::string& s) | |||
| { return string_conversion_t<T_traits>::template from_string<T>(s); } | |||
| template<typename T, typename T_traits> | |||
| inline T from_string_default(const std::string& s, const T& default_value) | |||
| { return string_conversion_t<T_traits>::template from_string_default<T>(s, default_value); } | |||
| template<typename T_predicate> | |||
| inline bool string_split(const std::string& str, char seperator, T_predicate&& predicate) | |||
| { | |||
| auto* i = str.c_str(); | |||
| auto* e = str.c_str() + str.size(); | |||
| auto* s = i; | |||
| while (i <= e) | |||
| { | |||
| if ( s != e | |||
| && ( *i == seperator | |||
| || *i == '\0')) | |||
| { | |||
| std::string tmp(s, static_cast<size_t>(i - s)); | |||
| if (!predicate(tmp)) | |||
| return false; | |||
| s = i + 1; | |||
| } | |||
| ++i; | |||
| } | |||
| return true; | |||
| } | |||
| /* string_conversion */ | |||
| template<typename T_traits> | |||
| template<typename T> | |||
| inline std::string string_conversion_t<T_traits> | |||
| ::to_string(const T& value) | |||
| { | |||
| using predicate_type = typename traits_type::template to_string_predicate_type<T>; | |||
| return predicate_type { } (value); | |||
| } | |||
| template<typename T_traits> | |||
| template<typename T> | |||
| inline void string_conversion_t<T_traits> | |||
| ::to_string(std::ostream& os, const T& value) | |||
| { | |||
| using predicate_type = typename traits_type::template to_stream_predicate_type<T>; | |||
| predicate_type { } (os, value); | |||
| } | |||
| template<typename T_traits> | |||
| template<typename T> | |||
| inline bool string_conversion_t<T_traits> | |||
| ::try_from_string(const std::string& s, T& value) | |||
| { | |||
| using predicate_type = typename traits_type::template from_string_predicate_type<T>; | |||
| return predicate_type { } (s, value); | |||
| } | |||
| template<typename T_traits> | |||
| template<typename T> | |||
| inline T string_conversion_t<T_traits> | |||
| ::from_string(const std::string& s) | |||
| { | |||
| using namespace ::std; | |||
| T ret; | |||
| if (!try_from_string(s, ret)) | |||
| throw convert_exception("unable to convert '"s + s + "' to '"s + type_helper<T>::name() + "'"s); | |||
| return ret; | |||
| } | |||
| template<typename T_traits> | |||
| template<typename T> | |||
| inline T string_conversion_t<T_traits> | |||
| ::from_string_default(const std::string& s, const T& default_value) | |||
| { | |||
| T ret; | |||
| return try_from_string(s, ret) | |||
| ? ret | |||
| : default_value; | |||
| } | |||
| namespace __impl | |||
| { | |||
| /* op_to_string */ | |||
| template<typename T, typename Enable> | |||
| struct op_to_string | |||
| { | |||
| inline std::string operator()(const T& v) const | |||
| { return std::to_string(v); } | |||
| }; | |||
| template<typename T> | |||
| struct op_to_string<T, std::enable_if_t<std::is_enum_v<T>>> | |||
| { | |||
| inline std::string operator()(const T& v) const | |||
| { return enum_conversion<T>::to_string(v); } | |||
| }; | |||
| template<typename T> | |||
| struct op_to_string<T, std::enable_if_t<std::is_floating_point_v<T>>> | |||
| { | |||
| inline std::string operator()(const T& v) const | |||
| { | |||
| std::stringstream os; | |||
| op_to_stream<T> { } (os, v); | |||
| return os.str(); | |||
| } | |||
| }; | |||
| template<> | |||
| struct op_to_string<std::string, void> | |||
| { | |||
| inline std::string operator()(const std::string& v) const | |||
| { return v; } | |||
| }; | |||
| template<typename T, size_t N> | |||
| struct op_to_string<T[N], std::enable_if_t<std::is_same_v<std::decay_t<T>, char>>> | |||
| { | |||
| using value_type = T[N]; | |||
| inline std::string operator()(const value_type& v) const | |||
| { return std::string(v, N-1); } | |||
| }; | |||
| template<typename T> | |||
| struct op_to_string<T, decltype(std::declval<T>().to_string(std::declval<std::ostream&>()), void())> | |||
| { | |||
| inline std::string operator()(const T& v) const | |||
| { | |||
| std::ostringstream os; | |||
| v.to_string(os); | |||
| return os.str(); | |||
| } | |||
| }; | |||
| template<typename T> | |||
| struct op_to_string<T, decltype(std::declval<T>().to_string(), void())> | |||
| { | |||
| inline std::string operator()(const T& v) const | |||
| { return v.to_string(); } | |||
| }; | |||
| #ifdef CPPCORE_HAS_VECTOR | |||
| template<typename T> | |||
| struct op_to_string<std::vector<T>, void> | |||
| { | |||
| inline std::string operator()(const std::vector<T>& v) const | |||
| { | |||
| std::ostringstream os; | |||
| op_to_stream<std::vector<T>> { } (os, v); | |||
| return os.str(); | |||
| } | |||
| }; | |||
| #endif | |||
| #ifdef CPPCORE_HAS_LIST | |||
| template<typename T> | |||
| struct op_to_string<std::list<T>, void> | |||
| { | |||
| inline std::string operator()(const std::list<T>& v) const | |||
| { | |||
| std::ostringstream os; | |||
| op_to_stream<std::list<T>> { } (os, v); | |||
| return os.str(); | |||
| } | |||
| }; | |||
| #endif | |||
| /* op_to_stream */ | |||
| template<typename T, typename Enable> | |||
| struct op_to_stream | |||
| { | |||
| inline void operator()(std::ostream& os, const T& v) const | |||
| { os << v; } | |||
| }; | |||
| template<typename T> | |||
| struct op_to_stream<T, std::enable_if_t<std::is_enum_v<T>>> | |||
| { | |||
| inline void operator()(std::ostream& os, const T& v) const | |||
| { os << enum_conversion<T>::to_string(v); } | |||
| }; | |||
| template<typename T> | |||
| struct op_to_stream<T, decltype(std::declval<T>().to_string(std::declval<std::ostream&>()), void())> | |||
| { | |||
| inline void operator()(std::ostream& os, const T& v) const | |||
| { v.to_string(os); } | |||
| }; | |||
| template<typename T> | |||
| struct op_to_stream<T, decltype(std::declval<T>().to_string(), void())> | |||
| { | |||
| inline void operator()(std::ostream& os, const T& v) const | |||
| { os << v.to_string(); } | |||
| }; | |||
| #ifdef CPPCORE_HAS_VECTOR | |||
| template<typename T> | |||
| struct op_to_stream<std::vector<T>, void> | |||
| { | |||
| inline void operator()(std::ostream& os, const std::vector<T>& v) const | |||
| { | |||
| bool first = true; | |||
| for (auto& x : v) | |||
| { | |||
| if (first) first = false; | |||
| else os << ','; | |||
| to_string(os, x); | |||
| } | |||
| } | |||
| }; | |||
| #endif | |||
| #ifdef CPPCORE_HAS_LIST | |||
| template<typename T> | |||
| struct op_to_stream<std::list<T>, void> | |||
| { | |||
| inline void operator()(std::ostream& os, const std::list<T>& v) const | |||
| { | |||
| bool first = true; | |||
| for (auto& x : v) | |||
| { | |||
| if (first) first = false; | |||
| else os << ','; | |||
| to_string(os, x); | |||
| } | |||
| } | |||
| }; | |||
| #endif | |||
| /* op_from_string */ | |||
| template<typename T, typename Enable> | |||
| struct op_from_string | |||
| { | |||
| inline bool operator()(const std::string& s, T& value) const | |||
| { | |||
| std::istringstream ss(s); | |||
| ss >> value; | |||
| return static_cast<bool>(ss); | |||
| } | |||
| }; | |||
| template<> | |||
| struct op_from_string<std::string, void> | |||
| { | |||
| inline bool operator()(const std::string& s, std::string& value) const | |||
| { | |||
| value = s; | |||
| return true; | |||
| } | |||
| }; | |||
| template<> | |||
| struct op_from_string<const char*, void> | |||
| { | |||
| inline bool operator()(const std::string& s, const char*& value) const | |||
| { | |||
| value = s.c_str(); | |||
| return true; | |||
| } | |||
| }; | |||
| template<> | |||
| struct op_from_string<bool, void> | |||
| { | |||
| inline bool operator()(const std::string& s, bool& value) const | |||
| { | |||
| const std::string TRUE_STR("true"); | |||
| int i; | |||
| value = s == "T" | |||
| || s == "t" | |||
| || std::equal( | |||
| s.begin(), s.end(), | |||
| TRUE_STR.begin(), TRUE_STR.end(), | |||
| [](char a, char b) { | |||
| return tolower(a) == tolower(b); | |||
| }) | |||
| || ( cppcore::try_from_string(s, i) | |||
| && i != 0); | |||
| return true; | |||
| } | |||
| }; | |||
| template<typename T> | |||
| struct op_from_string<T, std::enable_if_t<std::is_enum_v<T>>> | |||
| { | |||
| inline bool operator()(const std::string& s, T& v) const | |||
| { return enum_conversion<T>::try_to_enum(s, v); } | |||
| }; | |||
| template<typename T> | |||
| struct op_from_string<T, decltype(std::declval<T&>().from_string(std::declval<const std::string&>()), void())> | |||
| { | |||
| inline bool operator()(const std::string& s, T& v) const | |||
| { return v.from_string(s); } | |||
| }; | |||
| template<typename T> | |||
| struct op_from_string<T, decltype(T::from_string(std::declval<const std::string&>(), std::declval<T&>()), void())> | |||
| { | |||
| inline bool operator()(const std::string& s, T& v) const | |||
| { return T::from_string(s, v); } | |||
| }; | |||
| template<typename T> | |||
| struct op_from_string<T, typename std::enable_if_t<std::is_integral_v<T>>> | |||
| { | |||
| inline bool operator()(const std::string& s, T& v) const | |||
| { | |||
| char *e = nullptr; | |||
| const char *c = s.c_str(); | |||
| v = static_cast<T>(std::strtoull(c, &e, 0)); | |||
| return (c != e); | |||
| } | |||
| }; | |||
| template<typename T> | |||
| struct op_from_string<T, typename std::enable_if_t<std::is_floating_point_v<T>>> | |||
| { | |||
| inline bool operator()(const std::string& s, T& value) const | |||
| { | |||
| char *e = nullptr; | |||
| const char *c = s.c_str(); | |||
| value = static_cast<T>(std::strtold(c, &e)); | |||
| return (c != e); | |||
| } | |||
| }; | |||
| #ifdef CPPCORE_HAS_VECTOR | |||
| template<typename T> | |||
| struct op_from_string<std::vector<T>, void> | |||
| { | |||
| inline bool operator()(const std::string& str, std::vector<T>& value) const | |||
| { | |||
| std::vector<T> tmp; | |||
| auto ret = string_split(str, ',', [&](const std::string& s) { | |||
| tmp.emplace_back(); | |||
| return try_from_string(s, tmp.back()); | |||
| }); | |||
| if (ret) | |||
| value = std::move(tmp); | |||
| return ret; | |||
| } | |||
| }; | |||
| #endif | |||
| #ifdef CPPCORE_HAS_LIST | |||
| template<typename T> | |||
| struct op_from_string<std::list<T>, void> | |||
| { | |||
| inline bool operator()(const std::string& str, std::list<T>& value) const | |||
| { | |||
| std::list<T> tmp; | |||
| auto ret = string_split(str, ',', [&tmp](auto& s) { | |||
| tmp.emplace_back(); | |||
| return try_from_string(s, tmp.back()); | |||
| }); | |||
| if (ret) | |||
| value = std::move(tmp); | |||
| return ret; | |||
| } | |||
| }; | |||
| #endif | |||
| } | |||
| } | |||
| namespace std | |||
| { | |||
| template<typename T_char, typename T_traits, typename X> | |||
| inline auto operator<<(basic_ostream<T_char, T_traits>& os, X&& x) | |||
| -> decltype( | |||
| std::forward<X>(x).to_string(std::declval<basic_ostream<T_char, T_traits>&>()), | |||
| std::declval<basic_ostream<T_char, T_traits>&>()) | |||
| { | |||
| std::forward<X>(x).to_string(os); | |||
| return os; | |||
| } | |||
| } | |||
| @@ -0,0 +1,65 @@ | |||
| #pragma once | |||
| #include <chrono> | |||
| #include <utility> | |||
| namespace cppcore | |||
| { | |||
| namespace __impl | |||
| { | |||
| /** | |||
| * @brief Helper class to convert time values. | |||
| */ | |||
| template<class From, class To> | |||
| struct op_convert_time; | |||
| } | |||
| /** | |||
| * @brief Cast a chrono duration to a timeval. | |||
| * | |||
| * @param[in] d Chrono duration to cast. | |||
| * | |||
| * @return Casted timeval. | |||
| */ | |||
| template<typename T, typename Rep, typename Period> | |||
| inline auto duration_cast(const std::chrono::duration<Rep, Period>& d) | |||
| -> std::enable_if_t<std::is_same<T, ::timeval>::value, ::timeval>; | |||
| /** | |||
| * @brief Cast a chrono duration to a timespec. | |||
| * | |||
| * @param[in] d Chrono duration to cast. | |||
| * | |||
| * @return Casted timespec. | |||
| */ | |||
| template<typename T, typename Rep, typename Period> | |||
| inline auto duration_cast(const std::chrono::duration<Rep, Period>& d) | |||
| -> std::enable_if_t<std::is_same<T, ::timespec>::value, ::timespec>; | |||
| /** | |||
| * @brief Cast a timeval to a chrono duration. | |||
| * | |||
| * @param[in] tv Timeval to cast to chrono duration. | |||
| * | |||
| * @return Casted chrono duration. | |||
| */ | |||
| template<typename Duration> | |||
| Duration duration_cast(const ::timeval& tv); | |||
| /** | |||
| * @brief Cast a timespec to a chrono duration. | |||
| * | |||
| * @param[in] ts Timespec to cast to chrono duration. | |||
| * | |||
| * @return Casted chrono duration. | |||
| */ | |||
| template<typename Duration> | |||
| Duration duration_cast(const ::timespec& ts); | |||
| } | |||
| #include "time.inl" | |||
| @@ -0,0 +1,83 @@ | |||
| #pragma once | |||
| #include "time.h" | |||
| namespace cppcore | |||
| { | |||
| namespace __impl | |||
| { | |||
| /* op_convert_time */ | |||
| template<typename Rep, typename Period> | |||
| struct op_convert_time<std::chrono::duration<Rep, Period>, ::timeval> | |||
| { | |||
| static ::timeval cast(const std::chrono::duration<Rep, Period>& d) | |||
| { | |||
| ::timeval tv; | |||
| const std::chrono::seconds sec = std::chrono::duration_cast<std::chrono::seconds>(d); | |||
| tv.tv_sec = sec.count(); | |||
| tv.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(d - sec).count(); | |||
| return tv; | |||
| } | |||
| }; | |||
| template<typename Rep, typename Period> | |||
| struct op_convert_time<::timeval, std::chrono::duration<Rep, Period>> | |||
| { | |||
| static std::chrono::duration<Rep, Period> cast(const ::timeval& tv) | |||
| { | |||
| return std::chrono::duration_cast<std::chrono::duration<Rep, Period>>( | |||
| std::chrono::seconds(tv.tv_sec) + std::chrono::microseconds(tv.tv_usec)); | |||
| } | |||
| }; | |||
| template<typename Rep, typename Period> | |||
| struct op_convert_time<std::chrono::duration<Rep, Period>, ::timespec> | |||
| { | |||
| static ::timespec cast(const std::chrono::duration<Rep, Period>& d) | |||
| { | |||
| ::timespec ts; | |||
| const std::chrono::seconds sec = std::chrono::duration_cast<std::chrono::seconds>(d); | |||
| ts.tv_sec = sec.count(); | |||
| ts.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(d - sec).count(); | |||
| return ts; | |||
| } | |||
| }; | |||
| template<typename Rep, typename Period> | |||
| struct op_convert_time<::timespec, std::chrono::duration<Rep, Period>> | |||
| { | |||
| static std::chrono::duration<Rep, Period> cast(const ::timespec& ts) | |||
| { | |||
| return std::chrono::duration_cast<std::chrono::duration<Rep, Period>>( | |||
| std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)); | |||
| } | |||
| }; | |||
| } | |||
| /* global */ | |||
| template<typename T, typename Rep, typename Period> | |||
| inline auto duration_cast(const std::chrono::duration<Rep, Period>& d) | |||
| -> std::enable_if_t<std::is_same<T, ::timeval>::value, ::timeval> | |||
| { return __impl::op_convert_time<std::chrono::duration<Rep, Period>, ::timeval>::cast(d); } | |||
| template<typename T, typename Rep, typename Period> | |||
| inline auto duration_cast(const std::chrono::duration<Rep, Period>& d) | |||
| -> std::enable_if_t<std::is_same<T, ::timespec>::value, ::timespec> | |||
| { return __impl::op_convert_time<std::chrono::duration<Rep, Period>, ::timespec>::cast(d); } | |||
| template<typename Duration> | |||
| Duration duration_cast(const ::timeval& tv) | |||
| { return __impl::op_convert_time<::timeval, Duration>::cast(tv); } | |||
| template<typename Duration> | |||
| Duration duration_cast(const ::timespec& ts) | |||
| { return __impl::op_convert_time<::timespec, Duration>::cast(ts); } | |||
| } | |||
| @@ -0,0 +1,25 @@ | |||
| #pragma once | |||
| #define CPPCORE_BYTE_ORDER_UNKNOWN 0 | |||
| #define CPPCORE_BYTE_ORDER_LITTLE 1 | |||
| #define CPPCORE_BYTE_ORDER_BIG 2 | |||
| #ifdef __BYTE_ORDER__ | |||
| #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | |||
| #define CPPCORE_BYTE_ORDER CPPCORE_BYTE_ORDER_BIG | |||
| #elif __BYTE_ORDER__ == __ORDER_BIG_LITTLE__ | |||
| #define CPPCORE_BYTE_ORDER CPPCORE_BYTE_ORDER_LITTLE | |||
| #endif | |||
| #endif | |||
| #ifdef __BYTE_ORDER | |||
| #if __BYTE_ORDER == __BIG_ENDIAN | |||
| #define CPPCORE_BYTE_ORDER CPPCORE_BYTE_ORDER_BIG | |||
| #elif __BYTE_ORDER == __LITTLE_ENDIAN | |||
| #define CPPCORE_BYTE_ORDER CPPCORE_BYTE_ORDER_LITTLE | |||
| #endif | |||
| #endif | |||
| #ifndef CPPCORE_BYTE_ORDER | |||
| #define CPPCORE_BYTE_ORDER CPPCORE_BYTE_ORDER_UNKNOWN | |||
| #endif | |||
| @@ -0,0 +1,8 @@ | |||
| #pragma once | |||
| #include <cppcore/misc/exception.h> | |||
| #include <cppcore/misc/flags.h> | |||
| #include <cppcore/misc/indent.h> | |||
| #include <cppcore/misc/stream.h> | |||
| #include <cppcore/misc/typehelper.h> | |||
| #include <cppcore/misc/utils.h> | |||
| @@ -0,0 +1,27 @@ | |||
| #pragma once | |||
| #include <string> | |||
| namespace cppcore | |||
| { | |||
| /** | |||
| * @brief Predicate class to caompare to string ignoring the case and variant. | |||
| */ | |||
| struct op_less_invariant_string | |||
| { | |||
| /** | |||
| * @brief Compare to string. | |||
| * | |||
| * @param[in] lhs Left hand value. | |||
| * @param[in] rhs Right hand value. | |||
| * | |||
| * @retval true If lhs is less than rhs. | |||
| * @retval false If rhs is greater or equal lhs. | |||
| */ | |||
| inline bool operator()(const std::string& lhs, const std::string& rhs) const; | |||
| }; | |||
| } | |||
| #include "compare.inl" | |||
| @@ -0,0 +1,29 @@ | |||
| #pragma once | |||
| #include "compare.h" | |||
| namespace cppcore | |||
| { | |||
| /* op_less_invariant_string */ | |||
| bool op_less_invariant_string | |||
| ::operator()(const std::string& lhs, const std::string& rhs) const | |||
| { | |||
| auto c1 = lhs.c_str(); | |||
| auto c2 = rhs.c_str(); | |||
| auto l1 = lhs.size(); | |||
| auto l2 = rhs.size(); | |||
| while (l1 > 0 && l2 > 0 && std::tolower(*c1) == std::tolower(*c2)) | |||
| { | |||
| ++c1; | |||
| ++c2; | |||
| --l1; | |||
| --l2; | |||
| } | |||
| return l1 > 0 && l2 > 0 | |||
| ? std::tolower(*c1) < std::tolower(*c2) | |||
| : l1 < l2; | |||
| } | |||
| } | |||
| @@ -0,0 +1,219 @@ | |||
| #pragma once | |||
| #include <string> | |||
| #include <cstdint> | |||
| #include <iomanip> | |||
| #include <string.h> | |||
| #include <execinfo.h> | |||
| #include "flags.h" | |||
| namespace cppcore | |||
| { | |||
| /** | |||
| * @brief Basic exception with stack trace and some more small features. | |||
| */ | |||
| struct exception | |||
| : public std::exception | |||
| { | |||
| public: | |||
| enum class print_flag | |||
| { | |||
| print_trace, | |||
| resolve_address, | |||
| }; | |||
| using print_flags = shifted_flags<print_flag>; | |||
| public: | |||
| static constexpr size_t max_stack_size = 15; | |||
| /** | |||
| * @brief Get the default print flags. | |||
| */ | |||
| static inline const print_flags& default_print_flag(); | |||
| /** | |||
| * @brief Print the exception to the passed stream; | |||
| * | |||
| * @param[in] os Stream to print exception to. | |||
| * @param[in] ex Exception to print to stream. | |||
| * | |||
| * @return The stream received as parameter (for further processing). | |||
| */ | |||
| inline friend std::ostream& operator <<(std::ostream& os, const exception& ex); | |||
| private: | |||
| mutable bool _msg_cache_empty; //!< Indicates if the message cache was created or not. | |||
| mutable std::string _msg_cache; //!< Caches the message of the exception. | |||
| public: | |||
| std::string message; //!< message of the exception | |||
| void* stack[max_stack_size]; //!< stack trace | |||
| int stack_size; //!< number of entries stored in stack | |||
| public: | |||
| /** | |||
| * @brief Default constructor. | |||
| */ | |||
| inline exception(); | |||
| /** | |||
| * @brief Constructor to create an exception. | |||
| */ | |||
| inline exception(std::string msg); | |||
| /** | |||
| * @brief Destructor. | |||
| */ | |||
| virtual inline ~exception() = default; | |||
| /** | |||
| * @brief Print the whole exception to the passed stream. | |||
| * | |||
| * @param[in] os Stream to print exception to. | |||
| * @param[in] flags Flags to use for printing. | |||
| */ | |||
| inline void print( | |||
| std::ostream& os, | |||
| const print_flags& flags = default_print_flag()) const; | |||
| /** | |||
| * @brief Convert the exception to string. | |||
| * | |||
| * @param[in] flags Flags to use for printing. | |||
| * | |||
| * @return String representation of the exception. | |||
| */ | |||
| inline std::string print( | |||
| const print_flags& flags = default_print_flag()) const; | |||
| /** | |||
| * @brief Convert the exception to a string. | |||
| */ | |||
| inline std::string to_string() const; | |||
| /** | |||
| * @brief Get the message of the exception as c-string. | |||
| */ | |||
| inline const char* what() const throw() override; | |||
| protected: | |||
| /** | |||
| * @brief Print the message of the exception to the passed stream. | |||
| * | |||
| * @param[in] os Stream to print message of the exception to. | |||
| */ | |||
| virtual inline void print_message(std::ostream& os) const; | |||
| }; | |||
| /** | |||
| * @brief Error exception. Wrapps the errors from the operating system. | |||
| */ | |||
| struct error_exception | |||
| : public exception | |||
| { | |||
| public: | |||
| int error; //!< Error received from the operating system | |||
| public: | |||
| /** | |||
| * @brief Constructor to create a error exception. | |||
| * | |||
| * @param[in] e Error code received from the operating system. | |||
| */ | |||
| inline error_exception(int e); | |||
| /** | |||
| * @brief Constructor to create a error exception. | |||
| * | |||
| * @param[in] msg Message of the error exception. | |||
| * @param[in] e Error code received from the operating system. | |||
| */ | |||
| inline error_exception(const std::string& msg, int e); | |||
| }; | |||
| /** | |||
| * @brief Range exception. | |||
| */ | |||
| struct range_exception | |||
| : public exception | |||
| { | |||
| public: | |||
| size_t min; //!< minimum valid value of the range | |||
| size_t max; //!< maximum valid value of the range | |||
| size_t index; //!< actual index that was used | |||
| public: | |||
| /** | |||
| * @brief Constructor to create a range exception. | |||
| */ | |||
| inline range_exception(size_t mi, size_t ma, size_t idx, std::string msg = ""); | |||
| protected: | |||
| /** | |||
| * @brief Print the message of the exception to the passed stream. | |||
| * | |||
| * @param[in] os Stream to print message of the exception to. | |||
| */ | |||
| inline void print_message(std::ostream& os) const override; | |||
| }; | |||
| /** | |||
| * @brief Argument exception. | |||
| */ | |||
| struct argument_exception | |||
| : public exception | |||
| { | |||
| public: | |||
| std::string argument; //!< argument that caused the exception | |||
| public: | |||
| /** | |||
| * @brief Constructor to create the argument exception. | |||
| * | |||
| * @param[in] arg Argument that caused the exception. | |||
| * @param[in] msg Message of the exception. | |||
| */ | |||
| inline argument_exception(std::string arg, std::string msg = ""); | |||
| protected: | |||
| /** | |||
| * @brief Print the message of the exception to the passed stream. | |||
| * | |||
| * @param[in] os Stream to print message of the exception to. | |||
| */ | |||
| inline void print_message(std::ostream& os) const override; | |||
| }; | |||
| /** | |||
| * @brief Invalid operation exception. | |||
| */ | |||
| struct invalid_operation_exception | |||
| : public exception | |||
| { | |||
| using exception::exception; | |||
| }; | |||
| /** | |||
| * @brief Convert exception. | |||
| */ | |||
| struct convert_exception | |||
| : public exception | |||
| { | |||
| using exception::exception; | |||
| }; | |||
| } | |||
| #include "exception.inl" | |||
| @@ -0,0 +1,124 @@ | |||
| #pragma once | |||
| #include "exception.h" | |||
| namespace cppcore | |||
| { | |||
| /* exception */ | |||
| const exception::print_flags& exception::default_print_flag() | |||
| { | |||
| static const print_flags value({ | |||
| print_flag::print_trace, | |||
| print_flag::resolve_address, | |||
| }); | |||
| return value; | |||
| } | |||
| exception::exception() | |||
| : exception("") | |||
| { } | |||
| exception::exception(std::string msg) | |||
| : message (msg) | |||
| , stack_size (0) | |||
| , _msg_cache_empty (true) | |||
| { | |||
| stack_size = backtrace(&stack[0], max_stack_size); | |||
| } | |||
| void exception::print(std::ostream& os, const print_flags& flags) const | |||
| { | |||
| print_message(os); | |||
| if (!flags.is_set(print_flag::print_trace)) | |||
| return; | |||
| os << std::endl; | |||
| char** lines = nullptr; | |||
| if (flags.is_set(print_flag::resolve_address)) | |||
| lines = backtrace_symbols(stack, stack_size); | |||
| for (int i = 0; i < stack_size; ++i) | |||
| { | |||
| os << " [0x" << std::setw(2 * sizeof(void*)) << std::setfill('0') << std::hex << reinterpret_cast<uintptr_t>(stack[i]) << "]"; | |||
| if (lines && lines[i]) | |||
| os << " " << lines[i]; | |||
| os << std::endl; | |||
| } | |||
| } | |||
| std::string exception::print(const print_flags& flags) const | |||
| { | |||
| std::ostringstream os; | |||
| print(os, flags); | |||
| return os.str(); | |||
| } | |||
| std::string exception::to_string() const | |||
| { | |||
| if (_msg_cache_empty) | |||
| { | |||
| _msg_cache = print(); | |||
| _msg_cache_empty = false; | |||
| } | |||
| return _msg_cache.c_str(); | |||
| } | |||
| const char* exception::what() const throw() | |||
| { return to_string().c_str(); } | |||
| void exception::print_message(std::ostream& os) const | |||
| { | |||
| os << message; | |||
| } | |||
| std::ostream& operator <<(std::ostream& os, const exception& ex) | |||
| { | |||
| ex.print(os); | |||
| return os; | |||
| } | |||
| /* error_exception */ | |||
| error_exception::error_exception(int e) | |||
| : exception (std::to_string(e) + " - " + strerror(e)) | |||
| , error (e) | |||
| { } | |||
| error_exception::error_exception(const std::string& msg, int e) : | |||
| exception(msg + ": " + std::to_string(e) + " - " + strerror(e)), | |||
| error(e) | |||
| { } | |||
| /* range_exception */ | |||
| range_exception::range_exception(size_t mi, size_t ma, size_t idx, std::string msg) | |||
| : exception (msg) | |||
| , min (mi) | |||
| , max (ma) | |||
| , index (idx) | |||
| { } | |||
| void range_exception::print_message(std::ostream& os) const | |||
| { | |||
| os << "index out of range (min=" << min << "; max=" << max << "; index=" << index << ")"; | |||
| if (!message.empty()) | |||
| os << " - " << message; | |||
| } | |||
| /* argument_exception */ | |||
| argument_exception::argument_exception(std::string arg, std::string msg) | |||
| : exception (msg) | |||
| , argument (arg) | |||
| { } | |||
| void argument_exception::print_message(std::ostream& os) const | |||
| { | |||
| os << "invalid argument"; | |||
| if (!argument.empty()) | |||
| os << "(" << argument << ")"; | |||
| if (!message.empty()) | |||
| os << " - " << message; | |||
| } | |||
| } | |||
| @@ -0,0 +1,245 @@ | |||
| #pragma once | |||
| #include <stdio.h> | |||
| #include <limits> | |||
| #include <cassert> | |||
| #include <type_traits> | |||
| #include <initializer_list> | |||
| namespace cppcore | |||
| { | |||
| namespace __impl | |||
| { | |||
| /** | |||
| * @brief Helper class to convert enumeration values. | |||
| * | |||
| * This class does not convert the values of the enum. It will cast the enum directly to the flag. | |||
| */ | |||
| template<class T_enum, class T_base> | |||
| struct op_flag_convert_none | |||
| { | |||
| /** | |||
| * @brief Convert the given enum value to it's underlying flags value. | |||
| * | |||
| * The enum already represents the flag, so no convertion is needed. | |||
| */ | |||
| static inline T_base to_base(const T_enum& e); | |||
| /** | |||
| * @brief Convert the given flag index to an normal enum value. | |||
| * | |||
| * To get the enum (which equal to the flag), we need to use the index as shift count. | |||
| */ | |||
| static inline T_enum from_index(const ssize_t& index); | |||
| }; | |||
| /** | |||
| * @brief Helper class to convert enumeration values. | |||
| * | |||
| * This class will shift the enum to generate the suitable flag. | |||
| */ | |||
| template<class T_enum, class T_base> | |||
| struct op_flag_convert_shift | |||
| { | |||
| /** | |||
| * @brief Convert the given enum value to it's underlying flags value. | |||
| * | |||
| * The enum values are numbered continuously. To get the flag we need to use the enum as shift count. | |||
| */ | |||
| static inline T_base to_base(const T_enum& e); | |||
| /** | |||
| * @brief Convert the given flag index to an normal enum value. | |||
| * | |||
| * The given enum is equal to the flag index, no conversion is needed. | |||
| */ | |||
| static inline T_enum from_index(const ssize_t& index); | |||
| }; | |||
| } | |||
| /** | |||
| * @brief Class to create a bitmask of an enum type. | |||
| */ | |||
| template< | |||
| class T_enum, | |||
| class T_base = typename std::underlying_type<T_enum>::type, | |||
| class T_op = __impl::op_flag_convert_none<T_enum, T_base>> | |||
| struct flags | |||
| { | |||
| public: | |||
| using enum_type = T_enum; | |||
| using base_type = T_base; | |||
| using op_type = T_op; | |||
| public: | |||
| /** | |||
| * @brief Class to iterate through the flags. | |||
| */ | |||
| struct iterator | |||
| { | |||
| private: | |||
| static constexpr ssize_t bit_count = static_cast<ssize_t>(8 * sizeof(base_type)); | |||
| base_type _base; //!< Flags to iterate over. | |||
| ssize_t _pos; //!< Current position. | |||
| public: | |||
| /** | |||
| * @brief Constructor. | |||
| * | |||
| * @param[in] base Flasg to iterate over. | |||
| * @param[in] is_end This is the end iterator. | |||
| */ | |||
| inline iterator(const base_type& base, bool is_end); | |||
| /** | |||
| * @brief Equality compare operator. | |||
| */ | |||
| inline bool operator==(const iterator& other) const; | |||
| /** | |||
| * @brief Negative equality compare operator. | |||
| */ | |||
| inline bool operator!=(const iterator& other) const; | |||
| /** | |||
| * @brief Dereference the iterator. | |||
| */ | |||
| inline enum_type operator*() const; | |||
| /** | |||
| * @brief Increment operator. | |||
| */ | |||
| inline iterator& operator++(); | |||
| /** | |||
| * @brief Increment operator. | |||
| */ | |||
| inline iterator operator++(int); | |||
| private: | |||
| /** | |||
| * @brief Move the iterator to it's next position. | |||
| */ | |||
| inline void next(); | |||
| }; | |||
| public: | |||
| base_type value; //!< intenal representation of the flags | |||
| public: /* constructors */ | |||
| /** | |||
| * @brief Default constructor. | |||
| */ | |||
| inline flags(); | |||
| /** | |||
| * @brief Constructor to create a flags object from the underlying data type. | |||
| */ | |||
| inline explicit flags(base_type v); | |||
| /** | |||
| * @brief Constructor to create a flags object from the enum type. | |||
| */ | |||
| inline flags(enum_type e); | |||
| /** | |||
| * @brief Copy constructor. | |||
| */ | |||
| inline flags(const flags& other); | |||
| /** | |||
| * @brief Constructor to create flags object from a list of enum values. | |||
| */ | |||
| inline flags(std::initializer_list<enum_type> list); | |||
| public: /* misc */ | |||
| /** | |||
| * @brief Returns the begin iterator. | |||
| */ | |||
| inline auto begin() const; | |||
| /** | |||
| * @brief Returns the end iterator. | |||
| */ | |||
| inline auto end() const; | |||
| /** | |||
| * @brief Check if the given enum value is set in the flags object. | |||
| */ | |||
| inline bool is_set(enum_type e) const; | |||
| /** | |||
| * @brief Set the passed enum value in the flags object. | |||
| */ | |||
| inline void set(enum_type e); | |||
| /** | |||
| * @brief Clear the passed enum value in the flags object. | |||
| */ | |||
| inline void clear(enum_type e); | |||
| /** | |||
| * @brief REset all flags. | |||
| */ | |||
| inline void reset(); | |||
| public: /* operators */ | |||
| /** | |||
| * @brief Get the value of underlying type of the flags object. | |||
| */ | |||
| inline base_type operator()() const; | |||
| /** | |||
| * @brief Implicit conversion to the base type. | |||
| */ | |||
| inline operator base_type() const; | |||
| /** | |||
| * @brief Implicit conversion to bool. | |||
| */ | |||
| inline explicit operator bool() const; | |||
| /** | |||
| * @brief Check if a enum value is set in the flags object. | |||
| */ | |||
| inline bool operator[](enum_type e) const; | |||
| public: /* static */ | |||
| /** | |||
| * @brief Get a flags object with all flags cleared. | |||
| */ | |||
| static inline const flags& empty(); | |||
| /** | |||
| * @brief Get a flags object with all flags set. | |||
| */ | |||
| static inline const flags& all(); | |||
| }; | |||
| /** | |||
| * @brief Flag class that uses the enum as is. | |||
| */ | |||
| template< | |||
| class T_enum, | |||
| class T_base = typename std::underlying_type<T_enum>::type> | |||
| using simple_flags = flags<T_enum, T_base, __impl::op_flag_convert_none<T_enum, T_base>>; | |||
| /** | |||
| * @brief Flag class that uses the enum as index. | |||
| */ | |||
| template< | |||
| class T_enum, | |||
| class T_base = typename std::underlying_type<T_enum>::type> | |||
| using shifted_flags = flags<T_enum, T_base, __impl::op_flag_convert_shift<T_enum, T_base>>; | |||
| } | |||
| #include "flags.inl" | |||
| @@ -0,0 +1,196 @@ | |||
| #pragma once | |||
| #include "flags.h" | |||
| namespace cppcore | |||
| { | |||
| namespace __impl | |||
| { | |||
| /* op_flag_convert_none */ | |||
| template<class T_enum, class T_base> | |||
| T_base op_flag_convert_none<T_enum, T_base> | |||
| ::to_base(const T_enum& e) | |||
| { return static_cast<T_base>(e); } | |||
| template<class T_enum, class T_base> | |||
| T_enum op_flag_convert_none<T_enum, T_base> | |||
| ::from_index(const ssize_t& index) | |||
| { return static_cast<T_enum>(1 << index); } | |||
| /* op_flag_convert_shift */ | |||
| template<class T_enum, class T_base> | |||
| T_base op_flag_convert_shift<T_enum, T_base> | |||
| ::to_base(const T_enum& e) | |||
| { return static_cast<T_base>(1 << static_cast<int>(e)); } | |||
| template<class T_enum, class T_base> | |||
| T_enum op_flag_convert_shift<T_enum, T_base> | |||
| ::from_index(const ssize_t& index) | |||
| { return static_cast<T_enum>(index); } | |||
| } | |||
| /* flags::iterator */ | |||
| template<class T_enum, class T_base, class T_op> | |||
| flags<T_enum, T_base, T_op>::iterator | |||
| ::iterator(const base_type& base, bool is_end) | |||
| : _base(base) | |||
| , _pos (is_end ? bit_count : -1) | |||
| { next(); } | |||
| template<class T_enum, class T_base, class T_op> | |||
| bool flags<T_enum, T_base, T_op>::iterator | |||
| ::operator==(const iterator& other) const | |||
| { return _base == other._base && _pos == other._pos; } | |||
| template<class T_enum, class T_base, class T_op> | |||
| bool flags<T_enum, T_base, T_op>::iterator | |||
| ::operator!=(const iterator& other) const | |||
| { return _base != other._base || _pos != other._pos; } | |||
| template<class T_enum, class T_base, class T_op> | |||
| T_enum flags<T_enum, T_base, T_op>::iterator | |||
| ::operator*() const | |||
| { | |||
| assert(_pos < bit_count); | |||
| return op_type::from_index(_pos); | |||
| } | |||
| template<class T_enum, class T_base, class T_op> | |||
| typename flags<T_enum, T_base, T_op>::iterator& | |||
| flags<T_enum, T_base, T_op>::iterator | |||
| ::operator++() | |||
| { | |||
| next(); | |||
| return *this; | |||
| } | |||
| template<class T_enum, class T_base, class T_op> | |||
| typename flags<T_enum, T_base, T_op>::iterator | |||
| flags<T_enum, T_base, T_op>::iterator | |||
| ::operator++(int) | |||
| { | |||
| auto ret = *this; | |||
| next(); | |||
| return ret; | |||
| } | |||
| template<class T_enum, class T_base, class T_op> | |||
| void flags<T_enum, T_base, T_op>::iterator | |||
| ::next() | |||
| { | |||
| if (_pos >= bit_count) | |||
| return; | |||
| do | |||
| { | |||
| ++_pos; | |||
| } while(_pos < bit_count && !static_cast<bool>(_base & (1 << _pos))); | |||
| } | |||
| /* flags */ | |||
| template<class T_enum, class T_base, class T_op> | |||
| flags<T_enum, T_base, T_op> | |||
| ::flags() | |||
| : value(0) | |||
| { } | |||
| template<class T_enum, class T_base, class T_op> | |||
| flags<T_enum, T_base, T_op> | |||
| ::flags(base_type v) | |||
| : value(v) | |||
| { } | |||
| template<class T_enum, class T_base, class T_op> | |||
| flags<T_enum, T_base, T_op> | |||
| ::flags(enum_type e) | |||
| : value(T_op::to_base(e)) | |||
| { } | |||
| template<class T_enum, class T_base, class T_op> | |||
| flags<T_enum, T_base, T_op> | |||
| ::flags(const flags& other) | |||
| : value(other.value) | |||
| { } | |||
| template<class T_enum, class T_base, class T_op> | |||
| flags<T_enum, T_base, T_op> | |||
| ::flags(std::initializer_list<enum_type> list) | |||
| : flags() | |||
| { | |||
| for (auto& e : list) | |||
| set(e); | |||
| } | |||
| template<class T_enum, class T_base, class T_op> | |||
| auto flags<T_enum, T_base, T_op> | |||
| ::begin() const | |||
| { return iterator(value, false); } | |||
| template<class T_enum, class T_base, class T_op> | |||
| auto flags<T_enum, T_base, T_op> | |||
| ::end() const | |||
| { return iterator(value, true); } | |||
| template<class T_enum, class T_base, class T_op> | |||
| bool flags<T_enum, T_base, T_op> | |||
| ::is_set(enum_type e) const | |||
| { return static_cast<bool>(value & op_type::to_base(e)); } | |||
| template<class T_enum, class T_base, class T_op> | |||
| void flags<T_enum, T_base, T_op> | |||
| ::set(enum_type e) | |||
| { value = static_cast<base_type>(value | op_type::to_base(e)); } | |||
| template<class T_enum, class T_base, class T_op> | |||
| void flags<T_enum, T_base, T_op> | |||
| ::clear(enum_type e) | |||
| { value = static_cast<base_type>(value & ~op_type::to_base(e)); } | |||
| template<class T_enum, class T_base, class T_op> | |||
| void flags<T_enum, T_base, T_op> | |||
| ::reset() | |||
| { value = 0; } | |||
| template<class T_enum, class T_base, class T_op> | |||
| T_base flags<T_enum, T_base, T_op> | |||
| ::operator()() const | |||
| { return value; } | |||
| template<class T_enum, class T_base, class T_op> | |||
| flags<T_enum, T_base, T_op> | |||
| ::operator base_type() const | |||
| { return static_cast<base_type>(value); } | |||
| template<class T_enum, class T_base, class T_op> | |||
| flags<T_enum, T_base, T_op> | |||
| ::operator bool() const | |||
| { return static_cast<bool>(value); } | |||
| template<class T_enum, class T_base, class T_op> | |||
| bool flags<T_enum, T_base, T_op> | |||
| ::operator[](enum_type e) const | |||
| { return is_set(e); } | |||
| template<class T_enum, class T_base, class T_op> | |||
| const flags<T_enum, T_base, T_op>& flags<T_enum, T_base, T_op> | |||
| ::empty() | |||
| { | |||
| const flags value(0); | |||
| return value; | |||
| } | |||
| template<class T_enum, class T_base, class T_op> | |||
| const flags<T_enum, T_base, T_op>& flags<T_enum, T_base, T_op> | |||
| ::all() | |||
| { | |||
| const flags value(std::numeric_limits<base_type>::max()); | |||
| return value; | |||
| } | |||
| } | |||
| @@ -0,0 +1,70 @@ | |||
| #pragma once | |||
| #include <iostream> | |||
| namespace cppcore | |||
| { | |||
| namespace __impl | |||
| { | |||
| constexpr long default_indent = 4; | |||
| inline int indent_stream_index() | |||
| { | |||
| static const int value = std::ios::xalloc(); | |||
| return value; | |||
| } | |||
| inline int indent_count_stream_index() | |||
| { | |||
| static const int value = std::ios::xalloc(); | |||
| return value; | |||
| } | |||
| struct set_indent_impl | |||
| { int value; }; | |||
| } | |||
| inline auto setindent(int value) | |||
| { return __impl::set_indent_impl { value }; } | |||
| inline std::ostream& incindent(std::ostream& os) | |||
| { | |||
| ++os.iword(__impl::indent_stream_index()); | |||
| return os; | |||
| } | |||
| inline std::ostream& decindent(std::ostream& os) | |||
| { | |||
| auto& indent = os.iword(__impl::indent_stream_index()); | |||
| if (--indent < 0) | |||
| indent = 0; | |||
| return os; | |||
| } | |||
| inline std::ostream& indent(std::ostream& os) | |||
| { | |||
| auto i = os.iword(__impl::indent_stream_index()); | |||
| auto c = __impl::default_indent + os.iword(__impl::indent_count_stream_index()); | |||
| i *= c; | |||
| if (i >= 0) | |||
| { | |||
| os << std::endl; | |||
| while (i--) | |||
| os.put(' '); | |||
| } | |||
| return os; | |||
| } | |||
| } | |||
| namespace std | |||
| { | |||
| template<typename T_char, typename T_traits> | |||
| inline basic_ostream<T_char, T_traits>& operator<< (basic_ostream<T_char, T_traits>& os, const cppcore::__impl::set_indent_impl& i) | |||
| { | |||
| using namespace ::cppcore; | |||
| os.iword(__impl::indent_count_stream_index()) = i.value - __impl::default_indent; | |||
| return os; | |||
| } | |||
| } | |||
| @@ -0,0 +1,209 @@ | |||
| #pragma once | |||
| #include <iostream> | |||
| #include <cppcore/misc/exception.h> | |||
| namespace cppcore | |||
| { | |||
| namespace __impl | |||
| { | |||
| /** | |||
| * @brief Predicate class to read any type from the stream. | |||
| */ | |||
| template<class T, class T_enable = void> | |||
| struct op_stream_read; | |||
| /** | |||
| * @brief Predicate class to write any type to the stream. | |||
| */ | |||
| template<class T, class T_enable = void> | |||
| struct op_stream_write; | |||
| /** | |||
| * @brief Traits class to wrapp the needed types. | |||
| */ | |||
| struct stream_helper_traits | |||
| { | |||
| template<typename T> | |||
| using write_stream_predicate_type = op_stream_write<T>; | |||
| template<typename T> | |||
| using read_stream_predicate_type = op_stream_read<T>; | |||
| }; | |||
| } | |||
| /** | |||
| * @brief Helper class to read/write data to/from stream. | |||
| * | |||
| * @tparam T_traits Traits class to use for the stream operations. | |||
| */ | |||
| template<typename T_traits> | |||
| struct stream_helper_t | |||
| { | |||
| using traits_type = T_traits; | |||
| /** | |||
| * @brief Write a value to the stream. | |||
| * | |||
| * @tparam T Type of the value to write to the stream. | |||
| * | |||
| * @param[in] os Stream to write data to. | |||
| * @param[in] t Value to write to stream. | |||
| * | |||
| * @return Number of bytes written. | |||
| */ | |||
| template<class T> | |||
| static inline size_t write(std::ostream& os, const T& t); | |||
| /** | |||
| * @brief Read a value from the stream. | |||
| * | |||
| * @tparam T Type of the value to read from the stream. | |||
| * | |||
| * @param[in] is Stream to read data from. | |||
| * @param[out] t Parameter to store read value in. | |||
| * | |||
| * @return Number of read bytes. | |||
| */ | |||
| template<class T> | |||
| static inline size_t read(std::istream& is, T& t); | |||
| /** | |||
| * @brief Read a value from the stream. | |||
| * | |||
| * @tparam T Type of the value to read from the stream. | |||
| * | |||
| * @param[in] is Stream to read data from. | |||
| * | |||
| * @return Value read from the stream. | |||
| */ | |||
| template<class T> | |||
| static inline T read(std::istream& is); | |||
| }; | |||
| /** | |||
| * @brief Stream helper class with default traits. | |||
| */ | |||
| struct stream_helper | |||
| : public stream_helper_t<__impl::stream_helper_traits> | |||
| { }; | |||
| /** | |||
| * @brief Class to write values to the given stream. | |||
| */ | |||
| template<typename T_traits > | |||
| struct stream_writer_t | |||
| { | |||
| public: | |||
| using traits_type = T_traits; | |||
| using stream_helper_type = stream_helper_t<traits_type>; | |||
| public: | |||
| std::ostream& stream; //!< stream to write data to | |||
| public: | |||
| /** | |||
| * @brief Constructor. | |||
| */ | |||
| inline stream_writer_t(std::ostream& p_stream); | |||
| /** | |||
| * @brief Write a value to the stream. | |||
| * | |||
| * @tparam T Type of the value to write to the stream. | |||
| * | |||
| * @param[in] t Value to write to stream. | |||
| */ | |||
| template<class T> | |||
| inline void write(const T& t); | |||
| }; | |||
| /** | |||
| * @brief Stream write class with default traits. | |||
| */ | |||
| struct stream_writer | |||
| : public stream_writer_t<__impl::stream_helper_traits> | |||
| { }; | |||
| /** | |||
| * @brief Class to read values from the given stream. | |||
| */ | |||
| template<typename T_traits> | |||
| struct stream_reader_t | |||
| { | |||
| public: | |||
| using traits_type = T_traits; | |||
| using stream_helper_type = stream_helper_t<traits_type>; | |||
| public: | |||
| std::istream& stream; //!< stream to write data to | |||
| public: | |||
| /** | |||
| * @brief Constructor. | |||
| */ | |||
| inline stream_reader_t(std::istream& p_stream); | |||
| /** | |||
| * @brief Read a value from the stream. | |||
| * | |||
| * @tparam T Type of the value to read from the stream. | |||
| * | |||
| * @param[out] t Parameter to store read value in. | |||
| * | |||
| * @return Number of read bytes. | |||
| */ | |||
| template<class T> | |||
| inline size_t read(T& t); | |||
| /** | |||
| * @brief Read a value from the stream. | |||
| * | |||
| * @tparam T Type of the value to read from the stream. | |||
| * | |||
| * @return Value read from the stream. | |||
| */ | |||
| template<class T> | |||
| inline T read(std::istream& is); | |||
| }; | |||
| /** | |||
| * @brief Stream reader class with default traits. | |||
| */ | |||
| struct stream_reader | |||
| : public stream_reader_t<__impl::stream_helper_traits> | |||
| { }; | |||
| /** | |||
| * @brief Helper class to save stream format. | |||
| * | |||
| * This class stores the format of the passed stream and restore it, if it is destroyed- | |||
| */ | |||
| struct stream_format_saver | |||
| : private std::ios | |||
| { | |||
| std::ostream& stream; | |||
| /** | |||
| * @brief Constructor. | |||
| */ | |||
| inline stream_format_saver(std::ostream& s); | |||
| /** | |||
| * @brief Destructor. | |||
| */ | |||
| inline ~stream_format_saver(); | |||
| }; | |||
| } | |||
| #include "stream.inl" | |||
| @@ -0,0 +1,176 @@ | |||
| #pragma once | |||
| #include "stream.h" | |||
| namespace cppcore | |||
| { | |||
| /* stream_helper_t */ | |||
| template<typename T_traits> | |||
| template<class T> | |||
| size_t stream_helper_t<T_traits> | |||
| ::write(std::ostream& os, const T& t) | |||
| { return __impl::op_stream_write<T>()(os, t); } | |||
| template<typename T_traits> | |||
| template<class T> | |||
| size_t stream_helper_t<T_traits> | |||
| ::read(std::istream& is, T& t) | |||
| { return __impl::op_stream_read<T>()(is, t); } | |||
| template<typename T_traits> | |||
| template<class T> | |||
| T stream_helper_t<T_traits> | |||
| ::read(std::istream& is) | |||
| { | |||
| T t; | |||
| read<T>(is, t); | |||
| return std::move(t); | |||
| } | |||
| /* stream_writer_t */ | |||
| template<typename T_traits> | |||
| stream_writer_t<T_traits> | |||
| ::stream_writer_t(std::ostream& p_stream) | |||
| : stream(p_stream) | |||
| { } | |||
| template<typename T_traits> | |||
| template<class T> | |||
| void stream_writer_t<T_traits> | |||
| ::write(const T& t) | |||
| { stream_helper_type::template write<T>(stream, t); } | |||
| /* stream_reader_t */ | |||
| template<typename T_traits> | |||
| stream_reader_t<T_traits> | |||
| ::stream_reader_t(std::istream& p_stream) | |||
| : stream(p_stream) | |||
| { } | |||
| template<typename T_traits> | |||
| template<class T> | |||
| size_t stream_reader_t<T_traits> | |||
| ::read(T& t) | |||
| { return stream_helper_type::template read<T>(stream, t); } | |||
| template<typename T_traits> | |||
| template<class T> | |||
| T stream_reader_t<T_traits> | |||
| ::read(std::istream& is) | |||
| { return stream_helper_type::template read<T>(stream); } | |||
| /* stream_format_saver */ | |||
| inline stream_format_saver | |||
| ::stream_format_saver(std::ostream& s) | |||
| : stream(s) | |||
| { copyfmt(stream); } | |||
| inline stream_format_saver | |||
| ::~stream_format_saver() | |||
| { stream.copyfmt(*this); } | |||
| namespace __impl | |||
| { | |||
| /* op_stream_read */ | |||
| template<class T, class Enable> | |||
| struct op_stream_read | |||
| { | |||
| inline size_t operator()(std::istream& is, T& t) | |||
| { | |||
| if (!is) | |||
| throw exception("unable to read data from stream: invalid stream"); | |||
| if (is.read(reinterpret_cast<char*>(&t), sizeof(t)).gcount() != sizeof(t)) | |||
| throw exception("unable to read data from stream: EOF"); | |||
| if (!is) | |||
| throw exception("unable to read data from stream: stream error"); | |||
| return sizeof(t); | |||
| } | |||
| }; | |||
| template<> | |||
| struct op_stream_read<std::string, void> | |||
| { | |||
| inline size_t operator()(std::istream& is, std::string& t) | |||
| { | |||
| uint32_t sz; | |||
| op_stream_read<uint32_t, void>()(is, sz); | |||
| if (!is) | |||
| throw exception("unable to read data from stream: invalid stream"); | |||
| std::string tmp; | |||
| tmp.resize(sz); | |||
| if (is.read(const_cast<char*>(tmp.data()), sz).gcount() != sz) | |||
| throw exception("unable to read data from stream: EOF"); | |||
| if (!is) | |||
| throw exception("unable to read data from stream: stream error"); | |||
| t = std::move(tmp); | |||
| return sizeof(sz) + sz; | |||
| } | |||
| }; | |||
| template<class T> | |||
| struct op_stream_read<T, decltype(std::declval<T>().deserialize(std::declval<std::istream&>()), void())> | |||
| { | |||
| inline size_t operator()(std::istream& is, T& t) | |||
| { | |||
| auto pos = is.tellg(); | |||
| t.deserialize(is); | |||
| return static_cast<size_t>(is.tellg() - pos); | |||
| } | |||
| }; | |||
| /* op_stream_write */ | |||
| template<class T, class Enable> | |||
| struct op_stream_write | |||
| { | |||
| inline size_t operator()(std::ostream& os, const T& t) const | |||
| { | |||
| if (!os) | |||
| throw exception("unable to write data to stream: invalid stream"); | |||
| os.write(reinterpret_cast<const char*>(&t), sizeof(t)); | |||
| if (!os) | |||
| throw exception("unable to write data to stream: stream error"); | |||
| return sizeof(t); | |||
| } | |||
| }; | |||
| template<> | |||
| struct op_stream_write<std::string, void> | |||
| { | |||
| inline size_t operator()(std::ostream& os, const std::string& t) | |||
| { | |||
| if (t.size() > std::numeric_limits<uint32_t>::max()) | |||
| throw exception("unable to write data to stream: string is to large"); | |||
| op_stream_write<uint32_t, void>()(os, static_cast<uint32_t>(t.size())); | |||
| if (!os) | |||
| throw exception("unable to write data to stream: invalid stream"); | |||
| os.write(t.data(), static_cast<std::streamsize>(t.size())); | |||
| if (!os) | |||
| throw exception("unable to write data to stream: stream error"); | |||
| return sizeof(uint32_t) + t.size(); | |||
| } | |||
| }; | |||
| template<class T> | |||
| struct op_stream_write<T, decltype(std::declval<T>().serialize(std::declval<std::ostream&>()), void())> | |||
| { | |||
| inline size_t operator()(std::ostream& os, const T& t) | |||
| { | |||
| auto pos = os.tellp(); | |||
| t.serialize(os); | |||
| return static_cast<size_t>(os.tellp() - pos); | |||
| } | |||
| }; | |||
| } | |||
| } | |||
| @@ -0,0 +1,49 @@ | |||
| #pragma once | |||
| #include <cxxabi.h> | |||
| #include <string> | |||
| namespace cppcore | |||
| { | |||
| /** | |||
| * @brief Class to get meta infos for a specific type. | |||
| */ | |||
| template<typename T> | |||
| struct type_helper | |||
| { | |||
| public: | |||
| /** | |||
| * @brief Get the name of the type. | |||
| */ | |||
| static inline std::string name(); | |||
| }; | |||
| /** | |||
| * @brief Implements a unique counter for the given template parameters. | |||
| */ | |||
| template<typename...> | |||
| struct unique_counter | |||
| { | |||
| /** | |||
| * @brief Get the next value of the counter. | |||
| */ | |||
| static inline size_t& next(); | |||
| }; | |||
| /** | |||
| * @brief Get a unique ID for the passed template arguments. | |||
| * | |||
| * @tparam T_counter Counter to use to generate the unique ID. | |||
| * @tparam X Type to generate the ID for. | |||
| */ | |||
| template<typename T_counter, typename... X> | |||
| inline size_t get_unique_id(); | |||
| } | |||
| #include "type_helper.inl" | |||
| @@ -0,0 +1,39 @@ | |||
| #pragma once | |||
| #include "type_helper.h" | |||
| namespace cppcore | |||
| { | |||
| template<typename T> | |||
| std::string type_helper<T>::name() | |||
| { | |||
| int status; | |||
| auto name = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status); | |||
| return std::string(name ? name : typeid(T).name()); | |||
| } | |||
| /** | |||
| * @brief Implements a unique counter for the given template parameters. | |||
| */ | |||
| template<typename... T_args> | |||
| size_t& unique_counter<T_args...>::next() | |||
| { | |||
| static size_t value { }; | |||
| return ++value; | |||
| } | |||
| /** | |||
| * @brief Get a unique ID for the passed template arguments. | |||
| * | |||
| * @tparam T_counter Counter to use to generate the unique ID. | |||
| * @tparam X Type to generate the ID for. | |||
| */ | |||
| template<typename T_counter, typename... X> | |||
| size_t get_unique_id() | |||
| { | |||
| static const auto v = unique_counter<T_counter>::next(); | |||
| return v; | |||
| } | |||
| } | |||
| @@ -0,0 +1,28 @@ | |||
| #pragma once | |||
| namespace cppcore | |||
| { | |||
| /** | |||
| * @brief Count the bit set in the passed value using HACKMEM bitcount. | |||
| */ | |||
| inline size_t bit_count(uint32_t u); | |||
| /** | |||
| * @breif Try to dynamic cast the passed value to the given type. | |||
| * | |||
| * @tparam T Type to cast. | |||
| * @tparam S Type to cast to. | |||
| * | |||
| * @param[in] t Value to cast. | |||
| * @param[out] s Parameter to store casted value in. | |||
| * | |||
| * @retval true If the cast was succesful. | |||
| * @retval false If the cast failed. | |||
| */ | |||
| template<class T, class S> | |||
| inline bool try_cast(T* t, S*& s); | |||
| } | |||
| #include "utils.inl" | |||
| @@ -0,0 +1,23 @@ | |||
| #pragma once | |||
| #include "utils.h" | |||
| namespace cppcore | |||
| { | |||
| size_t bit_count(uint32_t u) | |||
| { | |||
| u = u | |||
| - ((u >> 1) & 033333333333) | |||
| - ((u >> 2) & 011111111111); | |||
| return static_cast<size_t>(((u + (u >> 3)) & 030707070707) % 63); | |||
| } | |||
| template<class T, class S> | |||
| bool try_cast(T* t, S*& s) | |||
| { | |||
| s = dynamic_cast<S*>(t); | |||
| return static_cast<bool>(s); | |||
| } | |||
| } | |||
| @@ -0,0 +1,3 @@ | |||
| #pragma once | |||
| #include <cppcore/threading/cancellation_token.h> | |||
| @@ -0,0 +1,107 @@ | |||
| #pragma once | |||
| #include <atomic> | |||
| #include <exception> | |||
| namespace cppcore | |||
| { | |||
| /** | |||
| * @brief Exception to throw to terminate the current operation. | |||
| */ | |||
| struct cancellation_exception | |||
| : public std::exception | |||
| { | |||
| inline const char* what() const throw() override; | |||
| }; | |||
| /** | |||
| * @brief Excaption to throw to terminate the current operation with some additional data. | |||
| */ | |||
| template<typename T> | |||
| struct data_cancellation_exception | |||
| : public cancellation_exception | |||
| { | |||
| T data; | |||
| /** | |||
| * @brief Constructor. | |||
| */ | |||
| inline data_cancellation_exception(const T& d); | |||
| }; | |||
| /** | |||
| * @brief Token to pass to an operation to check if an cancellation is requested. | |||
| */ | |||
| struct cancellation_token | |||
| { | |||
| private: | |||
| /** | |||
| * @brief Is set to true if the cancellation is requested. | |||
| */ | |||
| std::atomic<bool> _is_cancellation_requested; | |||
| public: | |||
| /** | |||
| * @brief Constructor. | |||
| */ | |||
| inline cancellation_token(); | |||
| /** | |||
| * @brief Destructor. | |||
| */ | |||
| virtual ~cancellation_token() = default; | |||
| /** | |||
| * @brief Returns true if a cancellation was requested, false otherwise. | |||
| */ | |||
| inline bool is_cancellation_requested() const; | |||
| /** | |||
| * @brief Throw a cancellation exception if cancellation was requested. | |||
| */ | |||
| virtual void throw_if_cancellation_requested() const = 0; | |||
| protected: | |||
| /** | |||
| * @brief Request to cancel the current operation. | |||
| */ | |||
| inline void cancel(); | |||
| private: | |||
| /** | |||
| * @brief Move constructor. | |||
| */ | |||
| cancellation_token(cancellation_token&&) = delete; | |||
| /** | |||
| * @brief Copy constructor. | |||
| */ | |||
| cancellation_token(const cancellation_token&) = delete; | |||
| }; | |||
| /** | |||
| * @brief Source of a cancellation token. Can be used to cancel the current operation. | |||
| */ | |||
| template<typename T> | |||
| struct cancellation_source | |||
| : public cancellation_token | |||
| { | |||
| private: | |||
| T _value; //!< Value to pass to the cancellation exception. | |||
| public: | |||
| /** | |||
| * @brief Throw a cancellation exception if cancellation was requested. | |||
| */ | |||
| inline void throw_if_cancellation_requested() const override; | |||
| /** | |||
| * @brief Request to cancel the current operation. | |||
| */ | |||
| inline void cancel(const T& value); | |||
| }; | |||
| } | |||
| #include "cancellation_token.inl" | |||
| @@ -0,0 +1,78 @@ | |||
| #pragma once | |||
| #include "cancellation_token.h" | |||
| namespace cppcore | |||
| { | |||
| /* cancellation_exception */ | |||
| const char* cancellation_exception | |||
| ::what() const throw() | |||
| { return "task was canceled!"; } | |||
| /* data_cancellation_exception */ | |||
| template<typename T> | |||
| data_cancellation_exception<T>::data_cancellation_exception(const T& d) | |||
| : data(d) | |||
| { } | |||
| /* data_cancellation_exception<void> */ | |||
| template<> | |||
| struct data_cancellation_exception<void> | |||
| : public cancellation_exception | |||
| { }; | |||
| /* cancellation_token */ | |||
| cancellation_token | |||
| ::cancellation_token() | |||
| : _is_cancellation_requested(false) | |||
| { } | |||
| bool cancellation_token | |||
| ::is_cancellation_requested() const | |||
| { return _is_cancellation_requested; } | |||
| void cancellation_token | |||
| ::cancel() | |||
| { _is_cancellation_requested = true; } | |||
| /* cancellation_source */ | |||
| template<typename T> | |||
| void cancellation_source<T> | |||
| ::throw_if_cancellation_requested() const | |||
| { | |||
| if (is_cancellation_requested()) | |||
| throw data_cancellation_exception<T>(_value); | |||
| } | |||
| template<typename T> | |||
| void cancellation_source<T> | |||
| ::cancel(const T& value) | |||
| { | |||
| cancellation_token::cancel(); | |||
| _value = value; | |||
| } | |||
| /* cancellation_source<void> */ | |||
| template<> | |||
| struct cancellation_source<void> | |||
| : public cancellation_token | |||
| { | |||
| public: | |||
| inline void throw_if_cancellation_requested() const | |||
| { | |||
| if (is_cancellation_requested()) | |||
| throw cancellation_exception(); | |||
| } | |||
| inline void cancel() | |||
| { cancellation_token::cancel(); } | |||
| }; | |||
| } | |||
| @@ -0,0 +1,25 @@ | |||
| # Initialize ###################################################################################### | |||
| Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) | |||
| Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) | |||
| Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_SYMBOLS ) | |||
| # Interface Library ############################################################################### | |||
| Set ( CPPCORE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | |||
| Add_Library ( cppcore INTERFACE ) | |||
| Target_Include_Directories ( cppcore | |||
| INTERFACE | |||
| $<BUILD_INTERFACE:${CPPCORE_INCLUDE_DIR}> | |||
| $<INSTALL_INTERFACE:${CPPCORE_INSTALL_DIR_INCLUDE}> ) | |||
| # Install ######################################################################################### | |||
| # Header | |||
| Install ( FILES ${CPPCORE_INCLUDE_DIR}/cppcore.h | |||
| DESTINATION ${CPPCORE_INSTALL_DIR_INCLUDE} ) | |||
| Install ( DIRECTORY ${CPPCORE_INCLUDE_DIR}/cppcore | |||
| DESTINATION ${CPPCORE_INSTALL_DIR_INCLUDE} ) | |||
| Install ( TARGETS cppcore | |||
| EXPORT cppcore | |||
| DESTINATION ${CPPCORE_INSTALL_DIR_INCLUDE} ) | |||
| @@ -0,0 +1,44 @@ | |||
| # Initialize ###################################################################################### | |||
| Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) | |||
| Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) | |||
| Include ( cmake_tests OPTIONAL RESULT_VARIABLE HAS_CMAKE_TESTS ) | |||
| # Test ############################################################################################ | |||
| Find_Package ( GTest ) | |||
| If ( NOT "${GTest_FOUND}" ) | |||
| Return ( ) | |||
| EndIf ( ) | |||
| File ( GLOB_RECURSE CPPCORE_TEST_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.h ) | |||
| File ( GLOB_RECURSE CPPCORE_TEST_INLINE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.inl ) | |||
| File ( GLOB_RECURSE CPPCORE_TEST_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | |||
| Add_Executable ( cppcore-test | |||
| EXCLUDE_FROM_ALL | |||
| ${CPPCORE_TEST_HEADER_FILES} | |||
| ${CPPCORE_TEST_INLINE_FILES} | |||
| ${CPPCORE_TEST_SOURCE_FILES} ) | |||
| Target_Link_Libraries ( cppcore-test | |||
| PUBLIC | |||
| cppcore | |||
| GTest::Main ) | |||
| # optimization | |||
| If ( HAS_COTIRE ) | |||
| Cotire ( cppcore-test ) | |||
| EndIf ( ) | |||
| # pedantic | |||
| If ( HAS_PEDANTIC ) | |||
| Pedantic_Apply_Flags_Target ( cppcore-test | |||
| ALL ) | |||
| EndIf ( ) | |||
| # test | |||
| If ( HAS_CMAKE_TESTS ) | |||
| Add_CMake_Test ( NAME cppcore TARGET cppcore-test ) | |||
| Else ( ) | |||
| Add_Test ( NAME cppcore COMMAND cppcore-test ) | |||
| EndIf ( ) | |||
| @@ -0,0 +1,39 @@ | |||
| #include <gtest/gtest.h> | |||
| #include <cppcore/defines.h> | |||
| #include <cppcore/conversion/byteorder.h> | |||
| using namespace ::cppcore; | |||
| TEST(byteorder_tests, hton) | |||
| { | |||
| #if CPPCORE_BYTE_ORDER == CPPCORE_BYTE_ORDER_LITTLE | |||
| EXPECT_EQ(hton(static_cast<uint8_t> (0x12)), 0x12); | |||
| EXPECT_EQ(hton(static_cast<uint16_t>(0x1234)), 0x3412); | |||
| EXPECT_EQ(hton(static_cast<uint32_t>(0x12345678)), 0x78563412); | |||
| EXPECT_EQ(hton(static_cast<uint64_t>(0x0123456789ABCDEF)), 0xEFCDAB8967452301); | |||
| #elif CPPCORE_BYTE_ORDER == CPPCORE_BYTE_ORDER_BIG | |||
| EXPECT_EQ(hton(static_cast<uint8_t> (0x12)), 0x12); | |||
| EXPECT_EQ(hton(static_cast<uint16_t>(0x1234)), 0x1234); | |||
| EXPECT_EQ(hton(static_cast<uint32_t>(0x12345678)), 0x12345678); | |||
| EXPECT_EQ(hton(static_cast<uint64_t>(0x0123456789ABCDEF)), 0x0123456789ABCDEF); | |||
| #else | |||
| #error "Please add test!" | |||
| #endif | |||
| } | |||
| TEST(byteorder_tests, ntoh) | |||
| { | |||
| #if CPPCORE_BYTE_ORDER == CPPCORE_BYTE_ORDER_LITTLE | |||
| EXPECT_EQ(ntoh(static_cast<uint8_t> (0x12)), 0x12); | |||
| EXPECT_EQ(ntoh(static_cast<uint16_t>(0x1234)), 0x3412); | |||
| EXPECT_EQ(ntoh(static_cast<uint32_t>(0x12345678)), 0x78563412); | |||
| EXPECT_EQ(ntoh(static_cast<uint64_t>(0x0123456789ABCDEF)), 0xEFCDAB8967452301); | |||
| #elif CPPCORE_BYTE_ORDER == CPPCORE_BYTE_ORDER_BIG | |||
| EXPECT_EQ(ntoh(static_cast<uint8_t> (0x12)), 0x12); | |||
| EXPECT_EQ(ntoh(static_cast<uint16_t>(0x1234)), 0x1234); | |||
| EXPECT_EQ(ntoh(static_cast<uint32_t>(0x12345678)), 0x12345678); | |||
| EXPECT_EQ(ntoh(static_cast<uint64_t>(0x0123456789ABCDEF)), 0x0123456789ABCDEF); | |||
| #else | |||
| #error "Please add test!" | |||
| #endif | |||
| } | |||
| @@ -0,0 +1,58 @@ | |||
| #include <gtest/gtest.h> | |||
| #include <cppcore/conversion/enum.h> | |||
| #include <cppcore/conversion/string.h> | |||
| enum class TestEnum | |||
| { | |||
| Test0, | |||
| Test1, | |||
| Test2, | |||
| Test3 | |||
| }; | |||
| cppcore_define_enum_value_traits( | |||
| TestEnum, | |||
| { TestEnum::Test0, "Test0" }, | |||
| { TestEnum::Test1, "Test1" }, | |||
| { TestEnum::Test2, "Test2" }, | |||
| { TestEnum::Test3, "Test3" } | |||
| ); | |||
| using namespace ::cppcore; | |||
| using namespace ::testing; | |||
| TEST(enum_tests, to_string) | |||
| { | |||
| EXPECT_EQ(std::string("Test1"), to_string(TestEnum::Test1)); | |||
| EXPECT_EQ(std::string("Test0(0)"), enum_conversion<TestEnum>::to_string(TestEnum::Test0, true)); | |||
| EXPECT_EQ(std::string("Test1"), enum_conversion<TestEnum>::to_string(TestEnum::Test1, false)); | |||
| EXPECT_EQ(std::string("Test2(2)"), enum_conversion<TestEnum>::to_string(TestEnum::Test2, true)); | |||
| EXPECT_EQ(std::string("Test3"), enum_conversion<TestEnum>::to_string(TestEnum::Test3, false)); | |||
| EXPECT_EQ(std::string("123"), enum_conversion<TestEnum>::to_string(static_cast<TestEnum>(123), true)); | |||
| } | |||
| TEST(enum_tests, from_string) | |||
| { | |||
| TestEnum e; | |||
| EXPECT_FALSE(try_from_string("abc", e)); | |||
| EXPECT_TRUE (try_from_string("test1", e)); | |||
| EXPECT_EQ (TestEnum::Test1, e); | |||
| EXPECT_THROW(enum_conversion<TestEnum>::to_enum("abc"), convert_exception); | |||
| } | |||
| TEST(enum_tests, to_enum) | |||
| { | |||
| TestEnum e; | |||
| EXPECT_TRUE (enum_conversion<TestEnum>::try_to_enum("test0", e, false)); | |||
| EXPECT_EQ (TestEnum::Test0, e); | |||
| EXPECT_TRUE (enum_conversion<TestEnum>::try_to_enum("Test1", e, false)); | |||
| EXPECT_EQ (TestEnum::Test1, e); | |||
| EXPECT_FALSE(enum_conversion<TestEnum>::try_to_enum("asd", e, false)); | |||
| EXPECT_FALSE(enum_conversion<TestEnum>::try_to_enum("1", e, false)); | |||
| EXPECT_TRUE (enum_conversion<TestEnum>::try_to_enum("2", e, true)); | |||
| EXPECT_EQ (TestEnum::Test2, e); | |||
| } | |||
| @@ -0,0 +1,95 @@ | |||
| #include <list> | |||
| #include <vector> | |||
| #include <gtest/gtest.h> | |||
| #include <cppcore/conversion/string.h> | |||
| struct TestClass1 | |||
| { | |||
| int i; | |||
| std::string to_string() const | |||
| { return std::to_string(i); } | |||
| bool from_string(const std::string& s) | |||
| { return static_cast<bool>(std::istringstream(s) >> i); } | |||
| }; | |||
| struct TestClass2 | |||
| { | |||
| int i; | |||
| void to_string(std::ostream& os) const | |||
| { os << i; } | |||
| static bool from_string(const std::string& s, TestClass2& v) | |||
| { return static_cast<bool>(std::istringstream(s) >> v.i); } | |||
| }; | |||
| using namespace ::testing; | |||
| TEST(string_tests, to_string) | |||
| { | |||
| EXPECT_EQ(std::string("4.5"), ::cppcore::to_string(4.5)); | |||
| EXPECT_EQ(std::string("test"), ::cppcore::to_string("test")); | |||
| EXPECT_EQ(std::string("fuu"), ::cppcore::to_string(std::string("fuu"))); | |||
| EXPECT_EQ(std::string("5"), ::cppcore::to_string(TestClass1 { 5 })); | |||
| EXPECT_EQ(std::string("6"), ::cppcore::to_string(TestClass2 { 6 })); | |||
| } | |||
| TEST(string_tests, from_string) | |||
| { | |||
| double d; | |||
| EXPECT_FALSE(::cppcore::try_from_string("abc", d)); | |||
| EXPECT_TRUE (::cppcore::try_from_string("4.5", d)); | |||
| EXPECT_TRUE (d >= 4.5 && d <= 4.5); | |||
| int i; | |||
| EXPECT_FALSE(::cppcore::try_from_string("abc", i)); | |||
| EXPECT_TRUE (::cppcore::try_from_string("123", i)); | |||
| EXPECT_EQ (123, i); | |||
| TestClass1 t1; | |||
| EXPECT_FALSE(::cppcore::try_from_string("abc", t1)); | |||
| EXPECT_TRUE (::cppcore::try_from_string("11", t1)); | |||
| EXPECT_EQ (11, t1.i); | |||
| TestClass2 t2; | |||
| EXPECT_FALSE(::cppcore::try_from_string("abc", t2)); | |||
| EXPECT_TRUE (::cppcore::try_from_string("12", t2)); | |||
| EXPECT_EQ (12, t2.i); | |||
| } | |||
| TEST(string_tests, shift_operator) | |||
| { | |||
| std::ostringstream ss; | |||
| ss << TestClass2 { 6 }; | |||
| EXPECT_EQ(std::string("6"), ss.str()); | |||
| } | |||
| TEST(string_tests, vector_to_string) | |||
| { | |||
| EXPECT_EQ( | |||
| "1,2,3,4,5", | |||
| ::cppcore::to_string(std::vector<int> { 1, 2, 3, 4, 5 })); | |||
| } | |||
| TEST(string_tests, list_to_string) | |||
| { | |||
| EXPECT_EQ( | |||
| "1,2,3,4,5", | |||
| ::cppcore::to_string(std::list<int> { 1, 2, 3, 4, 5 })); | |||
| } | |||
| TEST(string_tests, string_to_vector) | |||
| { | |||
| EXPECT_EQ( | |||
| (std::vector<int> { 1, 245, 3, 4, 5 }), | |||
| ::cppcore::from_string<std::vector<int>>("1, 245, 3, 4, 5")); | |||
| } | |||
| TEST(string_tests, string_to_list) | |||
| { | |||
| EXPECT_EQ( | |||
| (std::list<int> { 123, 2, 3, 4, 5 }), | |||
| ::cppcore::from_string<std::list<int>>("123, 2, 3, 4, 5")); | |||
| } | |||
| @@ -0,0 +1,30 @@ | |||
| #include <gtest/gtest.h> | |||
| #include <cppcore/conversion/time.h> | |||
| using namespace ::cppcore; | |||
| TEST(time_tests, duration_to_timespec) | |||
| { | |||
| auto ts1 = duration_cast<timespec>(std::chrono::milliseconds(123456)); | |||
| EXPECT_EQ(123, ts1.tv_sec); | |||
| EXPECT_EQ(456000000, ts1.tv_nsec); | |||
| } | |||
| TEST(time_tests, duration_to_timeval) | |||
| { | |||
| auto tv1 = duration_cast<timeval>(std::chrono::milliseconds(123456)); | |||
| EXPECT_EQ(123, tv1.tv_sec); | |||
| EXPECT_EQ(456000, tv1.tv_usec); | |||
| } | |||
| TEST(time_tests, timespec_to_duration) | |||
| { | |||
| auto d1 = duration_cast<std::chrono::microseconds>(timespec{ 1, 234567890 }); | |||
| EXPECT_EQ(1234567, d1.count()); | |||
| } | |||
| TEST(time_tests, timeval_to_duration) | |||
| { | |||
| auto d1 = duration_cast<std::chrono::microseconds>(timeval{ 1, 234567 }); | |||
| EXPECT_EQ(1234567, d1.count()); | |||
| } | |||
| @@ -0,0 +1,101 @@ | |||
| #include <gtest/gtest.h> | |||
| #include <cppcore/misc/flags.h> | |||
| using namespace ::cppcore; | |||
| using namespace ::testing; | |||
| enum class TestFlag : uint8_t | |||
| { | |||
| value0, | |||
| value1, | |||
| value2, | |||
| value3, | |||
| value4 | |||
| }; | |||
| using Testflags = shifted_flags<TestFlag>; | |||
| TEST(flags_tests, ctor) | |||
| { | |||
| Testflags f0; | |||
| EXPECT_EQ(0, f0()); | |||
| Testflags f1({ TestFlag::value1, TestFlag::value3 }); | |||
| EXPECT_EQ(10, f1()); | |||
| Testflags f2(f1); | |||
| EXPECT_EQ(10, f2()); | |||
| Testflags f3(TestFlag::value3); | |||
| EXPECT_EQ(8, f3()); | |||
| } | |||
| TEST(flags_tests, set) | |||
| { | |||
| Testflags f; | |||
| EXPECT_FALSE(static_cast<bool>(f)); | |||
| f.set(TestFlag::value1); | |||
| EXPECT_TRUE(static_cast<bool>(f)); | |||
| EXPECT_TRUE(f[TestFlag::value1]); | |||
| } | |||
| TEST(flags_tests, is_set) | |||
| { | |||
| Testflags f({ TestFlag::value1, TestFlag::value3 }); | |||
| EXPECT_FALSE(f[TestFlag::value0]); | |||
| EXPECT_TRUE (f[TestFlag::value1]); | |||
| EXPECT_FALSE(f[TestFlag::value2]); | |||
| EXPECT_TRUE (f[TestFlag::value3]); | |||
| EXPECT_FALSE(f[TestFlag::value4]); | |||
| EXPECT_FALSE(f.is_set(TestFlag::value0)); | |||
| EXPECT_TRUE (f.is_set(TestFlag::value1)); | |||
| EXPECT_FALSE(f.is_set(TestFlag::value2)); | |||
| EXPECT_TRUE (f.is_set(TestFlag::value3)); | |||
| EXPECT_FALSE(f.is_set(TestFlag::value4)); | |||
| } | |||
| TEST(flags_tests, clear) | |||
| { | |||
| Testflags f({ TestFlag::value1, TestFlag::value3 }); | |||
| f.clear(TestFlag::value1); | |||
| EXPECT_FALSE(f.is_set(TestFlag::value1)); | |||
| EXPECT_TRUE (f.is_set(TestFlag::value3)); | |||
| } | |||
| TEST(flags_tests, reset) | |||
| { | |||
| Testflags f({ TestFlag::value1, TestFlag::value3 }); | |||
| f.reset(); | |||
| EXPECT_FALSE(static_cast<bool>(f)); | |||
| } | |||
| TEST(flags_tests, iterator) | |||
| { | |||
| Testflags f({ TestFlag::value0, TestFlag::value1, TestFlag::value3 }); | |||
| auto it = f.begin(); | |||
| auto end = f.end(); | |||
| EXPECT_FALSE(it == end); | |||
| EXPECT_TRUE (it != end); | |||
| EXPECT_EQ (TestFlag::value0, *it); | |||
| ++it; | |||
| EXPECT_FALSE(it == end); | |||
| EXPECT_TRUE (it != end); | |||
| EXPECT_EQ (TestFlag::value1, *it); | |||
| ++it; | |||
| EXPECT_FALSE(it == end); | |||
| EXPECT_TRUE (it != end); | |||
| EXPECT_EQ (TestFlag::value3, *it); | |||
| ++it; | |||
| EXPECT_TRUE (it == end); | |||
| EXPECT_FALSE(it != end); | |||
| ++it; | |||
| EXPECT_TRUE (it == end); | |||
| EXPECT_FALSE(it != end); | |||
| } | |||
| @@ -0,0 +1,84 @@ | |||
| #include <gtest/gtest.h> | |||
| #include <cppcore/misc/stream.h> | |||
| namespace stream_helper_tests | |||
| { | |||
| struct SimpleStruct | |||
| { | |||
| uint32_t u32; | |||
| uint8_t u8; | |||
| } | |||
| __attribute__((__packed__)); | |||
| struct ManagedStruct | |||
| { | |||
| std::string s; | |||
| void serialize(std::ostream& os) const | |||
| { ::cppcore::stream_helper::write(os, s); } | |||
| void deserialize(std::istream& is) | |||
| { ::cppcore::stream_helper::read(is, s); } | |||
| }; | |||
| } | |||
| using namespace ::cppcore; | |||
| using namespace ::testing; | |||
| using namespace ::stream_helper_tests; | |||
| TEST(stream_tests, write_scalar) | |||
| { | |||
| std::ostringstream os; | |||
| stream_helper::write(os, static_cast<uint32_t>(0x12345678)); | |||
| EXPECT_EQ(std::string("\x78\x56\x34\x12", 4), os.str()); | |||
| } | |||
| TEST(stream_tests, write_string) | |||
| { | |||
| std::ostringstream os; | |||
| stream_helper::write(os, std::string("test")); | |||
| EXPECT_EQ(std::string("\x04\x00\x00\x00test", 8), os.str()); | |||
| } | |||
| TEST(stream_tests, write_simpleStruct) | |||
| { | |||
| std::ostringstream os; | |||
| stream_helper::write(os, SimpleStruct { 0x78563412, 5 }); | |||
| EXPECT_EQ(std::string("\x12\x34\x56\x78\x05", 5), os.str()); | |||
| } | |||
| TEST(stream_tests, write_managedStruct) | |||
| { | |||
| std::ostringstream os; | |||
| stream_helper::write(os, ManagedStruct { "test" }); | |||
| EXPECT_EQ(std::string("\x04\x00\x00\x00test", 8), os.str()); | |||
| } | |||
| TEST(stream_tests, read_scalar) | |||
| { | |||
| std::istringstream is(std::string("\x78\x56\x34\x12", 4)); | |||
| auto ret = stream_helper::read<uint32_t>(is); | |||
| EXPECT_EQ(0x12345678, ret); | |||
| } | |||
| TEST(stream_tests, read_string) | |||
| { | |||
| std::istringstream is(std::string("\x04\x00\x00\x00test", 8)); | |||
| auto ret = stream_helper::read<std::string>(is); | |||
| EXPECT_EQ(std::string("test"), ret); | |||
| } | |||
| TEST(stream_tests, read_simpleStruct) | |||
| { | |||
| std::istringstream is(std::string("\x12\x34\x56\x78\x05", 5)); | |||
| auto ret = stream_helper::read<SimpleStruct>(is); | |||
| EXPECT_EQ(0x78563412, ret.u32); | |||
| EXPECT_EQ(5, ret.u8); | |||
| } | |||
| TEST(stream_tests, read_managedStruct) | |||
| { | |||
| std::istringstream is(std::string("\x04\x00\x00\x00test", 8)); | |||
| auto ret = stream_helper::read<ManagedStruct>(is); | |||
| EXPECT_EQ(std::string("test"), ret.s); | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| #include <gtest/gtest.h> | |||
| #include <cppcore/threading/cancellation_token.h> | |||
| using namespace ::cppcore; | |||
| TEST(cancellation_token_tests, cancel) | |||
| { | |||
| cancellation_source<int> cancellation; | |||
| cancellation.throw_if_cancellation_requested(); | |||
| cancellation.cancel(5); | |||
| EXPECT_THROW(cancellation.throw_if_cancellation_requested(), data_cancellation_exception<int>); | |||
| } | |||