[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:
Christopher Warrington 2016-08-22 18:23:26 -07:00
Родитель 5e673765aa
Коммит 9747a8d5ce
12 изменённых файлов: 177 добавлений и 37 удалений

Просмотреть файл

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