From 22c45564f6fe2419dd4e72fd704cd151a598d6f9 Mon Sep 17 00:00:00 2001 From: bergmann Date: Tue, 3 Sep 2019 22:40:31 +0200 Subject: [PATCH] * Fixed bug in enum conversion (custom defined enum conversion traits are ignored) * Added options flags to hexdump --- include/cppcore/conversion/enum.h | 123 +++++++++++++------------ include/cppcore/conversion/enum.inl | 110 +++++++++++----------- include/cppcore/misc/hexdump.h | 23 ++++- include/cppcore/misc/hexdump.inl | 30 +++++- test/cppcore/conversion/enum_tests.cpp | 28 ++++++ 5 files changed, 193 insertions(+), 121 deletions(-) diff --git a/include/cppcore/conversion/enum.h b/include/cppcore/conversion/enum.h index d9cc0ee..99c3163 100644 --- a/include/cppcore/conversion/enum.h +++ b/include/cppcore/conversion/enum.h @@ -10,7 +10,6 @@ #define cppcore_define_enum_value_traits(enum, ...) \ namespace cppcore { \ - namespace __impl { \ template<> \ struct enum_value_traits \ { \ @@ -25,72 +24,67 @@ }); \ 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 + struct enum_value_traits { + using enum_type = T_enum; + using enum_value_pair_type = std::pair; + using enum_value_vector_type = std::vector; /** - * @brief Traits class to strore enum to string pairs and the needed data types. - * - * @tparam T_enum Enum type. + * @brief Returns a vector with all enum to string value paris. */ - template - struct enum_value_traits - { - using enum_type = T_enum; - using enum_value_pair_type = std::pair; - using enum_value_vector_type = std::vector; - - /** - * @brief Returns a vector with all enum to string value paris. - */ - static decltype(auto) get_enum_values(); - }; + 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> + struct enum_conversion_traits + { + public: + using enum_type = T_enum; + using traits_type = T_traits; + using enum_to_string_map_type = std::map; + using string_to_enum_map_type = std::map; /** - * @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. + * @brief Returns a map with enum to string values. */ - template< - typename T_enum, - typename T_traits = enum_value_traits> - struct enum_conversion_traits - { - public: - using enum_type = T_enum; - using traits_type = enum_value_traits; - using enum_to_string_map_type = std::map; - using string_to_enum_map_type = std::map; - - /** - * @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(); - }; - - } + 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. @@ -100,13 +94,28 @@ namespace cppcore */ template< typename T_enum, - typename T_traits = __impl::enum_conversion_traits> + typename T_traits = enum_conversion_traits> struct enum_conversion { using enum_type = T_enum; using base_type = typename std::underlying_type::type; using traits_type = T_traits; + /** + * @brief Try to convert the given enum value to a string. + * + * @param[in] value Enum value to convert to string. + * @param[out] str Enum value converted to string. + * @param[in] add_numeric_value Append the numeric value to the converted enum value. + * + * @retval true If the conversion was successfull. + * @retval false If the enum could not be converted. + */ + static inline bool try_to_string( + enum_type value, + std::string& str, + bool add_numeric_value = false); + /** * @brief Convert the given enum value to a string. * diff --git a/include/cppcore/conversion/enum.inl b/include/cppcore/conversion/enum.inl index 301938c..628a158 100644 --- a/include/cppcore/conversion/enum.inl +++ b/include/cppcore/conversion/enum.inl @@ -5,80 +5,82 @@ namespace cppcore { - namespace __impl + /* enum_value_traits */ + + template + decltype(auto) enum_value_traits::get_enum_values() { + static const auto value = enum_value_vector_type(); + return value; + } - /* enum_value_traits */ + /* enum_conversion_traits */ - template - decltype(auto) enum_value_traits::get_enum_values() - { - static const auto value = enum_value_vector_type(); - return value; - } + template + decltype(auto) enum_conversion_traits + ::get_enum_to_string_map() + { + static const auto value = create_enum_to_string_map(); + return value; + } - /* enum_conversion_traits */ + template + decltype(auto) enum_conversion_traits + ::get_string_to_enum_map() + { + static const auto value = create_string_to_enum_map(); + return value; + } - template - decltype(auto) enum_conversion_traits - ::get_enum_to_string_map() + template + decltype(auto) enum_conversion_traits + ::create_enum_to_string_map() + { + auto& values = traits_type::get_enum_values(); + enum_to_string_map_type ret; + for (auto& p : values) { - static const auto value = create_enum_to_string_map(); - return value; + ret.emplace(p.first, p.second); } + return ret; + } - template - decltype(auto) enum_conversion_traits - ::get_string_to_enum_map() + template + decltype(auto) enum_conversion_traits + ::create_string_to_enum_map() + { + auto& values = traits_type::get_enum_values(); + string_to_enum_map_type ret; + for (auto& p : values) { - static const auto value = create_string_to_enum_map(); - return value; + ret.emplace(p.second, p.first); } + return ret; + } - template - decltype(auto) enum_conversion_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; - } + /* enum_conversion */ - template - decltype(auto) enum_conversion_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; - } + template + bool enum_conversion + ::try_to_string(enum_type value, std::string& str, bool add_numeric_value) + { + auto& map = traits_type::get_enum_to_string_map(); + auto it = map.find(value); + if (it == map.end()) + return false; + str = it->second; + if (add_numeric_value) + str += '(' + std::to_string(static_cast(value)) + ')'; + return true; } - /* enum_conversion */ - template std::string enum_conversion ::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(value)) + ')'; - } - else + if (!try_to_string(value, ret, add_numeric_value)) ret = std::to_string(static_cast(value)); return ret; } diff --git a/include/cppcore/misc/hexdump.h b/include/cppcore/misc/hexdump.h index d200c19..de6fd05 100644 --- a/include/cppcore/misc/hexdump.h +++ b/include/cppcore/misc/hexdump.h @@ -2,9 +2,19 @@ #include +#include + namespace cppcore { + enum class hexdump_flag + { + unknown = 0, + print_header, + print_footer, + }; + using hexdump_flags = cppcore::shifted_flags; + /** * @brief Helper class to print hexdumps. */ @@ -15,6 +25,7 @@ namespace cppcore size_t offset; //!< Offset to start numbering at (this will not affect the passed data pointer). size_t split; //!< Add extra colum after specified number of bytes. size_t newline; //!< Add new line after specified number of bytes. + hexdump_flags flags; //!< Flags with additional options. /** * Constructor. @@ -24,13 +35,15 @@ namespace cppcore * @param[in] p_offset Offset to start numbering at (this will not affect the passed data pointer). * @param[in] p_split Add extra colum after specified number of bytes. * @param[in] p_newline Add new line after specified number of bytes. + * @param[in] p_flags Flags with additional options. */ inline hexdump( - const void * p_data, - size_t p_len, - size_t p_offset = 0, - size_t p_split = 8, - size_t p_newline = 16); + const void * p_data, + size_t p_len, + size_t p_offset = 0, + size_t p_split = 8, + size_t p_newline = 16, + const hexdump_flags& p_flags = hexdump_flags::empty()); /** * @pbrief Print the hexdump to the passed stream. diff --git a/include/cppcore/misc/hexdump.inl b/include/cppcore/misc/hexdump.inl index 74a873f..ffa781b 100644 --- a/include/cppcore/misc/hexdump.inl +++ b/include/cppcore/misc/hexdump.inl @@ -10,16 +10,18 @@ namespace cppcore /* hexdump */ hexdump::hexdump( - const void * p_data, - size_t p_len, - size_t p_offset, - size_t p_split, - size_t p_newline) + const void * p_data, + size_t p_len, + size_t p_offset, + size_t p_split, + size_t p_newline, + const hexdump_flags& p_flags) : data (p_data) , len (p_len) , offset (p_offset) , split (p_split) , newline (p_newline) + , flags (p_flags) { } void hexdump::print(std::ostream& os) const @@ -31,6 +33,18 @@ namespace cppcore size_t l = 0; std::string s; + if (flags.is_set(hexdump_flag::print_header)) + { + os << " "; + for (size_t x = 0; x < newline; ++x) + { + if (x % split == 0) + os.put(' '); + os << " " << hex << setw(2) << setfill('0') << x; + } + os << std::endl; + } + while (i < len) { if (i % newline == 0) @@ -69,6 +83,12 @@ namespace cppcore os << std::string(3 * rest + fill, ' ') << " " << s << std::string(rest + fill, ' ') << "|"; } + + if (flags.is_set(hexdump_flag::print_footer)) + { + os << std::endl + << hex << setw(8) << setfill('0') << (offset + len); + } } } diff --git a/test/cppcore/conversion/enum_tests.cpp b/test/cppcore/conversion/enum_tests.cpp index 70531e0..e2e2d80 100644 --- a/test/cppcore/conversion/enum_tests.cpp +++ b/test/cppcore/conversion/enum_tests.cpp @@ -18,6 +18,26 @@ cppcore_define_enum_value_traits( { TestEnum::Test3, "Test3" } ); +struct custom_enum_value_traits +{ + using enum_type = TestEnum; + using enum_value_pair_type = std::pair; + using enum_value_vector_type = std::vector; + + static const enum_value_vector_type& get_enum_values() + { + static const enum_value_vector_type value({ + { TestEnum::Test0, "Fuuu0" }, + { TestEnum::Test1, "Fuuu1" }, + { TestEnum::Test2, "Fuuu2" }, + { TestEnum::Test3, "Fuuu3" } + }); + return value; + } +}; +using custom_enum_conversion_traits = cppcore::enum_conversion_traits; +using custom_enum_conversion = cppcore::enum_conversion ; + using namespace ::cppcore; using namespace ::testing; @@ -56,3 +76,11 @@ TEST(enum_tests, to_enum) EXPECT_TRUE (enum_conversion::try_to_enum("2", e, true)); EXPECT_EQ (TestEnum::Test2, e); } + +TEST(enum_tests, custom_traits) +{ + EXPECT_EQ("Fuuu0", custom_enum_conversion::to_string(TestEnum::Test0)); + EXPECT_EQ("Fuuu1", custom_enum_conversion::to_string(TestEnum::Test1)); + EXPECT_EQ("Fuuu2", custom_enum_conversion::to_string(TestEnum::Test2)); + EXPECT_EQ("Fuuu3", custom_enum_conversion::to_string(TestEnum::Test3)); +}