| @@ -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>); | |||||
| } | |||||