* Added options flags to hexdumpmaster
| @@ -10,7 +10,6 @@ | |||
| #define cppcore_define_enum_value_traits(enum, ...) \ | |||
| namespace cppcore { \ | |||
| namespace __impl { \ | |||
| template<> \ | |||
| struct enum_value_traits<enum, void> \ | |||
| { \ | |||
| @@ -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<typename T_enum, typename = void> | |||
| 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 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<typename T_enum, typename = void> | |||
| 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(); | |||
| }; | |||
| 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 = T_traits; | |||
| 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 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<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(); | |||
| }; | |||
| } | |||
| 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<T_enum>> | |||
| typename T_traits = 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 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. | |||
| * | |||
| @@ -5,80 +5,82 @@ | |||
| namespace cppcore | |||
| { | |||
| namespace __impl | |||
| /* enum_value_traits */ | |||
| template<typename T_enum, typename T_enable> | |||
| decltype(auto) enum_value_traits<T_enum, T_enable>::get_enum_values() | |||
| { | |||
| static const auto value = enum_value_vector_type(); | |||
| return value; | |||
| } | |||
| /* enum_value_traits */ | |||
| /* enum_conversion_traits */ | |||
| template<typename T_enum, typename T_enable> | |||
| decltype(auto) enum_value_traits<T_enum, T_enable>::get_enum_values() | |||
| { | |||
| static const auto value = enum_value_vector_type(); | |||
| return value; | |||
| } | |||
| 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; | |||
| } | |||
| /* enum_conversion_traits */ | |||
| 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> | |||
| ::get_enum_to_string_map() | |||
| 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) | |||
| { | |||
| static const auto value = create_enum_to_string_map(); | |||
| return value; | |||
| ret.emplace(p.first, p.second); | |||
| } | |||
| return ret; | |||
| } | |||
| template<typename T_enum, typename T_traits> | |||
| decltype(auto) enum_conversion_traits<T_enum, T_traits> | |||
| ::get_string_to_enum_map() | |||
| 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) | |||
| { | |||
| static const auto value = create_string_to_enum_map(); | |||
| return value; | |||
| ret.emplace(p.second, p.first); | |||
| } | |||
| return ret; | |||
| } | |||
| 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; | |||
| } | |||
| /* enum_conversion */ | |||
| 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; | |||
| } | |||
| template<typename T_enum, typename T_traits> | |||
| bool enum_conversion<T_enum, T_traits> | |||
| ::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<base_type>(value)) + ')'; | |||
| return true; | |||
| } | |||
| /* 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)) + ')'; | |||
| } | |||
| else | |||
| if (!try_to_string(value, ret, add_numeric_value)) | |||
| ret = std::to_string(static_cast<base_type>(value)); | |||
| return ret; | |||
| } | |||
| @@ -2,9 +2,19 @@ | |||
| #include <iostream> | |||
| #include <cppcore/misc/flags.h> | |||
| namespace cppcore | |||
| { | |||
| enum class hexdump_flag | |||
| { | |||
| unknown = 0, | |||
| print_header, | |||
| print_footer, | |||
| }; | |||
| using hexdump_flags = cppcore::shifted_flags<hexdump_flag>; | |||
| /** | |||
| * @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. | |||
| @@ -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); | |||
| } | |||
| } | |||
| } | |||
| @@ -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<enum_type, std::string>; | |||
| using enum_value_vector_type = std::vector<enum_value_pair_type>; | |||
| 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<TestEnum, custom_enum_value_traits>; | |||
| using custom_enum_conversion = cppcore::enum_conversion <TestEnum, custom_enum_conversion_traits>; | |||
| using namespace ::cppcore; | |||
| using namespace ::testing; | |||
| @@ -56,3 +76,11 @@ TEST(enum_tests, to_enum) | |||
| EXPECT_TRUE (enum_conversion<TestEnum>::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)); | |||
| } | |||