Преглед изворни кода

* Fixed bug in enum conversion (custom defined enum conversion traits are ignored)

* Added options flags to hexdump
master
bergmann пре 6 година
родитељ
комит
22c45564f6
5 измењених фајлова са 193 додато и 121 уклоњено
  1. +66
    -57
      include/cppcore/conversion/enum.h
  2. +56
    -54
      include/cppcore/conversion/enum.inl
  3. +18
    -5
      include/cppcore/misc/hexdump.h
  4. +25
    -5
      include/cppcore/misc/hexdump.inl
  5. +28
    -0
      test/cppcore/conversion/enum_tests.cpp

+ 66
- 57
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<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.
*


+ 56
- 54
include/cppcore/conversion/enum.inl Прегледај датотеку

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


+ 18
- 5
include/cppcore/misc/hexdump.h Прегледај датотеку

@@ -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.


+ 25
- 5
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);
}
}

}


+ 28
- 0
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<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));
}

Loading…
Откажи
Сачувај