[c++] Generate FromEnum for string conversions
* Generated enum types now have a `FromEnum` method that can be used to convert from an enum value to a string. Now generated enum types have all four of `ToEnum`, `FromEnum`, `ToString`, and `FromString`. (The `...Enum` variants return false on failure, while the `...String` variants throw.) * enumerations example updated to demonstrate all four of these functions. * Existing throwing `FromString` re-implemented in terms of non-throwing `ToEnum`. * `ToString` is intentionally not implemented in terms of `FromEnum`, as `ToString` returns a reference to the name stored in the map. `FromEnum` copies this name into the output paramater. Fixes https://github.com/Microsoft/bond/pull/223
This commit is contained in:
Родитель
5e673765aa
Коммит
9747a8d5ce
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -11,6 +11,21 @@ tag versions. The Bond compiler (`gbc`) and
|
|||
different versioning scheme, following the Haskell community's
|
||||
[package versioning policy](https://wiki.haskell.org/Package_versioning_policy).
|
||||
|
||||
## Unreleased ##
|
||||
|
||||
* `gbc` & compiler library: minor bump needed
|
||||
* IDL core version: TBD
|
||||
* IDL comm version: TBD
|
||||
* C++ version: minor bump needed
|
||||
* C# NuGet version: TBD
|
||||
* C# Comm NuGet version: TBD
|
||||
|
||||
### C++ ###
|
||||
* Generated enum types now have a `FromEnum` method that can be used to
|
||||
convert from an enum value to a string. Now generated enum types have all
|
||||
four of `ToEnum`, `FromEnum`, `ToString`, and `FromString`. (The `...Enum`
|
||||
variants return false on failure, while the `...String` variants throw.)
|
||||
|
||||
## 4.3.0: 2016-08-23 ##
|
||||
|
||||
* `gbc` & compiler library: 0.5.0.0
|
||||
|
|
|
@ -31,6 +31,10 @@ types_cpp cpp file _imports declarations = ("_types.cpp", [lt|
|
|||
if null declParams then CPP.schemaMetadata cpp s else mempty
|
||||
|
||||
-- global variables for enum name/value conversions
|
||||
--
|
||||
-- ToString is intentionally not implemented in terms of FromEnum, as
|
||||
-- ToString returns a reference to the name stored in the map. FromEnum
|
||||
-- copies this name into the output paramater.
|
||||
statics Enum {..} = [lt|
|
||||
namespace _bond_enumerators
|
||||
{
|
||||
|
@ -58,15 +62,9 @@ types_cpp cpp file _imports declarations = ("_types.cpp", [lt|
|
|||
|
||||
void FromString(const std::string& name, enum #{declName}& value)
|
||||
{
|
||||
std::map<std::string, enum #{declName}>::const_iterator it =
|
||||
_name_to_value_#{declName}.find(name);
|
||||
|
||||
if (_name_to_value_#{declName}.end() == it)
|
||||
if (!ToEnum(value, name))
|
||||
bond::InvalidEnumValueException(name.c_str(), "#{declName}");
|
||||
|
||||
value = it->second;
|
||||
}
|
||||
|
||||
} // namespace #{declName}
|
||||
} // namespace _bond_enumerators|]
|
||||
where
|
||||
|
|
|
@ -373,6 +373,20 @@ namespace std
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool FromEnum(std::string& name, enum #{declName} value)
|
||||
{
|
||||
std::map<enum #{declName}, std::string>::const_iterator it =
|
||||
_value_to_name_#{declName}.find(value);
|
||||
|
||||
if (_value_to_name_#{declName}.end() == it)
|
||||
return false;
|
||||
|
||||
name = it->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace #{declName}
|
||||
} // namespace _bond_enumerators
|
||||
|
||||
|
|
|
@ -31,15 +31,9 @@ namespace tests
|
|||
|
||||
void FromString(const std::string& name, enum Enum& value)
|
||||
{
|
||||
std::map<std::string, enum Enum>::const_iterator it =
|
||||
_name_to_value_Enum.find(name);
|
||||
|
||||
if (_name_to_value_Enum.end() == it)
|
||||
if (!ToEnum(value, name))
|
||||
bond::InvalidEnumValueException(name.c_str(), "Enum");
|
||||
|
||||
value = it->second;
|
||||
}
|
||||
|
||||
} // namespace Enum
|
||||
} // namespace _bond_enumerators
|
||||
|
||||
|
|
|
@ -74,6 +74,20 @@ namespace tests
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool FromEnum(std::string& name, enum Enum value)
|
||||
{
|
||||
std::map<enum Enum, std::string>::const_iterator it =
|
||||
_value_to_name_Enum.find(value);
|
||||
|
||||
if (_value_to_name_Enum.end() == it)
|
||||
return false;
|
||||
|
||||
name = it->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace Enum
|
||||
} // namespace _bond_enumerators
|
||||
|
||||
|
|
|
@ -41,15 +41,9 @@ namespace tests
|
|||
|
||||
void FromString(const std::string& name, enum EnumType1& value)
|
||||
{
|
||||
std::map<std::string, enum EnumType1>::const_iterator it =
|
||||
_name_to_value_EnumType1.find(name);
|
||||
|
||||
if (_name_to_value_EnumType1.end() == it)
|
||||
if (!ToEnum(value, name))
|
||||
bond::InvalidEnumValueException(name.c_str(), "EnumType1");
|
||||
|
||||
value = it->second;
|
||||
}
|
||||
|
||||
} // namespace EnumType1
|
||||
} // namespace _bond_enumerators
|
||||
|
||||
|
|
|
@ -84,6 +84,20 @@ namespace tests
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool FromEnum(std::string& name, enum EnumType1 value)
|
||||
{
|
||||
std::map<enum EnumType1, std::string>::const_iterator it =
|
||||
_value_to_name_EnumType1.find(value);
|
||||
|
||||
if (_value_to_name_EnumType1.end() == it)
|
||||
return false;
|
||||
|
||||
name = it->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace EnumType1
|
||||
} // namespace _bond_enumerators
|
||||
|
||||
|
|
|
@ -31,15 +31,9 @@ namespace tests
|
|||
|
||||
void FromString(const std::string& name, enum Enum& value)
|
||||
{
|
||||
std::map<std::string, enum Enum>::const_iterator it =
|
||||
_name_to_value_Enum.find(name);
|
||||
|
||||
if (_name_to_value_Enum.end() == it)
|
||||
if (!ToEnum(value, name))
|
||||
bond::InvalidEnumValueException(name.c_str(), "Enum");
|
||||
|
||||
value = it->second;
|
||||
}
|
||||
|
||||
} // namespace Enum
|
||||
} // namespace _bond_enumerators
|
||||
|
||||
|
|
|
@ -74,6 +74,20 @@ namespace tests
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool FromEnum(std::string& name, enum Enum value)
|
||||
{
|
||||
std::map<enum Enum, std::string>::const_iterator it =
|
||||
_value_to_name_Enum.find(value);
|
||||
|
||||
if (_value_to_name_Enum.end() == it)
|
||||
return false;
|
||||
|
||||
name = it->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace Enum
|
||||
} // namespace _bond_enumerators
|
||||
|
||||
|
|
|
@ -41,15 +41,9 @@ namespace tests
|
|||
|
||||
void FromString(const std::string& name, enum EnumType1& value)
|
||||
{
|
||||
std::map<std::string, enum EnumType1>::const_iterator it =
|
||||
_name_to_value_EnumType1.find(name);
|
||||
|
||||
if (_name_to_value_EnumType1.end() == it)
|
||||
if (!ToEnum(value, name))
|
||||
bond::InvalidEnumValueException(name.c_str(), "EnumType1");
|
||||
|
||||
value = it->second;
|
||||
}
|
||||
|
||||
} // namespace EnumType1
|
||||
} // namespace _bond_enumerators
|
||||
|
||||
|
|
|
@ -84,6 +84,20 @@ namespace tests
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool FromEnum(std::string& name, enum EnumType1 value)
|
||||
{
|
||||
std::map<enum EnumType1, std::string>::const_iterator it =
|
||||
_value_to_name_EnumType1.find(value);
|
||||
|
||||
if (_value_to_name_EnumType1.end() == it)
|
||||
return false;
|
||||
|
||||
name = it->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace EnumType1
|
||||
} // namespace _bond_enumerators
|
||||
|
||||
|
|
|
@ -1,13 +1,34 @@
|
|||
#include <cassert>
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
#include <bond/core/exception.h>
|
||||
|
||||
#include "enumerations_enum.h"
|
||||
#include "enumerations_types.h"
|
||||
|
||||
using namespace examples::enumerations;
|
||||
|
||||
static void DisambiguateEnumsWithSameName();
|
||||
static void EnumValueLimits();
|
||||
static void ConversionToFromEnum();
|
||||
static void ConversionsToFromString();
|
||||
|
||||
int main()
|
||||
{
|
||||
DisambiguateEnumsWithSameName();
|
||||
EnumValueLimits();
|
||||
ConversionToFromEnum();
|
||||
ConversionsToFromString();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Bond provides a standard-compliant solution for scoped enumerations in
|
||||
// C++ that overcomes the limitations of normal C++ enumeration types.
|
||||
void DisambiguateEnumsWithSameName()
|
||||
{
|
||||
// Both Color and Fruit have a value named Orange.
|
||||
|
||||
Color color;
|
||||
|
||||
color = Color::Orange;
|
||||
|
@ -17,11 +38,71 @@ int main()
|
|||
|
||||
fruit = Apple;
|
||||
fruit = Fruit::Orange;
|
||||
}
|
||||
|
||||
// Bond enums are represented as signed 32-bit integers on the wire, but
|
||||
// implicit conversions allow the comparison to uint32_t values.
|
||||
void EnumValueLimits()
|
||||
{
|
||||
assert(Limits::Int32Min == std::numeric_limits<int32_t>::min());
|
||||
assert(Limits::Int32Max == std::numeric_limits<int32_t>::max());
|
||||
assert(Limits::UInt32Min == std::numeric_limits<uint32_t>::min());
|
||||
assert(Limits::UInt32Max == std::numeric_limits<uint32_t>::max());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The ToEnum and FromEnum functions can be used to convert between enum
|
||||
// values and their names. ToEnum and FromEnum return a bool indicating
|
||||
// whether they were successful or not.
|
||||
void ConversionToFromEnum()
|
||||
{
|
||||
std::string name;
|
||||
bool result = FromEnum(name, Yellow);
|
||||
assert(result);
|
||||
assert(name == "Yellow");
|
||||
|
||||
result = FromEnum(name, static_cast<Color>(100));
|
||||
assert(!result);
|
||||
|
||||
Color value;
|
||||
result = ToEnum(value, "Yellow");
|
||||
assert(result);
|
||||
assert(value == Yellow);
|
||||
|
||||
result = ToEnum(value, "Green");
|
||||
assert(!result);
|
||||
}
|
||||
|
||||
// The ToString and FromString functions can be used to convert between enum
|
||||
// values and their names. ToString and FromString throw when they encounter
|
||||
// things they cannot convert.
|
||||
void ConversionsToFromString()
|
||||
{
|
||||
std::string name = ToString(Yellow);
|
||||
assert(name == "Yellow");
|
||||
|
||||
try
|
||||
{
|
||||
name = ToString(static_cast<Color>(100));
|
||||
assert(false); // expected exception
|
||||
}
|
||||
catch (const bond::CoreException&)
|
||||
{
|
||||
// ToString throws on unknown values. FromEnum is a non-throwing
|
||||
// alternative.
|
||||
}
|
||||
|
||||
Color value;
|
||||
FromString("Yellow", value);
|
||||
assert(value == Yellow);
|
||||
|
||||
try
|
||||
{
|
||||
FromString("Green", value);
|
||||
assert(false); // expected exception
|
||||
}
|
||||
catch (const bond::CoreException&)
|
||||
{
|
||||
// FromString throws on unknown names. ToEnum is a non-throwing
|
||||
// alternative.
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче