diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7da542b --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +.cache/ +.ninja_deps +.ninja_log +CMakeCache.txt +CMakeFiles/ +CPM_modules/ +CTestTestfile.cmake +_deps/ +build.ninja +cmake/CPM.cmake +cmake_install.cmake +compile_commands.json +compile_commands.json.tmp9cdd8 +cpm-package-lock.cmake +examples/output/ +install_manifest.txt +lib__cmake_cxx23.a +utemplConfig.cmake +utemplConfigVersion.cmake +utempl_tests +utempl_tests\[1\]_include.cmake +utempl_tests\[1\]_tests.cmake +libutempl_shared.so +libutempl_static.so diff --git a/CMakeLists.txt b/CMakeLists.txt index 3847aed..bf49331 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,26 @@ -cmake_minimum_required(VERSION 3.27) +cmake_minimum_required(VERSION 3.30) + +set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD + "0e5b6991-d74f-4b3d-a41c-cf096e0b2508") + project(utempl - VERSION 0.1) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(CMAKE_CXX_STANDART 23) + VERSION 0.1 + LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CXX_EXTENSIONS NO) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_MODULE_STD 1) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(FMT_MODULE ON) set(BOOST_INCLUDE_LIBRARIES "pfr") + option(CPM_USE_LOCAL_PACKAGES "Use local packages" ON) +option(BUILD_SHARED_LIBS "Build shared libraries (.so)" ON) +option(BUILD_STATIC_LIBS "Build static libraries (.a)" OFF) +file(GLOB_RECURSE SOURCES "src/*.cpp") + +set_target_properties(__cmake_cxx23 PROPERTIES CXX_EXTENSIONS OFF) file( @@ -26,38 +40,71 @@ CPMAddPackage( OPTIONS "BOOST_SKIP_INSTALL_RULES OFF" ) -CPMAddPackage("gh:fmtlib/fmt#10.2.1") +set(TMP ${CPM_USE_LOCAL_PACKAGES}) +set(CPM_USE_LOCAL_PACKAGES OFF) + +CPMAddPackage( + NAME fmt + URL + "https://github.com/linuxnyasha/fmt_import/archive/refs/heads/linuxnyasha-patch-1.zip" + # Fixes for fmt module and constexpr fmt::formatted_size + OPTIONS "CMAKE_CXX_FLAGS -DFMT_ATTACH_TO_GLOBAL_MODULE" +) + +set(CPM_USE_LOCAL_PACKAGES ${TMP}) + +function(configure target) + target_compile_features(${target} INTERFACE cxx_std_23) + + target_include_directories(${target} INTERFACE $ + $) + + target_sources(${target} PUBLIC FILE_SET ${target} TYPE CXX_MODULES + FILES ${SOURCES}) + install(TARGETS ${target} + EXPORT utemplTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + FILE_SET ${target} DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + + + if(TARGET Boost::pfr) + target_link_libraries(${target} PUBLIC fmt::fmt + Boost::pfr) + else() + find_package(Boost 1.85.0 REQUIRED) + target_link_libraries(${target} PUBLIC fmt::fmt + ${Boost_LIBRARIES}) + endif() +endfunction(configure) + cmake_policy(SET CMP0079 NEW) include(GNUInstallDirs) -add_library(utempl INTERFACE) -add_library(utempl::utempl ALIAS utempl) - -target_include_directories( - utempl - INTERFACE $ - $) - -if(TARGET Boost::pfr) - target_link_libraries(utempl INTERFACE fmt::fmt-header-only Boost::pfr) -else() - find_package(Boost 1.85.0 REQUIRED) - target_link_libraries(utempl INTERFACE fmt::fmt-header-only ${Boost_LIBRARIES}) +if(BUILD_SHARED_LIBS) + add_library(utempl_shared) + add_library(utempl::utempl ALIAS utempl_shared) + configure(utempl_shared) endif() -target_compile_features(utempl INTERFACE cxx_std_23) -install(TARGETS utempl - EXPORT utemplTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} -) +if(BUILD_STATIC_LIBS) + add_library(utempl_static) + if(NOT BUILD_SHARED_LIBS) + add_library(utempl ALIAS utempl_static) + add_library(utempl::utempl ALIAS utempl_static) + endif() + configure(utempl_static) +endif() + + include(CMakePackageConfigHelpers) write_basic_package_version_file("utemplConfigVersion.cmake" @@ -87,8 +134,10 @@ if(ENABLE_TESTS) find_package(GTest REQUIRED) enable_testing() file(GLOB SOURCES tests/* tests/*/* tests/*/*/*) - add_executable(utempl_tests ${SOURCES}) - target_link_libraries(utempl_tests GTest::gtest_main utempl) + add_executable(utempl_tests) + target_sources(utempl_tests PUBLIC FILE_SET utempl_tests TYPE CXX_MODULES + FILES ${SOURCES}) + target_link_libraries(utempl_tests GTest::gtest_main utempl::utempl) set_property(TARGET utempl_tests PROPERTY CXX_STANDARD 23) include(GoogleTest) gtest_discover_tests(utempl_tests) @@ -98,7 +147,7 @@ if(ENABLE_EXAMPLES) foreach(EXAMPLE_SRC ${EXAMPLES_SRC}) get_filename_component(EXAMPLE_NAME ${EXAMPLE_SRC} NAME_WE) add_executable(${EXAMPLE_NAME} ${EXAMPLE_SRC}) - target_link_libraries(${EXAMPLE_NAME} utempl) + target_link_libraries(${EXAMPLE_NAME} utempl::utempl) set_property(TARGET ${EXAMPLE_NAME} PROPERTY CXX_STANDARD 23) set_target_properties(${EXAMPLE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/examples/output") diff --git a/examples/src/attributes.cpp b/examples/src/attributes.cpp index 6eac821..25d24b2 100644 --- a/examples/src/attributes.cpp +++ b/examples/src/attributes.cpp @@ -1,5 +1,7 @@ -#include -#include +import std; +import utempl.attributes; +import utempl.type_list; +#include template struct AttributeData { @@ -7,25 +9,21 @@ struct AttributeData { constexpr auto operator==(const AttributeData&) const -> bool = default; }; +#define MY_ATTRIBUTE(type, ...) GENERIC_ATTRIBUTE(AttributeData{__VA_ARGS__}) // NOLINT -#define MY_ATTRIBUTE(type, ...) GENERIC_ATTRIBUTE(AttributeData{__VA_ARGS__}) +// clang-format off - -ATTRIBUTE_STRUCT(SomeStruct, +ATTRIBUTE_STRUCT(SomeStruct, MY_ATTRIBUTE(int, .value = 2); int field; SKIP_ATTRIBUTE(); int field2; - MY_ATTRIBUTE(std::string, .value = "HEY!") + MY_ATTRIBUTE(std::string, .value = "HEY!"); std::string field3; ); - -static_assert(utempl::GetAttributes() - == utempl::Tuple{ - AttributeData{.value = 2}, - utempl::NoInfo{}, - AttributeData{.value = "HEY!"}}); - +// clang-format on +static_assert(utempl::GetAttributes() == + utempl::Tuple{AttributeData{.value = 2}, utempl::NoInfo{}, AttributeData{.value = "HEY!"}}); struct SomeOtherStruct { static_assert(utempl::OpenStruct()); @@ -35,13 +33,6 @@ struct SomeOtherStruct { static_assert(utempl::CloseStruct()); }; -static_assert(utempl::GetAttributes() - == utempl::Tuple{ - utempl::kTypeList, - utempl::NoInfo{}, - utempl::kTypeList}); - - - +static_assert(utempl::GetAttributes() == utempl::Tuple{utempl::kTypeList, utempl::NoInfo{}, utempl::kTypeList}); auto main() -> int {}; diff --git a/examples/src/curry.cpp b/examples/src/curry.cpp index 1533cb9..55d31b7 100644 --- a/examples/src/curry.cpp +++ b/examples/src/curry.cpp @@ -1,9 +1,9 @@ -#include -#include +import utempl.utils; +import std; auto main() -> int { - constexpr auto f = utempl::Curry([](auto... args){ + constexpr auto f = utempl::Curry([](auto... args) { return (0 + ... + args); }); - std::cout << f(1)(2)(3) << std::endl; // Call on cast to return type + std::cout << f(1)(2)(3) << std::endl; // Call on cast to return type }; diff --git a/examples/src/go_interface.cpp b/examples/src/go_interface.cpp index 73ed557..d3f76cd 100644 --- a/examples/src/go_interface.cpp +++ b/examples/src/go_interface.cpp @@ -1,5 +1,6 @@ -#include -#include +import fmt; +import utempl.go_interface; +import std; struct SomeInterfaceImpl { int a; @@ -7,15 +8,14 @@ struct SomeInterfaceImpl { }; using SomeInterface = utempl::GoInterface; struct SomeStruct { - short a; - short b; + std::int16_t a; + std::int16_t b; }; inline auto Func(SomeInterface arg) { fmt::print("{} {}\n", arg.a, arg.b); }; - auto main() -> int { - Func(SomeStruct{42, 300}); + Func(SomeStruct{42, 300}); // NOLINT }; diff --git a/examples/src/left_fold.cpp b/examples/src/left_fold.cpp index f14030e..110474e 100644 --- a/examples/src/left_fold.cpp +++ b/examples/src/left_fold.cpp @@ -1,4 +1,6 @@ -#include +import utempl.utils; +import utempl.tuple; +import std; auto main() -> int { constexpr auto value = utempl::LeftFold( diff --git a/examples/src/make.cpp b/examples/src/make.cpp index 82f2534..c265bc9 100644 --- a/examples/src/make.cpp +++ b/examples/src/make.cpp @@ -1,4 +1,5 @@ -#include +import utempl.utils; +import std; auto main() -> int { constexpr auto arr = utempl::TupleMaker>::Make(); diff --git a/examples/src/menu.cpp b/examples/src/menu.cpp index 0fa6edb..002f10c 100644 --- a/examples/src/menu.cpp +++ b/examples/src/menu.cpp @@ -1,13 +1,13 @@ -#include -#include +import utempl.menu; +import std; auto main() -> int { utempl::menu::Menu{} - .With<{"This is 0"}>([]{ - std::cout << "You entered 0" << std::endl; - }) - .With<{"Some Long", "S"}>([]{ - std::cout << "It aligns the output to the longest element" << std::endl; - }) - .Run<"[{0}]{2} - |{1}|\n">(); + .With<{"This is 0"}>([] { + std::cout << "You entered 0" << std::endl; + }) + .With<{"Some Long", "S"}>([] { + std::cout << "It aligns the output to the longest element" << std::endl; + }) + .Run<"[{0}]{2} - |{1}|\n">(); }; diff --git a/examples/src/meta.cpp b/examples/src/meta.cpp index 3f73537..8a64b15 100644 --- a/examples/src/meta.cpp +++ b/examples/src/meta.cpp @@ -1,6 +1,5 @@ -#include -#include -#include +import utempl.meta_info; +import std; auto main() -> int { constexpr std::array types = {utempl::kTypeId, utempl::kTypeId}; diff --git a/examples/src/overloaded.cpp b/examples/src/overloaded.cpp index 28a1345..06c237c 100644 --- a/examples/src/overloaded.cpp +++ b/examples/src/overloaded.cpp @@ -1,13 +1,9 @@ -#include -#include - +import utempl.overloaded; +import std; auto main() -> int { - utempl::Overloaded( - [](auto&& arg){ - }, - [](int arg) { - std::cout << arg << std::endl; - } - )(42); + utempl::Overloaded([](auto&& arg) {}, + [](int arg) { + std::cout << arg << std::endl; + })(42); }; diff --git a/examples/src/pipe.cpp b/examples/src/pipe.cpp index 00b2bb9..affe128 100644 --- a/examples/src/pipe.cpp +++ b/examples/src/pipe.cpp @@ -1,4 +1,4 @@ -#include +import utempl; struct Container { float data{}; @@ -6,15 +6,17 @@ struct Container { auto main() -> int { using namespace utempl; - constexpr auto value = Tuple{1, 2, 3, 4, 5, 6} - | Take<5>() - | Map([](int arg) {return arg + 1;}) - | Map([](int arg) -> float {return arg;}) - | Map([](float arg) -> Container {return {.data = arg};}) - | Reverse() - | Take<3>() - | Reduce(0.f, [](auto accumulator, Container arg) -> float { - return accumulator + arg.data; - }); // Lazy evavalue + constexpr auto value = Tuple{1, 2, 3, 4, 5, 6} | Take<5>() | Map([](int arg) { + return arg + 1; + }) | + Map([](int arg) -> float { + return arg; + }) | + Map([](float arg) -> Container { + return {.data = arg}; + }) | + Reverse() | Take<3>() | Reduce(0.f, [](auto accumulator, Container arg) -> float { + return accumulator + arg.data; + }); // Lazy evavalue static_assert(value == 15.0f); }; diff --git a/examples/src/reverse.cpp b/examples/src/reverse.cpp index ee78d29..8ae7bf9 100644 --- a/examples/src/reverse.cpp +++ b/examples/src/reverse.cpp @@ -1,9 +1,10 @@ -#include -#include +import utempl.utils; +import utempl.tuple; +import std; auto main() -> int { auto tuple = Reverse(utempl::Tuple{4, 3, 2, 1}); - ForEach(tuple, [](auto arg){ + ForEach(tuple, [](auto arg) { std::cout << arg << std::endl; }); }; diff --git a/examples/src/switch.cpp b/examples/src/switch.cpp index 161c061..27cdece 100644 --- a/examples/src/switch.cpp +++ b/examples/src/switch.cpp @@ -1,4 +1,6 @@ -#include +import utempl.utils; +import utempl.tuple; +import std; auto main() -> int { static_assert(utempl::Switch(utempl::Tuple{2, 1, 0}, utempl::Tuple{0, 1, 2}, 0, [](int value) { diff --git a/examples/src/times.cpp b/examples/src/times.cpp index 57254a0..f3477d8 100644 --- a/examples/src/times.cpp +++ b/examples/src/times.cpp @@ -1,9 +1,9 @@ -#include -#include +import utempl.utils; +import std; auto main() -> int { std::size_t i = 0; - utempl::Times<10>([&](){ + utempl::Times<10>([&]() { ++i; std::cout << i << std::endl; }); diff --git a/examples/src/tuple.cpp b/examples/src/tuple.cpp index caba874..0d2cf23 100644 --- a/examples/src/tuple.cpp +++ b/examples/src/tuple.cpp @@ -1,23 +1,24 @@ -#include -#include -#include #include +import utempl.utils; +import utempl.tuple; +import utempl.overloaded; +import std; auto main() -> int { using utempl::literals::operator""_c; constexpr utempl::Tuple tuple = {42, 3.141500, "Hello World"}; - utempl::Tuple tuple2{{}}; + utempl::Tuple tuple2{{}}; std::ignore = tuple2; - std::cout << utempl::kTupleSize << std::endl; // Get tuple size - std::cout << tuple[0_c] << std::endl; // Get element using [] with literal - auto newTuple = Transform(tuple, utempl::Overloaded( - [](auto arg){ - return std::to_string(arg); - }, - [](const char* arg) { - return std::string(arg); - } - )); + std::cout << utempl::kTupleSize << std::endl; // Get tuple size + std::cout << tuple[0_c] << std::endl; // Get element using [] with literal + auto newTuple = Transform(tuple, + utempl::Overloaded( + [](auto arg) { + return std::to_string(arg); + }, + [](const char* arg) { + return std::string(arg); + })); auto flag = newTuple == utempl::Tuple{"42", "3.141500", "Hello World"}; assert(flag); }; diff --git a/include/utempl/attributes.hpp b/include/utempl/attributes.hpp deleted file mode 100644 index 822efbf..0000000 --- a/include/utempl/attributes.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include -#include - -namespace utempl { - -namespace impl { - -struct AttributesTag {}; - -template -struct AttributesCounterTag {}; - -} // namespace impl - -template ()> -consteval auto OpenStruct() -> bool { - return true; -}; - -template (), - auto II = (I >= 2) ? I - 2 : I - 1, - typename T = decltype(Magic(loopholes::Getter{}>{}))::Type, - auto = AddTypeToTag()> -consteval auto CloseStruct() -> bool { - return true; -}; - -struct NoInfo { - consteval auto operator==(const NoInfo&) const -> bool = default; -}; - -namespace impl { - -template -struct FieldAttributeData { - using Type = TypeList; -}; - -template <> -struct FieldAttributeData<> { - using Type = NoInfo; -}; - -template ())::Type, - auto = AddTypeToTag, typename FieldAttributeData::Type, decltype(f)>()> -consteval auto FieldAttribute() -> T; - -} // namespace impl - -template -using FieldAttribute = decltype(impl::FieldAttribute()); - -#define ATTRIBUTE_STRUCT(name, ...) /* NOLINT */ \ - \ - struct name { \ - static_assert(::utempl::OpenStruct()); \ - template \ - static consteval auto GetAttribute(); \ - __VA_ARGS__ \ - static_assert(::utempl::CloseStruct()); \ - } - -#define GENERIC_ATTRIBUTE(value) /* NOLINT */ \ - template <> \ - consteval auto GetAttribute<::utempl::loopholes::Counter< \ - ::utempl::impl::AttributesCounterTag())::Type>, \ - decltype([] {})>()>() { \ - return value; \ - } - -#define SKIP_ATTRIBUTE() /* NOLINT */ GENERIC_ATTRIBUTE(::utempl::NoInfo{}) - -template , decltype(f)>() > 0)> -concept HasAttributes = R; - -template -concept HasMacroAttributes = requires { T::template GetAttribute<0>(); }; - -template -consteval auto GetAttributes() - requires HasMacroAttributes -{ - constexpr auto I = loopholes::CountValue>(); - return [](auto... is) { - return Tuple{T::template GetAttribute()...}; - } | kSeq; -}; - -template -consteval auto GetAttributes() { - constexpr auto I = loopholes::CountValue>(); - return [](auto... is) { - return utempl::Tuple{typename decltype(Magic(loopholes::Getter>{}>{}))::Type{}...}; - } | kSeq; -}; - -} // namespace utempl diff --git a/include/utempl/macro.hpp b/include/utempl/macro.hpp new file mode 100644 index 0000000..8af3c1f --- /dev/null +++ b/include/utempl/macro.hpp @@ -0,0 +1,20 @@ +#pragma once +#define ATTRIBUTE_STRUCT(name, ...) /* NOLINT */ \ + \ + struct name { \ + static_assert(::utempl::OpenStruct()); \ + template \ + static consteval auto GetAttribute(); \ + __VA_ARGS__ \ + static_assert(::utempl::CloseStruct()); \ + } + +#define GENERIC_ATTRIBUTE(value) /* NOLINT */ \ + template <> \ + consteval auto GetAttribute<::utempl::loopholes::Counter< \ + ::utempl::impl::AttributesCounterTag())::Type>, \ + decltype([] {})>()>() { \ + return value; \ + } + +#define SKIP_ATTRIBUTE() /* NOLINT */ GENERIC_ATTRIBUTE(::utempl::NoInfo{}) diff --git a/include/utempl/reference_wrapper.hpp b/include/utempl/reference_wrapper.hpp deleted file mode 100644 index 8b1bd6b..0000000 --- a/include/utempl/reference_wrapper.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -namespace utempl { -template -struct ReferenceWrapper; - -template -struct ReferenceWrapper { - constexpr auto operator*() -> T& { - return this->value; - }; - constexpr auto operator->() -> T* { - return &this->value; - }; - T&& value; -}; - -template -struct ReferenceWrapper { - constexpr auto operator*() -> const T& { - return this->value; - }; - constexpr auto operator->() -> const T* { - return &this->value; - }; - const T& value; -}; - -template -struct ReferenceWrapper { - constexpr auto operator*() -> T& { - return this->value; - }; - constexpr auto operator->() -> T* { - return &this->value; - }; - T& value; -}; - -} // namespace utempl diff --git a/src/attributes.cpp b/src/attributes.cpp new file mode 100644 index 0000000..36186b4 --- /dev/null +++ b/src/attributes.cpp @@ -0,0 +1,82 @@ +export module utempl.attributes; +export import utempl.meta_info; +export import utempl.tuple; +export import utempl.loopholes.counter; +import utempl.utils; +import utempl.type_list; + +namespace utempl { + +namespace impl { + +export struct AttributesTag {}; + +export template +struct AttributesCounterTag {}; + +} // namespace impl + +export template ()> +consteval auto OpenStruct() -> bool { + return true; +}; + +export template (), + auto II = (I >= 2) ? I - 2 : I - 1, + typename T = decltype(Magic(loopholes::Getter{}>{}))::Type, + auto = AddTypeToTag()> +consteval auto CloseStruct() -> bool { + return true; +}; + +export struct NoInfo { + consteval auto operator==(const NoInfo&) const -> bool = default; +}; + +template +struct FieldAttributeData { + using Type = TypeList; +}; + +template <> +struct FieldAttributeData<> { + using Type = NoInfo; +}; + +template ())::Type, + auto = AddTypeToTag, typename FieldAttributeData::Type, decltype(f)>()> +consteval auto FieldAttributeHelper() -> T; + +export template +using FieldAttribute = decltype(FieldAttributeHelper()); + +export template , decltype(f)>() > 0)> +concept HasAttributes = R; + +export template +concept HasMacroAttributes = requires { T::template GetAttribute<0>(); }; + +export template +consteval auto GetAttributes() + requires HasMacroAttributes +{ + constexpr auto I = loopholes::CountValue>(); + return [](auto... is) { + return Tuple{T::template GetAttribute()...}; + } | kSeq; +}; + +export template +consteval auto GetAttributes() { + constexpr auto I = loopholes::CountValue>(); + return [](auto... is) { + return utempl::Tuple{typename decltype(Magic(loopholes::Getter>{}>{}))::Type{}...}; + } | kSeq; +}; + +} // namespace utempl diff --git a/include/utempl/constexpr_string.hpp b/src/constexpr_string.cpp similarity index 79% rename from include/utempl/constexpr_string.hpp rename to src/constexpr_string.cpp index 501e74d..5753fe2 100644 --- a/include/utempl/constexpr_string.hpp +++ b/src/constexpr_string.cpp @@ -1,28 +1,31 @@ -#pragma once -#include - -#include +module; +#include +export module utempl.string; +import std; +// import fmt; namespace utempl { -template +export template struct ConstexprString; } // namespace utempl -template -struct fmt::formatter> : public fmt::formatter { - constexpr auto parse(format_parse_context& ctx) const { - return ctx.begin(); - }; - constexpr auto format(const utempl::ConstexprString& str, auto& ctx) const { - return fmt::formatter::format({str.begin()}, ctx); +export { + template + struct fmt::formatter> : public fmt::formatter { + constexpr auto parse(format_parse_context& ctx) const { + return ctx.begin(); + }; + constexpr auto format(const utempl::ConstexprString& str, auto& ctx) const { + return fmt::formatter::format({str.begin()}, ctx); + }; }; }; - -namespace utempl { +export namespace utempl { template struct ConstexprString { std::array data; + using char_type = char; constexpr auto begin() -> char* { return this->data.begin(); }; @@ -74,6 +77,11 @@ struct ConstexprString { constexpr ConstexprString(ConstexprString&&) = default; }; +template +consteval auto GetFmtCompiledString() { + return FMT_COMPILE(Str.data.begin()); +}; + template constexpr auto operator<<(std::ostream& stream, const ConstexprString& str) -> std::ostream& { stream << static_cast(str); diff --git a/include/utempl/go_interface.hpp b/src/go_interface.cpp similarity index 82% rename from include/utempl/go_interface.hpp rename to src/go_interface.cpp index 4a865d7..07d441c 100644 --- a/include/utempl/go_interface.hpp +++ b/src/go_interface.cpp @@ -1,7 +1,8 @@ -#pragma once +module; #include -#include -#include +export module utempl.go_interface; +import std; +import utempl.string; namespace utempl { @@ -19,8 +20,6 @@ constexpr auto Get(T&& arg) { template struct EmptyField {}; -namespace impl { - template constexpr auto TryGet(T&& arg) -> decltype(boost::pfr::get()>(std::forward(arg))) requires(FindField() < boost::pfr::tuple_size_v>) @@ -41,9 +40,7 @@ constexpr auto Transform(Transformer&& transformer, From&& from) { }(std::make_index_sequence>()); }; -} // namespace impl - -struct DefaultFieldTransformer { +export struct DefaultFieldTransformer { constexpr auto operator()(auto&& arg) -> auto&& { return arg; }; @@ -56,12 +53,12 @@ struct DefaultFieldTransformer { }; }; -template +export template struct GoInterface : Value { constexpr GoInterface(Value&& value) : Value(std::move(value)) {}; // NOLINT constexpr GoInterface(const Value& value) : Value(value) {}; // NOLINT template - constexpr GoInterface(T&& value) : Value(impl::Transform(Transformer{}, std::forward(value))){}; // NOLINT + constexpr GoInterface(T&& value) : Value(Transform(Transformer{}, std::forward(value))){}; // NOLINT constexpr auto operator=(const GoInterface&) -> GoInterface& = default; constexpr auto operator=(GoInterface&&) -> GoInterface& = default; constexpr auto operator==(const Value& other) const -> bool @@ -78,11 +75,10 @@ struct GoInterface : Value { using Type = std::remove_cvref_t; Transformer transformer; // + 1 - NULL Terminator - return ( - (boost::pfr::get(static_cast(*this)) == - transformer(impl::TryGet().size() + 1>{boost::pfr::get_name().begin()}>( - other))) && - ...); + return ((boost::pfr::get(static_cast(*this)) == + transformer(TryGet().size() + 1>{boost::pfr::get_name().begin()}>( + other))) && + ...); }(std::make_index_sequence>()); }; template diff --git a/include/utempl/loopholes/core.hpp b/src/loopholes/core.cpp similarity index 55% rename from include/utempl/loopholes/core.hpp rename to src/loopholes/core.cpp index 88dd128..37947a4 100644 --- a/include/utempl/loopholes/core.hpp +++ b/src/loopholes/core.cpp @@ -1,19 +1,20 @@ -#include -#pragma once +export module utempl.loopholes.core; +import std; namespace utempl::loopholes { -template -struct Getter { - friend constexpr auto Magic(Getter); -}; -template -struct Injector { - friend constexpr auto Magic(Getter) { - return Value; +export { + template + struct Getter { + friend constexpr auto Magic(Getter); }; -}; - + template + struct Injector { + friend constexpr auto Magic(Getter) { + return Value; + }; + }; +} template struct InjectedImpl { static constexpr bool value = false; @@ -23,7 +24,7 @@ struct InjectedImpl{}))>, Ts...> { static constexpr bool value = true; }; -template +export template concept Injected = InjectedImpl::value; } // namespace utempl::loopholes diff --git a/include/utempl/loopholes/counter.hpp b/src/loopholes/counter.cpp similarity index 65% rename from include/utempl/loopholes/counter.hpp rename to src/loopholes/counter.cpp index 49045b7..00f0851 100644 --- a/include/utempl/loopholes/counter.hpp +++ b/src/loopholes/counter.cpp @@ -1,19 +1,16 @@ -#pragma once -#include -#include -#include +export module utempl.loopholes.counter; +export import utempl.loopholes.core; +import std; namespace utempl::loopholes { -namespace impl { - template struct TagWithValue {}; template -consteval auto Counter() -> std::size_t { +consteval auto CounterHelper() -> std::size_t { if constexpr(requires { Magic(Getter{}>{}); }) { - return Counter(); + return CounterHelper(); }; if constexpr(Add) { return (std::ignore = Injector{}, 0>{}, I); @@ -22,16 +19,14 @@ consteval auto Counter() -> std::size_t { }; }; -} // namespace impl - // For incerement counter need a unique Ts... -template ()> +export template ()> consteval auto Counter(auto...) -> std::size_t { return R; }; // Without increment -template ()> +export template ()> consteval auto CountValue(auto...) -> std::size_t { return R; }; diff --git a/src/loopholes/loopholes.cpp b/src/loopholes/loopholes.cpp new file mode 100644 index 0000000..6bebbe0 --- /dev/null +++ b/src/loopholes/loopholes.cpp @@ -0,0 +1,3 @@ +export module utempl.loopholes; +export import utempl.loopholes.core; +export import utempl.loopholes.counter; diff --git a/include/utempl/menu.hpp b/src/menu.cpp similarity index 80% rename from include/utempl/menu.hpp rename to src/menu.cpp index 167021c..db83b80 100644 --- a/include/utempl/menu.hpp +++ b/src/menu.cpp @@ -1,13 +1,14 @@ -#pragma once -#include -#include +module; +#include +export module utempl.menu; -#include -#include -#include -#include -#include -#include +import fmt; +import std; +import utempl.string; +import utempl.optional; +import utempl.tuple; +import utempl.utils; +import utempl.type_list; namespace utempl { @@ -46,8 +47,6 @@ constexpr auto GetMax(Range&& range) { namespace menu { -namespace impl { - template struct CallbackMessage { ConstexprString message; @@ -62,17 +61,24 @@ CallbackMessage(const char (&)[N1], const char (&)[N2]) -> CallbackMessage CallbackMessage(const char (&)[N1]) -> CallbackMessage; // NOLINT -} // namespace impl - -template +export template struct Menu { private: template static consteval auto FormatMessage() { + constexpr auto fmtlib = GetFmtCompiledString(); // + 1 - NULL Terminator - constexpr auto size = fmt::formatted_size(FMT_COMPILE(fmt.data.begin()), neededInput, message, alignment) + 1; + constexpr auto size = fmt::formatted_size(fmtlib, + static_cast(neededInput), + static_cast(message), + static_cast(alignment)) + + 1; std::array data{}; - fmt::format_to(data.begin(), FMT_COMPILE(fmt.data.begin()), neededInput, message, alignment); + fmt::format_to(data.begin(), + fmtlib, + static_cast(neededInput), + static_cast(message), + static_cast(alignment)); return ConstexprString(data); }; template @@ -101,7 +107,7 @@ struct Menu { : CountDigits(Is))...}); }(std::index_sequence_for()); }; - template + template constexpr auto With(F&& f) const { return Menu>{.functionStorage = this->functionStorage + Tuple(std::forward(f))}; @@ -120,7 +126,7 @@ struct Menu { std::string input; std::getline(in, input); ( - [&](storage)>(Wrapper) { + [&](storage)>(Wrapper) { if constexpr(message.need) { if(*message.need == input) { Get(this->functionStorage)(); diff --git a/include/utempl/meta_info.hpp b/src/meta_info.cpp similarity index 63% rename from include/utempl/meta_info.hpp rename to src/meta_info.cpp index 71ddbb8..56a58ee 100644 --- a/include/utempl/meta_info.hpp +++ b/src/meta_info.cpp @@ -1,18 +1,16 @@ -#pragma once -#include -#include +export module utempl.meta_info; +import utempl.loopholes; +import utempl.type_list; +import std; namespace utempl { -namespace impl { +export struct Types {}; -struct Types {}; -} // namespace impl - -template +export template struct MetaInfoKey {}; -template +export template struct MetaInfo { static constexpr std::size_t kTypeId = loopholes::Counter(); using Type = T; @@ -21,27 +19,25 @@ struct MetaInfo { static constexpr auto _ = loopholes::Injector{}, TypeList{}>{}; }; -template +export template inline constexpr std::size_t kTypeId = MetaInfo::kTypeId; -template (), - auto = loopholes::Injector{}, TypeList{}>{}> +export template (), + auto = loopholes::Injector{}, TypeList{}>{}> consteval auto AddTypeToTag(TTs&&...) -> std::size_t { return Id; }; -template +export template using GetMetaInfo = MetaInfo{}>{}))::Type>; -template +export template using GetType = GetMetaInfo::Type; -namespace impl { - template static consteval auto GetTypeListForTag(G g) requires(I == 0 || requires { Magic(loopholes::Getter{}>{}); }) @@ -59,14 +55,12 @@ static consteval auto GetTypeListForTag(G g) }; }; -} // namespace impl - -template +export template consteval auto GetTypeListForTag() { - return impl::GetTypeListForTag(TypeList{}); + return GetTypeListForTag(TypeList{}); }; -template () - 1> +export template () - 1> consteval auto GetCurrentTagType() { return Magic(utempl::loopholes::Getter{}>()); }; @@ -74,7 +68,7 @@ consteval auto GetCurrentTagType() { /* static_assert(kTypeId == 0); static_assert(kTypeId == 1); -static_assert(AddTypeToTag() == 2); +static_assert(AddTypeToTag() == 2); static_assert(std::is_same_v>); */ diff --git a/include/utempl/optional.hpp b/src/optional.cpp similarity index 93% rename from include/utempl/optional.hpp rename to src/optional.cpp index 68aea9e..3fe6b68 100644 --- a/include/utempl/optional.hpp +++ b/src/optional.cpp @@ -1,9 +1,9 @@ -#pragma once -#include +export module utempl.optional; +import std; namespace utempl { -template +export template struct Optional { // NOLINT bool flag = false; union { diff --git a/include/utempl/overloaded.hpp b/src/overloaded.cpp similarity index 74% rename from include/utempl/overloaded.hpp rename to src/overloaded.cpp index 5d116b7..242330d 100644 --- a/include/utempl/overloaded.hpp +++ b/src/overloaded.cpp @@ -1,8 +1,8 @@ -#pragma once -#include +export module utempl.overloaded; +import std; namespace utempl { -template +export template constexpr auto Overloaded(Fs&&... fs) { struct Overloaded : public std::remove_cvref_t... { using Fs::operator()...; diff --git a/include/utempl/tuple.hpp b/src/tuple.cpp similarity index 62% rename from include/utempl/tuple.hpp rename to src/tuple.cpp index 03bce28..59e2f80 100644 --- a/include/utempl/tuple.hpp +++ b/src/tuple.cpp @@ -1,11 +1,25 @@ -#pragma once -#include -#include +export module utempl.tuple; + +import utempl.type_list; +import utempl.overloaded; +import std; + namespace utempl { -template -struct Wrapper; -namespace impl { +export template +struct Wrapper { + static constexpr auto kValue = Value; + static constexpr auto value = Value; + inline constexpr auto operator==(auto&& arg) const { + return arg == Value; + }; + consteval operator decltype(Value)() const { // NOLINT + return Value; + }; + consteval auto operator*() const { + return Value; + }; +}; template struct TupleLeaf { @@ -17,60 +31,58 @@ template struct TupleHelper; template -struct TupleHelper, Ts...> : public impl::TupleLeaf... { +struct TupleHelper, Ts...> : public TupleLeaf... { constexpr auto operator==(const TupleHelper&) const -> bool = default; }; -} // namespace impl - -template +export template struct Tuple; -template +export template constexpr auto Get(Tuple& tuple) -> auto& requires(I < sizeof...(Ts)) { using Type = decltype(Get(TypeList{})); - return static_cast&>(tuple).value; + return static_cast&>(tuple).value; }; -template +export template constexpr auto Get(const Tuple& tuple) -> const auto& requires(I < sizeof...(Ts)) { using Type = decltype(Get(TypeList{})); - return static_cast&>(tuple).value; + return static_cast&>(tuple).value; }; -template +export template constexpr auto Get(Tuple&& tuple) -> decltype(auto) requires(I < sizeof...(Ts)) { using Type = decltype(Get(TypeList{})); - return std::move(static_cast&&>(tuple).value); + return std::move(static_cast&&>(tuple).value); }; -template +export template constexpr auto Get(T&& arg) -> decltype(get(std::forward(arg))) { return get(std::forward(arg)); }; -template -struct Tuple : impl::TupleHelper, Ts...> { +export template +struct Tuple : TupleHelper, Ts...> { template - constexpr Tuple(TTs&&... args) /* NOLINT */ : impl::TupleHelper, Ts...>{{std::forward(args)}...} {}; + constexpr Tuple(TTs&&... args) /* NOLINT */ : TupleHelper, Ts...>{{std::forward(args)}...} {}; template constexpr Tuple(Fs&&... fs) // NOLINT requires(!std::invocable || ...) - : impl::TupleHelper, Ts...>{{fs()}...} {}; - constexpr Tuple(Ts&&... args) : impl::TupleHelper, Ts...>{{args}...} {}; // NOLINT + : TupleHelper, Ts...>{{fs()}...} {}; + constexpr Tuple(Ts&&... args) : TupleHelper, Ts...>{{args}...} {}; // NOLINT constexpr Tuple(const Tuple&) = default; constexpr Tuple(Tuple&&) = default; constexpr Tuple(Tuple&) = default; constexpr auto operator=(const Tuple&) -> Tuple& = default; constexpr auto operator=(Tuple&&) -> Tuple& = default; constexpr auto operator=(Tuple&) -> Tuple& = default; - constexpr Tuple() : impl::TupleHelper, Ts...>() {}; + constexpr Tuple() : TupleHelper, Ts...>() {}; constexpr auto operator==(const Tuple& other) const -> bool { return [&](std::index_sequence) { return ((Get(*this) == Get(other)) && ...); @@ -94,7 +106,7 @@ struct Tuple : impl::TupleHelper, Ts...> { }; }; -template <> +export template <> struct Tuple<> { template constexpr auto operator+(const Tuple& other) const -> Tuple { @@ -104,10 +116,10 @@ struct Tuple<> { return true; }; }; -template +export template Tuple(Ts&&...) -> Tuple...>; -template +export template consteval auto ListFromTuple(Tuple) -> TypeList { return {}; }; diff --git a/include/utempl/type_list.hpp b/src/type_list.cpp similarity index 72% rename from include/utempl/type_list.hpp rename to src/type_list.cpp index 1268963..deed029 100644 --- a/include/utempl/type_list.hpp +++ b/src/type_list.cpp @@ -1,27 +1,25 @@ -#pragma once -#include -#include -#include -#include -#include +export module utempl.type_list; + +import std; +import utempl.overloaded; namespace utempl { -template +export template struct TypeList {}; -template +export template struct TypeList { using Type = T; }; -template +export template inline constexpr auto kType = TypeList{}; -template +export template inline constexpr auto kTypeList = TypeList{}; -template +export template concept IsTypeList = Overloaded( [](TypeList>) { return true; @@ -30,8 +28,6 @@ concept IsTypeList = Overloaded( return false; })(kType>); -namespace impl { - template struct IndexedType {}; @@ -41,45 +37,45 @@ struct Caster {}; template struct Caster, Ts...> : IndexedType... {}; -} // namespace impl -template +export template consteval auto operator==(const TypeList& first, const TypeList& second) -> bool { return std::same_as; }; -template +export template consteval auto operator+(const TypeList&, const TypeList&) -> TypeList { return {}; }; -template -consteval auto Get(TypeList) -> decltype([](impl::IndexedType&&) -> T { -}(impl::Caster, Ts...>{})); +export template +consteval auto Get(TypeList) -> decltype([](IndexedType&&) -> T { +}(Caster, Ts...>{})); -template +export template consteval auto Find(TypeList) -> std::size_t { std::array arr{std::same_as...}; return std::ranges::find(arr, true) - arr.begin(); }; -template