mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-07 01:06:42 +08:00
Subscript operator for iterables and tests for constexpr iterators.
This commit is contained in:
parent
14bc834f7d
commit
6c60edcc46
2
enum.h
2
enum.h
@ -346,6 +346,8 @@ struct _Iterable {
|
|||||||
constexpr iterator begin() const { return iterator(_array); }
|
constexpr iterator begin() const { return iterator(_array); }
|
||||||
constexpr iterator end() const { return iterator(_array + _size); }
|
constexpr iterator end() const { return iterator(_array + _size); }
|
||||||
constexpr size_t size() const { return _size; }
|
constexpr size_t size() const { return _size; }
|
||||||
|
constexpr const Element& operator [](size_t index) const
|
||||||
|
{ return _array[index]; }
|
||||||
|
|
||||||
constexpr _Iterable(const Element *array, size_t size) :
|
constexpr _Iterable(const Element *array, size_t size) :
|
||||||
_array(array), _size(size) { };
|
_array(array), _size(size) { };
|
||||||
|
|||||||
@ -33,6 +33,7 @@ constexpr bool should_be_invalid_3 = Channel::_is_valid_nocase("reed");
|
|||||||
// _names and _values collections and iterators.
|
// _names and _values collections and iterators.
|
||||||
constexpr Channel channel_5 = *(Channel::_values.begin() + 1);
|
constexpr Channel channel_5 = *(Channel::_values.begin() + 1);
|
||||||
constexpr const char *name_through_iterator = *(Channel::_names.begin() + 1);
|
constexpr const char *name_through_iterator = *(Channel::_names.begin() + 1);
|
||||||
|
constexpr const char *name_through_subscript = Channel::_names[2];
|
||||||
|
|
||||||
// Range properties.
|
// Range properties.
|
||||||
constexpr Channel channel_6 = Channel::_max;
|
constexpr Channel channel_6 = Channel::_max;
|
||||||
@ -89,6 +90,8 @@ int main()
|
|||||||
std::cout << "constexpr trimmed name: " << channel_1_name << std::endl;
|
std::cout << "constexpr trimmed name: " << channel_1_name << std::endl;
|
||||||
std::cout << "constexpr name through iterator: "
|
std::cout << "constexpr name through iterator: "
|
||||||
<< name_through_iterator << std::endl;
|
<< name_through_iterator << std::endl;
|
||||||
|
std::cout << "constexpr name through suscript: "
|
||||||
|
<< name_through_subscript << std::endl;
|
||||||
std::cout << "span: " << span << std::endl;
|
std::cout << "span: " << span << std::endl;
|
||||||
std::cout << "type name: " << name << std::endl;
|
std::cout << "type name: " << name << std::endl;
|
||||||
|
|
||||||
|
|||||||
81
example/8-constexpr-iterate.cc
Normal file
81
example/8-constexpr-iterate.cc
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Compile-time iteration. This example generates an approximation of enum
|
||||||
|
// declarations (without explicit "="" settings) at run time. The storage space
|
||||||
|
// for this is reserved at compile time, however.
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <enum.h>
|
||||||
|
|
||||||
|
ENUM(Channel, int, Red, Green, Blue);
|
||||||
|
ENUM(Depth, int, TrueColor, HighColor);
|
||||||
|
|
||||||
|
// Computes the length of a string.
|
||||||
|
constexpr size_t string_length(const char *s, size_t index = 0)
|
||||||
|
{
|
||||||
|
return s[index] == '\0' ? index : string_length(s, index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runs over all the constants in an enum and adds up the lengths of their
|
||||||
|
// names.
|
||||||
|
template <typename Enum>
|
||||||
|
constexpr size_t total_names_length(size_t accumulator = 0, size_t index = 0)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
index == Enum::_size ? accumulator :
|
||||||
|
total_names_length<Enum>
|
||||||
|
(accumulator + string_length(Enum::_names[index]), index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes the total length of an ENUM declaration, assuming the type is int.
|
||||||
|
// The summands correspond to each of the tokens and spaces (i.e., "ENUM", "(",
|
||||||
|
// etc.). (Enum::_size - 1) * 2 is added to account for each comma and space
|
||||||
|
// following each constant name, except for the last one. The final 1 is added
|
||||||
|
// to account for the null terminator.
|
||||||
|
template <typename Enum>
|
||||||
|
constexpr size_t declaration_length()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
4 + 1 + string_length(Enum::_name) + 1 + 1 + 3 + 1 + 1 +
|
||||||
|
total_names_length<Enum>() + (Enum::_size - 1) * 2 + 1 + 1 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formats the declaration into space already reserved.
|
||||||
|
template <typename Enum>
|
||||||
|
void format_declaration(char *storage)
|
||||||
|
{
|
||||||
|
std::strcat(storage, "ENUM(");
|
||||||
|
std::strcat(storage, Enum::_name);
|
||||||
|
std::strcat(storage, ", int, ");
|
||||||
|
|
||||||
|
for (auto name_iterator = Enum::_names.begin();
|
||||||
|
name_iterator < Enum::_names.end() - 1; ++name_iterator) {
|
||||||
|
|
||||||
|
std::strcat(storage, *name_iterator);
|
||||||
|
std::strcat(storage, ", ");
|
||||||
|
}
|
||||||
|
std::strcat(storage, (+Enum::_last).to_string());
|
||||||
|
|
||||||
|
std::strcat(storage, ");");
|
||||||
|
|
||||||
|
assert(std::strlen(storage) == declaration_length<Enum>() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserve space for the formatted declaration of each enum. These buffers
|
||||||
|
// should be zeroed at load time or during code generation, so, semantically,
|
||||||
|
// they contain the empty string.
|
||||||
|
char channel_declaration[declaration_length<Channel>()];
|
||||||
|
char depth_declaration[declaration_length<Depth>()];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
format_declaration<Channel>(channel_declaration);
|
||||||
|
std::cout << channel_declaration << std::endl;
|
||||||
|
|
||||||
|
format_declaration<Depth>(depth_declaration);
|
||||||
|
std::cout << depth_declaration << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -128,7 +128,13 @@ static_assert_1(!Channel::_is_valid_nocase("greeen"));
|
|||||||
// Iterables.
|
// Iterables.
|
||||||
static_assert_1(Channel::_values.size() == Channel::_size);
|
static_assert_1(Channel::_values.size() == Channel::_size);
|
||||||
static_assert_1(*Channel::_values.begin() == Channel::_first);
|
static_assert_1(*Channel::_values.begin() == Channel::_first);
|
||||||
|
static_assert_1(*(Channel::_values.begin() + 1) == Channel::Green);
|
||||||
|
static_assert_1(*(Channel::_values.begin() + 2) == Channel::Blue);
|
||||||
|
static_assert_1(Channel::_values[1] == Channel::Green);
|
||||||
|
static_assert_1(Channel::_values[2] == Channel::Blue);
|
||||||
static_assert_1(Channel::_names.size() == Channel::_size);
|
static_assert_1(Channel::_names.size() == Channel::_size);
|
||||||
|
// The next one is a little janky, but actually the pointers should be the same.
|
||||||
|
static_assert_1(*Channel::_names.begin() == (+Channel::_first).to_string());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -149,7 +155,8 @@ class EnumTests : public CxxTest::TestSuite {
|
|||||||
void test_string_conversions()
|
void test_string_conversions()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(strcmp((+Channel::Green).to_string(), "Green"), 0);
|
TS_ASSERT_EQUALS(strcmp((+Channel::Green).to_string(), "Green"), 0);
|
||||||
TS_ASSERT_EQUALS(strcmp((+Channel::Blue).to_string(), "Blue"), 0);
|
TS_ASSERT_EQUALS(strcmp((+Depth::HighColor).to_string(),
|
||||||
|
"HighColor"), 0);
|
||||||
|
|
||||||
TS_ASSERT_THROWS(Channel::_from_string("green"), std::runtime_error);
|
TS_ASSERT_THROWS(Channel::_from_string("green"), std::runtime_error);
|
||||||
TS_ASSERT_THROWS(Channel::_from_string_nocase("a"), std::runtime_error);
|
TS_ASSERT_THROWS(Channel::_from_string_nocase("a"), std::runtime_error);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user