Skip to content

Commit

Permalink
pre-v1.0-update
Browse files Browse the repository at this point in the history
  • Loading branch information
dakka committed Mar 27, 2024
1 parent 6f34044 commit 444861c
Show file tree
Hide file tree
Showing 5 changed files with 451 additions and 51 deletions.
41 changes: 27 additions & 14 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,42 @@ project (conjure_enum
DESCRIPTION "Lightweight C++20 enum reflection"
VERSION 1.0.0
)
include(FetchContent)

FetchContent_Declare(Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_SHALLOW ON
GIT_TAG devel
)
FetchContent_MakeAvailable(Catch2)
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
# to disable building unit tests:
# cmake -DBUILD_UNITTESTS=false ..
option(BUILD_UNITTESTS "enable building unit tests" true)
message("-- Build unit tests: ${BUILD_UNITTESTS}")
if(BUILD_UNITTESTS)
include(FetchContent)
FetchContent_Declare(Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_SHALLOW ON
GIT_TAG devel
)
FetchContent_MakeAvailable(Catch2)
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
endif()

set(files example.cpp unittests.cpp)
set(files example.cpp)
if(BUILD_UNITTESTS)
list(APPEND files unittests.cpp)
endif()
foreach(x IN LISTS files)
cmake_path(GET x STEM LAST_ONLY target)
add_executable(${target} examples/${x})
set_target_properties(${target} PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED true)
target_include_directories(${target} PRIVATE include examples)
target_link_libraries(${target} PRIVATE Catch2::Catch2WithMain)
target_include_directories(${target} PRIVATE include examples)
if(BUILD_UNITTESTS)
target_link_libraries(${target} PRIVATE Catch2::Catch2WithMain)
endif()
add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_STRIP} ${target})
cmake_path(GET x FILENAME fname)
get_target_property(cppstd ${target} CXX_STANDARD)
message("-- adding ${fname} cxx std: C++${cppstd}")
endforeach()

include(Catch)
enable_testing()
catch_discover_tests(unittests)
if(BUILD_UNITTESTS)
include(Catch)
enable_testing()
catch_discover_tests(unittests)
endif()
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ enum component1 : int { scheme, authority, userinfo, user, password, host, port,
Returns a `std::string_view` (empty if not found)
```c++
auto name { conjure_enum::enum_to_string(component::path) };
auto name_trim { conjure_enum::enum_to_string(component::path, true) }; // optionally remove scope
auto name_trim { conjure_enum::enum_to_string(component::path, true) }; // optionally remove scope in result
auto alias_name { conjure_enum::enum_to_string(component::test) }; // alias
auto noscope_name { conjure_enum::enum_to_string(path) };
std::cout << name << '\n' << name_trim << '\n' << alias_name << '\n' << noscope_name << '\n';
Expand All @@ -71,14 +71,16 @@ path
Returns a `std::optional<T>`
```c++
int value { static_cast<int>(conjure_enum::string_to_enum<component>("component::path").value()) };
int value_trim { static_cast<int>(conjure_enum::string_to_enum<component>("path", true).value()) }; // optionally remove scope in test
int noscope_value { static_cast<int>(conjure_enum::string_to_enum<component1>("path").value()) };
int bad_value { static_cast<int>(conjure_enum::string_to_enum<component>("bad_string").value_or(component(100))) };
std::cout << value << '\n' << noscope_value << '\n' << bad_value << '\n';
std::cout << value << '\n' << value_trim << '\n' << noscope_value << '\n' << bad_value << '\n';
```
_output_
```CSV
12
12
12
100
```
### `int_to_enum`
Expand Down Expand Up @@ -124,7 +126,6 @@ component::port
component::path
component::query
component::fragment
component::host
scheme
authority
userinfo
Expand Down Expand Up @@ -175,7 +176,7 @@ _output_
14 component::fragment
```
### `for_each`
Call supplied invocable for each enum. Similar to `std::for_each` except first parameter of your invocable must be an enum value (passed by `for_each`).
Call supplied invocable for each enum. Similar to `std::for_each` except first parameter of your invocable must accept an enum value (passed by `for_each`).
Optionally provide any additional parameters. Works with lambdas, member functions, functions etc. When using a member function, the _first_ parameter
passed by your call must be the `this` pointer of the object. If you wish to pass a `reference` parameter, you must wrap it in
`std::ref`.
Expand Down
61 changes: 58 additions & 3 deletions examples/example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,17 @@

#include <fix8/conjure_enum.hpp>

using namespace std::literals::string_view_literals;
using namespace std::literals::string_literals;
//-----------------------------------------------------------------------------------------
using namespace FIX8;

enum class component : int { scheme, authority, userinfo, user, password, host, port, path=12, test=path, query, fragment };
enum component1 : int { scheme, authority, userinfo, user, password, host, port, path=12, query, fragment };
enum class numbers : int { zero, one, two, three, four, five, six, seven, eight, nine };
enum class numbers1 : int { zero=4, one=3, two=2, three, four, five, six, seven, eight, nine };

int main()
int main(int argc, char *argv[])
{
/*
std::cout << get_name(epeek<component, component::user>()) << '\n';
Expand All @@ -60,20 +64,35 @@ int main()
else
std::cout << "not valid\n";

/*
for(const auto ev : conjure_enum::enum_values<component>)
std::cout << static_cast<int>(ev) << '\n';
for(const auto [a, b] : conjure_enum::enum_entries<component>)
std::cout << static_cast<int>(a) << ' ' << b << '\n';
std::cout << '*' << static_cast<int>(a) << ' ' << conjure_enum::remove_scope<component>(b) << '\n';
for(const auto ev : conjure_enum::enum_values<component1>)
std::cout << static_cast<int>(ev) << '\n';
for(const auto ev : conjure_enum::enum_names<component>)
std::cout << ev << '\n';
std::cout << conjure_enum::enum_names<component>[5] << '\n';
enum_bitset<numbers> n1(numbers::zero,numbers::one,numbers::three,numbers::seven,numbers::nine);
n1.for_each([](numbers val) noexcept
{
std::cout << conjure_enum::enum_to_string<numbers>(val) << '(' << static_cast<int>(val) << ')' << '\n';
});
*/
/*
for (auto itr{conjure_enum::cbegin<component>()}; itr != conjure_enum::cend<component>(); ++itr)
{
const auto [a, b] {*itr};
std::cout << static_cast<int>(a) << ' ' << conjure_enum::remove_scope<component>(b) << '\n';
}*/

/*
std::cout << "1: " << std::string_view(conjure_enum::enum_name_v<component, component::fragment>) << '\n';
std::cout << "2: " << conjure_enum::enum_name<component, component::fragment>().get() << '\n';
std::cout << "3: " << conjure_enum::enum_to_string(component::path) << '\n';
std::cout << "3: " << conjure_enum::enum_to_string(component::path, true) << '\n';
std::cout << "4: " << conjure_enum::enum_to_string(component::test) << '\n';
std::cout << "16: " << '\"' << conjure_enum::enum_to_string(static_cast<component>(100)) << '\"' << '\n';
std::cout << "5: " << conjure_enum::enum_to_string(path) << '\n';
std::cout << "6: " << static_cast<int>(conjure_enum::string_to_enum<component>("component::path").value()) << '\n';
std::cout << "7: " << static_cast<int>(conjure_enum::string_to_enum<component1>("path").value()) << '\n';
Expand All @@ -82,7 +101,9 @@ int main()
std::cout << "10: " << conjure_enum::get_name<component, component::scheme>() << '\n';
std::cout << "16: " << conjure_enum::get_type<component>() << '\n';
std::cout << "16: " << conjure_enum::get_type<component1>() << '\n';
*/

/*
//using enum component;
//std::cout << std::boolalpha << is_scoped<component, scheme>() << '\n';
std::cout << "11: " << std::boolalpha << conjure_enum::is_scoped<component>() << '\n';
Expand All @@ -109,5 +130,39 @@ int main()
myfunc(component::fragment);
std::cout << total << '\n';
// enum_bitset
enum class numbers : int { zero, one, two, three, four, five, six, seven, eight, nine };
//enum_bitset<component> ec;
enum_bitset<numbers> eb;
eb.set_all<numbers::zero,numbers::two,numbers::five,numbers::nine>();
std::cout << eb << '\n';
std::cout << eb.test_all<numbers::zero,numbers::two,numbers::five,numbers::nine>() << '\n';
eb.clear_all<numbers::five>();
std::cout << eb.test_all<numbers::zero,numbers::two,numbers::five,numbers::nine>() << '\n';
std::cout << eb << '\n';
eb.clear(numbers::nine);
std::cout << eb << '\n';
enum_bitset<numbers> ec(numbers::one,numbers::three,numbers::six);
std::cout << ec << '\n';
std::cout << ec.to_string('-', '+') << '\n'<< '\n';
std::cout << ec << '\n';
ec.flip<numbers::one>();
std::cout << ec << '\n';
ec.flip<numbers::one>();
std::cout << ec << '\n';
ec.flip();
std::cout << ec << '\n';
ec.flip();
std::cout << ec << '\n';
*/
std::cout << std::boolalpha << conjure_enum::enum_contains<component>("component::path"sv) << '\n';
std::cout << std::boolalpha << conjure_enum::enum_contains<component>(argv[1]) << '\n';
for(const auto [a, b] : conjure_enum::enum_entries_sorted<component>)
std::cout << conjure_enum::remove_scope<component>(b) << ' ' << static_cast<int>(a) << '\n';
for(const auto [a, b] : conjure_enum::enum_entries<numbers1>)
std::cout << b << ' ' << static_cast<int>(a) << '\n';
std::cout << conjure_enum::add_scope<component>("path"sv) << '\n';
std::cout << conjure_enum::add_scope<component>("component::path"sv) << '\n';
std::cout << conjure_enum::add_scope<component1>("path"sv) << '\n';
return 0;
}
119 changes: 119 additions & 0 deletions examples/unittests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,18 @@
//----------------------------------------------------------------------------------------
#include <catch2/catch_test_macros.hpp>
#include <string_view>
#include <iostream>
#include <fix8/conjure_enum.hpp>

//-----------------------------------------------------------------------------------------
using namespace FIX8;
using namespace std::literals::string_view_literals;
using namespace std::literals::string_literals;

//-----------------------------------------------------------------------------------------
enum class component : int { scheme, authority, userinfo, user, password, host, port, path=12, test=path, query, fragment };
enum component1 : int { scheme, authority, userinfo, user, password, host, port, path=12, query, fragment };
enum class numbers { zero, one, two, three, four, five, FIVE=five, six, seven, eight, nine };

//-----------------------------------------------------------------------------------------
// run as: ctest --output-on-failure
Expand Down Expand Up @@ -156,12 +159,44 @@ TEST_CASE("enum_entries")
REQUIRE(conjure_enum::enum_entries<component1> == compentries1);
}

//-----------------------------------------------------------------------------------------
TEST_CASE("enum_contains")
{
REQUIRE(conjure_enum::enum_contains(component::path));
REQUIRE(conjure_enum::enum_contains(component::test)); // alias
REQUIRE(conjure_enum::enum_contains(path));
REQUIRE(!conjure_enum::enum_contains(static_cast<component>(100)));
REQUIRE(conjure_enum::enum_contains<component>("component::path"sv));
REQUIRE(conjure_enum::enum_contains<component1>("path"sv));
}

//-----------------------------------------------------------------------------------------
TEST_CASE("enum_to_string")
{
REQUIRE(conjure_enum::enum_to_string(component::path) == "component::path");
REQUIRE(conjure_enum::enum_to_string(component::test) == "component::path"); // alias
REQUIRE(conjure_enum::enum_to_string(path) == "path");
REQUIRE(conjure_enum::enum_to_string(static_cast<component>(100)).empty());
}

//-----------------------------------------------------------------------------------------
TEST_CASE("remove_scope")
{
REQUIRE(conjure_enum::remove_scope<component>(conjure_enum::enum_name<component, component::fragment>()) == "fragment"sv);
REQUIRE(conjure_enum::remove_scope<component1>(conjure_enum::enum_name<component1, fragment>()) == "fragment"sv);
}

//-----------------------------------------------------------------------------------------
TEST_CASE("iterators")
{
auto itr{conjure_enum::cbegin<component>()};
const auto [a, b] {*itr};
REQUIRE(a == component::scheme);
REQUIRE(b == "component::scheme"sv);
int cnt{};
for (; itr != conjure_enum::cend<component>(); ++itr)
++cnt;
REQUIRE(cnt == conjure_enum::count<component>());
}

//-----------------------------------------------------------------------------------------
Expand Down Expand Up @@ -195,3 +230,87 @@ TEST_CASE("get_type")
REQUIRE(conjure_enum::get_type<component1>() == "component1");
}

//-----------------------------------------------------------------------------------------
TEST_CASE("for_each")
{
int total{};
auto myfunc { conjure_enum::for_each<component>([](component val, int& tot)
{
tot += static_cast<int>(val);
}, std::ref(total)) };
myfunc(component::fragment);
REQUIRE(total == 74);
}

//-----------------------------------------------------------------------------------------
TEST_CASE("enum_bitset")
{
enum_bitset<numbers> eb;
eb.set_all<numbers::zero,numbers::two,numbers::five,numbers::nine>();
REQUIRE(eb.test_all<numbers::zero,numbers::two,numbers::five,numbers::nine>());
eb.clear_all<numbers::FIVE>(); // use alias
REQUIRE(!eb.test_all<numbers::zero,numbers::two,numbers::five,numbers::nine>());
eb.clear(numbers::nine);
REQUIRE(!eb.test(numbers::nine));

enum_bitset<numbers> ec(numbers::one,numbers::three,numbers::six);
REQUIRE(ec.to_ulong() == (1 << 1 | 1 << 3 | 1 << 6));
REQUIRE(ec.to_string() == "0001001010"s);
REQUIRE(ec.to_ulong() == 0b0001001010);
REQUIRE(ec.to_string('-', '+') == "---+--+-+-"s);

REQUIRE(ec.test<numbers::one>());
ec.flip<numbers::one>();
REQUIRE(!ec.test<numbers::one>());
ec.flip<numbers::one>();
REQUIRE(ec.test<numbers::one>());
ec.flip();
REQUIRE(ec.to_ulong() == 0b1110110101);
REQUIRE(ec.count() == 7);
ec.clear<numbers::three>();
REQUIRE(!ec.test<numbers::three>());
ec.set<numbers::three>();
REQUIRE(ec.test<numbers::three>());
ec.clear(numbers::three);
REQUIRE(!ec.test<numbers::three>());
ec.set(numbers::three);
REQUIRE(ec.test<numbers::three>());

enum_bitset<numbers> ed(numbers::two,numbers::three,numbers::four,numbers::seven);
REQUIRE(ed.test_all<numbers::two,numbers::three,numbers::four,numbers::seven>());
REQUIRE(ed.test_any<numbers::two,numbers::three,numbers::four,numbers::seven>());
REQUIRE((ed << 1) == 0b0100111000);
ed <<= 1;
REQUIRE(ed.to_ulong() == 0b0100111000);
REQUIRE((ed >> 1) == 0b0010011100);
ed >>= 1;
REQUIRE(ed.to_ulong() == 0b0010011100);

REQUIRE((ed | numbers::one) == 0b0010011110);
REQUIRE((ed & numbers::two) == 0b100);
ed |= numbers::one;
REQUIRE(ed.to_ulong() == 0b0010011110);
ed &= numbers::one;
REQUIRE(ed.to_ulong() == 0b10);
//std::cerr << ed << '\n';

ed.clear();
REQUIRE(!ed);
REQUIRE((ed ^ numbers::one) == 0b010);
ed ^= numbers::one;
REQUIRE(ed.to_ulong() == 0b010);

enum_bitset<numbers> ee(0b10101010);
std::ostringstream ostr;
ee.for_each([&ostr](numbers val) noexcept
{
ostr << conjure_enum::enum_to_string<numbers>(val) << '(' << static_cast<int>(val) << ')' << '\n';
});
REQUIRE(ostr.str() ==
R"(numbers::one(1)
numbers::three(3)
numbers::five(5)
numbers::seven(7)
)");
}

Loading

0 comments on commit 444861c

Please sign in to comment.