better-enums/test/cxxtest/underlying.h
Anton Bachin 4314ad3fd3 Experimental generalization of underlying types.
With this change, the underlying type can be a non-integral type that
provides conversions to and from an integral type. See the test at
test/cxxtest/underlying.h for some examples - though they are more
verbose than strictly necessary, for testing needs.

Move constructors in underlying types are not supported. It has been
difficult so far to get constexpr code not to select the move
constructor, which is generally not constexpr, for various operations.
2015-06-11 20:39:46 -05:00

155 lines
4.7 KiB
C++

#include <cxxtest/TestSuite.h>
#include <enum.h>
// This test uses internal constants declared by feature testing macros in
// enum.h. They are not part of the public interface, but are used here to avoid
// duplication of definitions for C++11 and C++98.
//
// BETTER_ENUMS__CONSTEXPR is a synonym for constexpr when available, and
// othewise expands to nothing.
// Using a type trait.
struct html_color_1 {
unsigned char r, g, b;
BETTER_ENUMS__CONSTEXPR
html_color_1(unsigned char _r, unsigned char _g, unsigned char _b) :
r(_r), g(_g), b(_b) { }
};
// In C++11, can simply to struct ::better_enums::underlying_traits below.
namespace better_enums {
template <>
struct underlying_traits<html_color_1> {
typedef unsigned int integral_representation;
BETTER_ENUMS__CONSTEXPR static html_color_1 from_integral(unsigned int i)
{ return html_color_1(i >> 16 & 0xff, i >> 8 & 0xff, i & 0xff); }
BETTER_ENUMS__CONSTEXPR static unsigned int to_integral(html_color_1 v)
{ return (unsigned int)v.r << 16 | (unsigned int)v.g << 8 | v.b; }
BETTER_ENUMS__CONSTEXPR static bool
are_equal(const html_color_1 &u, const html_color_1 &v)
{ return u.r == v.r && u.g == v.g && u.b == v.b; }
};
}
ENUM(HtmlColor1, html_color_1,
darksalmon = 0xc47451, purplemimosa = 0x9e7bff, slimegreen = 0xbce954)
// Using member definitions.
struct html_color_2 {
unsigned char r, g, b;
BETTER_ENUMS__CONSTEXPR
html_color_2(unsigned char _r, unsigned char _g, unsigned char _b) :
r(_r), g(_g), b(_b) { }
typedef unsigned int integral_representation;
explicit BETTER_ENUMS__CONSTEXPR html_color_2(unsigned int i) :
r(i >> 16 & 0xff), g(i >> 8 & 0xff), b(i & 0xff) { }
BETTER_ENUMS__CONSTEXPR operator unsigned int() const
{ return (unsigned int)r << 16 | (unsigned int)g << 8 | b; }
};
// Initializers are not supported before GCC 5.1, even with a literal type and
// constexpr conversion to integer.
#ifdef BETTER_ENUMS__HAVE_CONSTEXPR
# ifdef __GNUC__
# ifdef __clang__
# define SUPPORT_INITIALIZER
# else
# if __GNUC__ >= 5
# define SUPPORT_INITIALIZER
# endif
# endif
# endif
#endif
#ifdef SUPPORT_INITIALIZER
ENUM(HtmlColor2, html_color_2,
darksalmon = 0xc47451, purplemimosa = 0x9e7bff, slimegreen = 0xbce954,
celeste = html_color_2(0x50, 0xeb, 0xec))
#else
ENUM(HtmlColor2, html_color_2,
darksalmon = 0xc47451, purplemimosa = 0x9e7bff, slimegreen = 0xbce954)
#endif
class UnderlyingTypeTests : public CxxTest::TestSuite {
public:
void test_basics_and_operators()
{
HtmlColor1 color_1 = HtmlColor1::darksalmon;
TS_ASSERT_EQUALS(color_1->r, 0xc4);
TS_ASSERT_EQUALS(color_1->g, 0x74);
TS_ASSERT_EQUALS(color_1->b, 0x51);
TS_ASSERT_EQUALS(sizeof(HtmlColor1), sizeof(html_color_1));
HtmlColor2 color_2 = HtmlColor2::purplemimosa;
TS_ASSERT_EQUALS(color_2->r, 0x9e);
TS_ASSERT_EQUALS(color_2->g, 0x7b);
TS_ASSERT_EQUALS(color_2->b, 0xff);
TS_ASSERT_EQUALS(sizeof(HtmlColor2), sizeof(html_color_2));
#ifdef SUPPORT_INITIALIZER
HtmlColor2 color_3 = HtmlColor2::celeste;
TS_ASSERT_EQUALS(color_3->r, 0x50);
TS_ASSERT_EQUALS(color_3->g, 0xeb);
TS_ASSERT_EQUALS(color_3->b, 0xec);
#endif
color_1->r = 0;
const HtmlColor1 const_color = HtmlColor1::slimegreen;
TS_ASSERT_EQUALS(const_color->r, 0xbc);
html_color_1 &color_1_reference = *color_1;
const html_color_1 &const_color_reference = *const_color;
TS_ASSERT_EQUALS(color_1_reference.r, 0);
TS_ASSERT_EQUALS(const_color_reference.r, 0xbc);
}
void test_conversion_functions()
{
HtmlColor2 color_1 = HtmlColor2::darksalmon;
html_color_2 color_1_underlying = color_1._to_underlying();
TS_ASSERT_EQUALS(color_1_underlying.r, color_1->r);
TS_ASSERT_EQUALS(color_1_underlying.g, color_1->g);
TS_ASSERT_EQUALS(color_1_underlying.b, color_1->b);
color_1_underlying = html_color_2(HtmlColor2::slimegreen);
color_1 = HtmlColor2::_from_underlying(color_1_underlying);
TS_ASSERT_EQUALS(color_1->r, color_1_underlying.r);
TS_ASSERT_EQUALS(color_1->g, color_1_underlying.g);
TS_ASSERT_EQUALS(color_1->b, color_1_underlying.b);
color_1_underlying = html_color_2(1, 2, 3);
color_1 = HtmlColor2::_from_underlying_unchecked(color_1_underlying);
TS_ASSERT_EQUALS(color_1->r, color_1_underlying.r);
TS_ASSERT_EQUALS(color_1->g, color_1_underlying.g);
TS_ASSERT_EQUALS(color_1->b, color_1_underlying.b);
}
};