Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
enum_cast as a simple and consistent way of casting from enums to strings and back the other way.
- Loading branch information
Richard Mills
committed
Aug 6, 2019
1 parent
6cb6016
commit cc10f4b
Showing
5 changed files
with
164 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// Copyright (c) 2019 Bitcoin Association. | ||
// Distributed under the Open BSV software license, see the accompanying file LICENSE. | ||
|
||
/* | ||
* A general purpose mechanism for casting between enums and strings. | ||
* | ||
* Given an enumeration, we also provide a function enumTable() that returns | ||
* an enumTableT specifying a mapping between the enumeration and the | ||
* castable string values. With that in place we can perform casting with | ||
* enum_cast<Enum>(string) or enum_cast<string>(Enum). | ||
* | ||
* Eg: | ||
* | ||
* enum class MyTypes { UNKNOWN, Type1, Type2 }; | ||
* | ||
* const enumTableT<MyTypes, std::string>& enumTable(MyTypes, std::string) | ||
* { | ||
* static enumTableT<MyTypes, std::string> table | ||
* { | ||
* {MyTypes::UNKNOWN, "Unknown"}, {MyTypes::Type1, "Type 1"}, {MyTypes::Type2, "Type 2"} | ||
* }; | ||
* return table; | ||
* } | ||
* | ||
* std::string str { enum_cast<std::string>(MyTypes::Type1) }; | ||
* MyTypes mytype { enum_cast<MyTypes>(str) }; | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <string> | ||
#include <unordered_map> | ||
|
||
// The type returned by all enum_table() functions. | ||
template <typename From> | ||
class enumTableT | ||
{ | ||
public: | ||
|
||
// Constructor - requires table.size() > 0 | ||
enumTableT(std::initializer_list<std::pair<const From, std::string>> table) | ||
: mLookupTable{table}, mDefaultValue{*table.begin()} | ||
{ | ||
// Populate reverse lookup table | ||
for(const auto& item : mLookupTable) | ||
{ | ||
mReverseLookupTable[item.second] = item.first; | ||
} | ||
} | ||
|
||
// Cast from enum to string | ||
template <typename CastType> | ||
const std::string& castToString(const CastType& from) const | ||
{ | ||
auto it { mLookupTable.find(from) }; | ||
if(it != mLookupTable.end()) | ||
{ | ||
return it->second; | ||
} | ||
return mDefaultValue.second; | ||
} | ||
|
||
// Cast from string to enum | ||
template <typename CastType> | ||
const From& castToEnum(const CastType& to) const | ||
{ | ||
auto it { mReverseLookupTable.find(to) }; | ||
if(it != mReverseLookupTable.end()) | ||
{ | ||
return it->second; | ||
} | ||
return mDefaultValue.first; | ||
} | ||
|
||
private: | ||
|
||
using LookupTable = std::unordered_map<From, std::string>; | ||
using ReverseLookupTable = std::unordered_map<std::string, From>; | ||
|
||
LookupTable mLookupTable {}; | ||
ReverseLookupTable mReverseLookupTable {}; | ||
typename LookupTable::value_type mDefaultValue {}; | ||
|
||
}; | ||
|
||
// Cast to string | ||
template<typename ToType = std::string, typename FromType> | ||
std::string enum_cast(const FromType& value) | ||
{ | ||
return enumTable(FromType{}).castToString(value); | ||
} | ||
|
||
// Cast from string | ||
template<typename ToType> | ||
ToType enum_cast(const std::string& value) | ||
{ | ||
return enumTable(ToType{}).castToEnum(value); | ||
} | ||
|
||
// Cast from convertable to string | ||
template<typename ToType> | ||
ToType enum_cast(const char* value) | ||
{ | ||
return enumTable(ToType{}).castToEnum(value); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Copyright (c) 2019 Bitcoin Association. | ||
// Distributed under the Open BSV software license, see the accompanying file LICENSE. | ||
|
||
#include "enum_cast.h" | ||
#include <boost/test/unit_test.hpp> | ||
|
||
namespace | ||
{ | ||
// Table for casting to/from string | ||
enum class MyTypesCorrect { UNKNOWN, Type1, Type2 }; | ||
const enumTableT<MyTypesCorrect>& enumTable(MyTypesCorrect) | ||
{ | ||
static enumTableT<MyTypesCorrect> table | ||
{ | ||
{MyTypesCorrect::UNKNOWN, "Unknown"}, {MyTypesCorrect::Type1, "Type 1"}, {MyTypesCorrect::Type2, "Type 2"} | ||
}; | ||
return table; | ||
} | ||
|
||
// Output operator | ||
std::ostream& operator<<(std::ostream& str, MyTypesCorrect mytype) | ||
{ | ||
str << enum_cast<std::string>(mytype); | ||
return str; | ||
} | ||
} | ||
|
||
BOOST_AUTO_TEST_SUITE(TestEnumCast); | ||
|
||
// Test normal (correct) operation of enum_cast | ||
BOOST_AUTO_TEST_CASE(TestCorrectEnumCast) | ||
{ | ||
// Cast from existing string and back (non-fundamental type) | ||
std::string str { "Type 1" }; | ||
MyTypesCorrect myType { enum_cast<MyTypesCorrect>(str) }; | ||
BOOST_CHECK_EQUAL(myType, MyTypesCorrect::Type1); | ||
str = enum_cast<std::string>(myType); | ||
BOOST_CHECK_EQUAL(str, "Type 1"); | ||
|
||
// Cast from convertable to string | ||
myType = enum_cast<MyTypesCorrect>("Type 1"); | ||
BOOST_CHECK_EQUAL(myType, MyTypesCorrect::Type1); | ||
} | ||
|
||
// Test UNKNOWN casting | ||
BOOST_AUTO_TEST_CASE(TestUnknownEnumCast) | ||
{ | ||
// Cast to MyTypes from unknown string | ||
std::string str { "Wibble" }; | ||
MyTypesCorrect myType { enum_cast<MyTypesCorrect>(str) }; | ||
BOOST_CHECK_EQUAL(myType, MyTypesCorrect::UNKNOWN); | ||
} | ||
|
||
BOOST_AUTO_TEST_SUITE_END(); | ||
|