Compare commits
10 commits
b440c81474
...
e7bc40ad39
Author | SHA1 | Date | |
---|---|---|---|
e7bc40ad39 | |||
555d9f9645 | |||
6fa97fcb87 | |||
b325c54968 | |||
42619d15a8 | |||
2aa1c6bb79 | |||
4548b03c67 | |||
fd757260c5 | |||
58134818ef | |||
5b402e48dd |
38 changed files with 602 additions and 459 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -20,5 +20,5 @@ utemplConfigVersion.cmake
|
||||||
utempl_tests
|
utempl_tests
|
||||||
utempl_tests\[1\]_include.cmake
|
utempl_tests\[1\]_include.cmake
|
||||||
utempl_tests\[1\]_tests.cmake
|
utempl_tests\[1\]_tests.cmake
|
||||||
libutempl_shared.so
|
libutempl.a
|
||||||
libutempl_static.so
|
_headers
|
||||||
|
|
179
CMakeLists.txt
179
CMakeLists.txt
|
@ -10,18 +10,23 @@ project(utempl
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
set(CMAKE_CXX_MODULE_STD 1)
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
set(FMT_MODULE ON)
|
|
||||||
set(BOOST_INCLUDE_LIBRARIES "pfr")
|
set(BOOST_INCLUDE_LIBRARIES "pfr")
|
||||||
|
set(NAMEOF_OPT_INSTALL ON)
|
||||||
|
|
||||||
|
|
||||||
option(CPM_USE_LOCAL_PACKAGES "Use local packages" ON)
|
option(CPM_USE_LOCAL_PACKAGES "Use local packages" ON)
|
||||||
option(BUILD_SHARED_LIBS "Build shared libraries (.so)" ON)
|
option(UTEMPL_MODULE OFF)
|
||||||
option(BUILD_STATIC_LIBS "Build static libraries (.a)" OFF)
|
|
||||||
|
if(UTEMPL_MODULE OR ENABLE_EXAMPLES OR ENABLE_TESTS)
|
||||||
|
set(CMAKE_CXX_MODULE_STD 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
file(GLOB_RECURSE SOURCES "src/*.cpp")
|
file(GLOB_RECURSE SOURCES "src/*.cpp")
|
||||||
|
|
||||||
set_target_properties(__cmake_cxx23 PROPERTIES CXX_EXTENSIONS OFF)
|
if(TARGET __cmake_cxx23)
|
||||||
|
set_target_properties(__cmake_cxx23 PROPERTIES CXX_EXTENSIONS OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
file(
|
file(
|
||||||
DOWNLOAD
|
DOWNLOAD
|
||||||
|
@ -40,48 +45,27 @@ CPMAddPackage(
|
||||||
OPTIONS "BOOST_SKIP_INSTALL_RULES OFF"
|
OPTIONS "BOOST_SKIP_INSTALL_RULES OFF"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(UTEMPL_MODULE)
|
||||||
|
|
||||||
set(TMP ${CPM_USE_LOCAL_PACKAGES})
|
set(TMP ${CPM_USE_LOCAL_PACKAGES})
|
||||||
set(CPM_USE_LOCAL_PACKAGES OFF)
|
set(CPM_USE_LOCAL_PACKAGES OFF)
|
||||||
|
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
NAME fmt
|
NAME nameof
|
||||||
URL
|
URL
|
||||||
"https://github.com/linuxnyasha/fmt_import/archive/refs/heads/linuxnyasha-patch-1.zip"
|
"https://sha512sum.xyz/git/sha512sum/nameof_module/archive/master.tar.gz"
|
||||||
# Fixes for fmt module and constexpr fmt::formatted_size
|
EXCLUDE_FROM_ALL ON
|
||||||
OPTIONS "CMAKE_CXX_FLAGS -DFMT_ATTACH_TO_GLOBAL_MODULE"
|
OPTIONS "NAMEOF_MODULE ON"
|
||||||
)
|
)
|
||||||
|
|
||||||
set(CPM_USE_LOCAL_PACKAGES ${TMP})
|
set(CPM_USE_LOCAL_PACKAGES ${TMP})
|
||||||
|
|
||||||
function(configure target)
|
else()
|
||||||
target_compile_features(${target} INTERFACE cxx_std_23)
|
|
||||||
|
|
||||||
target_include_directories(${target} INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
CPMAddPackage("gh:Neargye/nameof@0.10.4")
|
||||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
|
||||||
|
|
||||||
target_sources(${target} PUBLIC FILE_SET ${target} TYPE CXX_MODULES
|
|
||||||
FILES ${SOURCES})
|
|
||||||
|
|
||||||
|
|
||||||
|
endif()
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,20 +73,111 @@ cmake_policy(SET CMP0079 NEW)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
if(BUILD_SHARED_LIBS)
|
|
||||||
add_library(utempl_shared)
|
|
||||||
add_library(utempl::utempl ALIAS utempl_shared)
|
|
||||||
configure(utempl_shared)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(BUILD_STATIC_LIBS)
|
file(MAKE_DIRECTORY "_headers")
|
||||||
add_library(utempl_static)
|
file(MAKE_DIRECTORY "_headers/utempl")
|
||||||
if(NOT BUILD_SHARED_LIBS)
|
file(MAKE_DIRECTORY "_headers/utempl/loopholes")
|
||||||
add_library(utempl ALIAS utempl_static)
|
if(UTEMPL_MODULE)
|
||||||
add_library(utempl::utempl ALIAS utempl_static)
|
add_library(utempl STATIC)
|
||||||
|
target_compile_definitions(utempl PUBLIC UTEMPL_MODULE)
|
||||||
|
target_compile_options(utempl PUBLIC "-Wno-pragma-once-outside-header")
|
||||||
|
target_sources(utempl PUBLIC FILE_SET utemplModules TYPE CXX_MODULES
|
||||||
|
FILES ${SOURCES})
|
||||||
|
file(GLOB_RECURSE HEADER_SOURCES "src/*.hpp")
|
||||||
|
set(EXISTING_HEADERS)
|
||||||
|
|
||||||
|
foreach(HPP_FILE ${HEADER_SOURCES})
|
||||||
|
get_filename_component(REL_PATH ${HPP_FILE} DIRECTORY)
|
||||||
|
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/src" "" REL_PATH ${REL_PATH})
|
||||||
|
get_filename_component(FILE_NAME ${HPP_FILE} NAME_WE)
|
||||||
|
set(FILE_NAME "${REL_PATH}/${FILE_NAME}")
|
||||||
|
set(HEADER_FILE "_headers/utempl/${FILE_NAME}.hpp")
|
||||||
|
file(READ ${HPP_FILE} FILE_CONTENT)
|
||||||
|
if(EXISTS ${HEADER_FILE})
|
||||||
|
file(READ ${HEADER_FILE} HEADER_CONTENT)
|
||||||
|
if(NOT FILE_CONTENT STREQUAL HEADER_CONTENT)
|
||||||
|
file(WRITE ${HEADER_FILE} "${FILE_CONTENT}")
|
||||||
endif()
|
endif()
|
||||||
configure(utempl_static)
|
else()
|
||||||
|
file(WRITE ${HEADER_FILE} "${FILE_CONTENT}")
|
||||||
|
endif()
|
||||||
|
list(APPEND EXISTING_HEADERS "${HEADER_FILE}")
|
||||||
|
endforeach()
|
||||||
|
file(GLOB HEADER_FILES "_headers/*.hpp")
|
||||||
|
foreach(HEADER_FILE ${HEADER_FILES})
|
||||||
|
if(NOT HEADER_FILE IN_LIST EXISTING_HEADERS)
|
||||||
|
file(REMOVE ${HEADER_FILE})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
if(TARGET Boost::pfr)
|
||||||
|
target_link_libraries(utempl PUBLIC nameof::nameof
|
||||||
|
Boost::pfr)
|
||||||
|
else()
|
||||||
|
find_package(Boost 1.85.0 REQUIRED)
|
||||||
|
target_link_libraries(utempl PUBLIC nameof::nameof
|
||||||
|
${Boost_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
target_include_directories(utempl PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/_headers>
|
||||||
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||||
|
|
||||||
|
else()
|
||||||
|
add_library(utempl INTERFACE)
|
||||||
|
file(GLOB_RECURSE HEADER_SOURCES "src/*.hpp")
|
||||||
|
set(EXISTING_HEADERS)
|
||||||
|
foreach(CPP_FILE ${SOURCES} ${HEADER_SOURCES})
|
||||||
|
get_filename_component(REL_PATH ${CPP_FILE} DIRECTORY)
|
||||||
|
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/src" "" REL_PATH ${REL_PATH})
|
||||||
|
get_filename_component(FILE_NAME ${CPP_FILE} NAME_WE)
|
||||||
|
set(FILE_NAME "${REL_PATH}/${FILE_NAME}")
|
||||||
|
set(HEADER_FILE "_headers/utempl/${FILE_NAME}.hpp")
|
||||||
|
file(READ ${CPP_FILE} FILE_CONTENT)
|
||||||
|
if(EXISTS ${HEADER_FILE})
|
||||||
|
file(READ ${HEADER_FILE} HEADER_CONTENT)
|
||||||
|
if(NOT FILE_CONTENT STREQUAL HEADER_CONTENT)
|
||||||
|
file(WRITE ${HEADER_FILE} "${FILE_CONTENT}")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
file(WRITE ${HEADER_FILE} "${FILE_CONTENT}")
|
||||||
|
endif()
|
||||||
|
list(APPEND EXISTING_HEADERS "${HEADER_FILE}")
|
||||||
|
|
||||||
|
endforeach()
|
||||||
|
file(GLOB HEADER_FILES "_headers/*.hpp")
|
||||||
|
foreach(HEADER_FILE ${HEADER_FILES})
|
||||||
|
if(NOT HEADER_FILE IN_LIST EXISTING_HEADERS)
|
||||||
|
file(REMOVE ${HEADER_FILE})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
if(TARGET Boost::pfr)
|
||||||
|
target_link_libraries(utempl INTERFACE nameof::nameof
|
||||||
|
Boost::pfr nameof::nameof)
|
||||||
|
else()
|
||||||
|
find_package(Boost 1.85.0 REQUIRED)
|
||||||
|
target_link_libraries(utempl INTERFACE nameof::nameof
|
||||||
|
${Boost_LIBRARIES} nameof::nameof)
|
||||||
|
endif()
|
||||||
|
target_include_directories(utempl INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/_headers>
|
||||||
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||||
endif()
|
endif()
|
||||||
|
add_library(utempl::utempl ALIAS utempl)
|
||||||
|
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}
|
||||||
|
FILE_SET utemplModules DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,17 +201,19 @@ install(FILES "${PROJECT_BINARY_DIR}/utemplConfig.cmake"
|
||||||
"${PROJECT_BINARY_DIR}/utemplConfigVersion.cmake"
|
"${PROJECT_BINARY_DIR}/utemplConfigVersion.cmake"
|
||||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/utempl/cmake)
|
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/utempl/cmake)
|
||||||
|
|
||||||
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/utempl DESTINATION include)
|
install(DIRECTORY ${PROJECT_SOURCE_DIR}/_headers/utempl DESTINATION include)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(ENABLE_TESTS)
|
if(ENABLE_TESTS)
|
||||||
find_package(GTest REQUIRED)
|
CPMAddPackage(
|
||||||
|
NAME GTest
|
||||||
|
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
|
||||||
|
)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
file(GLOB SOURCES tests/* tests/*/* tests/*/*/*)
|
file(GLOB SOURCES tests/* tests/*/* tests/*/*/*)
|
||||||
add_executable(utempl_tests)
|
add_executable(utempl_tests)
|
||||||
target_sources(utempl_tests PUBLIC FILE_SET utempl_tests TYPE CXX_MODULES
|
target_sources(utempl_tests PUBLIC ${SOURCES})
|
||||||
FILES ${SOURCES})
|
|
||||||
target_link_libraries(utempl_tests GTest::gtest_main utempl::utempl)
|
target_link_libraries(utempl_tests GTest::gtest_main utempl::utempl)
|
||||||
set_property(TARGET utempl_tests PROPERTY CXX_STANDARD 23)
|
set_property(TARGET utempl_tests PROPERTY CXX_STANDARD 23)
|
||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import std;
|
#include <utempl/utempl.hpp>
|
||||||
import utempl;
|
|
||||||
#include <utempl/macro.hpp>
|
#include <utempl/macro.hpp>
|
||||||
|
import std;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct AttributeData {
|
struct AttributeData {
|
||||||
|
@ -26,12 +26,13 @@ static_assert(utempl::GetAttributes<SomeStruct>() ==
|
||||||
|
|
||||||
struct SomeOtherStruct {
|
struct SomeOtherStruct {
|
||||||
static_assert(utempl::OpenStruct<SomeOtherStruct>());
|
static_assert(utempl::OpenStruct<SomeOtherStruct>());
|
||||||
utempl::FieldAttribute<int, int> field1;
|
utempl::FieldAttribute<int, utempl::TypeList<int>> field1;
|
||||||
utempl::FieldAttribute<int> field2;
|
utempl::FieldAttribute<int> field2;
|
||||||
utempl::FieldAttribute<std::string, void> field3;
|
utempl::FieldAttribute<std::string, utempl::TypeList<void>> field3;
|
||||||
static_assert(utempl::CloseStruct());
|
static_assert(utempl::CloseStruct());
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(utempl::GetAttributes<SomeOtherStruct>() == utempl::Tuple{utempl::kTypeList<int>, utempl::NoInfo{}, utempl::kTypeList<void>});
|
static_assert(utempl::GetAttributes<SomeOtherStruct>() ==
|
||||||
|
utempl::Tuple{utempl::kTypeList<int>, utempl::kTypeList<>, utempl::kTypeList<void>});
|
||||||
|
|
||||||
auto main() -> int {};
|
auto main() -> int {};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import utempl;
|
#include <utempl/utempl.hpp>
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import fmt;
|
#include <utempl/utempl.hpp>
|
||||||
import utempl;
|
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
struct SomeInterfaceImpl {
|
struct SomeInterfaceImpl {
|
||||||
|
@ -13,7 +12,7 @@ struct SomeStruct {
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto Func(SomeInterface arg) {
|
inline auto Func(SomeInterface arg) {
|
||||||
fmt::print("{} {}\n", arg.a, arg.b);
|
std::println("{} {}\n", arg.a, arg.b);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import utempl;
|
#include <utempl/utempl.hpp>
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import utempl;
|
#include <utempl/utempl.hpp>
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
import utempl;
|
|
||||||
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">();
|
|
||||||
};
|
|
|
@ -1,4 +1,4 @@
|
||||||
import utempl;
|
#include <utempl/utempl.hpp>
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import utempl;
|
#include <utempl/utempl.hpp>
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import utempl;
|
#include <utempl/utempl.hpp>
|
||||||
|
|
||||||
struct Container {
|
struct Container {
|
||||||
float data{};
|
float data{};
|
||||||
|
|
38
examples/src/public_cast.cpp
Normal file
38
examples/src/public_cast.cpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#include <utempl/utempl.hpp>
|
||||||
|
|
||||||
|
using namespace utempl; // NOLINT
|
||||||
|
|
||||||
|
struct A {
|
||||||
|
private:
|
||||||
|
[[nodiscard]] constexpr auto Method() const -> int {
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
[[nodiscard]] constexpr auto Method(int) const -> int {
|
||||||
|
return 2;
|
||||||
|
};
|
||||||
|
[[nodiscard]] constexpr auto Method() -> int {
|
||||||
|
return 3;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace utempl {
|
||||||
|
|
||||||
|
template struct PublicCast<static_cast<int (A::*)() const>(&A::Method)>;
|
||||||
|
|
||||||
|
template struct PublicCast<static_cast<int (A::*)(int) const>(&A::Method)>;
|
||||||
|
|
||||||
|
template struct PublicCast<static_cast<int (A::*)()>(&A::Method)>;
|
||||||
|
|
||||||
|
} // namespace utempl
|
||||||
|
|
||||||
|
constexpr A a;
|
||||||
|
|
||||||
|
static_assert(GetPrivateMemberOverloaded<"Method">(a) == 1);
|
||||||
|
static_assert(GetPrivateMemberOverloaded<"Method">(a, 1) == 2);
|
||||||
|
static_assert(GetPrivateMemberOverloaded<"Method">(A{}) == 3);
|
||||||
|
|
||||||
|
static_assert((a.*GetPrivateMember<"Method", 0, A>())() == 1);
|
||||||
|
|
||||||
|
static_assert((a.*GetPrivateMember<"Method", 1>(a))(1) == 2);
|
||||||
|
|
||||||
|
auto main() -> int {};
|
|
@ -1,4 +1,4 @@
|
||||||
import utempl;
|
#include <utempl/utempl.hpp>
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import utempl;
|
#include <utempl/utempl.hpp>
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import utempl;
|
#include <utempl/utempl.hpp>
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
import utempl;
|
#include <utempl/utempl.hpp>
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
|
|
|
@ -1,27 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
#include <utempl/module.hpp>
|
||||||
|
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
export module utempl.attributes;
|
export module utempl.attributes;
|
||||||
export import utempl.meta_info;
|
export import utempl.meta_info;
|
||||||
export import utempl.tuple;
|
export import utempl.tuple;
|
||||||
export import utempl.loopholes.counter;
|
export import utempl.loopholes.counter;
|
||||||
import utempl.utils;
|
import utempl.utils;
|
||||||
import utempl.type_list;
|
import utempl.type_list;
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <utempl/loopholes/counter.hpp>
|
||||||
|
#include <utempl/meta_info.hpp>
|
||||||
|
#include <utempl/tuple.hpp>
|
||||||
|
#include <utempl/type_list.hpp>
|
||||||
|
#include <utempl/utils.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
export struct AttributesTag {};
|
UTEMPL_EXPORT struct AttributesTag {};
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
struct AttributesCounterTag {};
|
struct AttributesCounterTag {};
|
||||||
|
|
||||||
} // namespace impl
|
} // namespace impl
|
||||||
|
|
||||||
export template <typename T, typename..., auto f = [] {}, auto = AddTypeToTag<impl::AttributesTag, T, decltype(f)>()>
|
UTEMPL_EXPORT template <typename T, typename..., auto f = [] {}, auto = AddTypeToTag<impl::AttributesTag, T, decltype(f)>()>
|
||||||
consteval auto OpenStruct() -> bool {
|
consteval auto OpenStruct() -> bool {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename...,
|
UTEMPL_EXPORT template <typename...,
|
||||||
auto f = [] {},
|
auto f = [] {},
|
||||||
auto I = loopholes::CountValue<impl::AttributesTag, decltype(f)>(),
|
auto I = loopholes::CountValue<impl::AttributesTag, decltype(f)>(),
|
||||||
auto II = (I >= 2) ? I - 2 : I - 1,
|
auto II = (I >= 2) ? I - 2 : I - 1,
|
||||||
|
@ -31,37 +43,24 @@ consteval auto CloseStruct() -> bool {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export struct NoInfo {
|
UTEMPL_EXPORT struct NoInfo {
|
||||||
consteval auto operator==(const NoInfo&) const -> bool = default;
|
consteval auto operator==(const NoInfo&) const -> bool = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename... Ts>
|
UTEMPL_EXPORT template <typename T,
|
||||||
struct FieldAttributeData {
|
typename O = TypeList<>,
|
||||||
using Type = TypeList<Ts...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct FieldAttributeData<> {
|
|
||||||
using Type = NoInfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T,
|
|
||||||
typename... Ts,
|
|
||||||
auto f = [] {},
|
auto f = [] {},
|
||||||
typename Current = decltype(GetCurrentTagType<impl::AttributesTag, decltype(f)>())::Type,
|
typename Current = decltype(GetCurrentTagType<impl::AttributesTag, decltype(f)>())::Type,
|
||||||
auto = AddTypeToTag<impl::AttributesCounterTag<Current>, typename FieldAttributeData<Ts...>::Type, decltype(f)>()>
|
auto = AddTypeToTag<impl::AttributesCounterTag<Current>, O, decltype(f)>()>
|
||||||
consteval auto FieldAttributeHelper() -> T;
|
using FieldAttribute = T;
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename T, auto f = [] {}, bool R = (loopholes::CountValue<impl::AttributesCounterTag<T>, decltype(f)>() > 0)>
|
||||||
using FieldAttribute = decltype(FieldAttributeHelper<Ts...>());
|
|
||||||
|
|
||||||
export template <typename T, auto f = [] {}, bool R = (loopholes::CountValue<impl::AttributesCounterTag<T>, decltype(f)>() > 0)>
|
|
||||||
concept HasAttributes = R;
|
concept HasAttributes = R;
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
concept HasMacroAttributes = requires { T::template GetAttribute<0>(); };
|
concept HasMacroAttributes = requires { T::template GetAttribute<0>(); };
|
||||||
|
|
||||||
export template <HasAttributes T>
|
UTEMPL_EXPORT template <HasAttributes T>
|
||||||
consteval auto GetAttributes()
|
consteval auto GetAttributes()
|
||||||
requires HasMacroAttributes<T>
|
requires HasMacroAttributes<T>
|
||||||
{
|
{
|
||||||
|
@ -71,11 +70,12 @@ consteval auto GetAttributes()
|
||||||
} | kSeq<I>;
|
} | kSeq<I>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
consteval auto GetAttributes() {
|
consteval auto GetAttributes() {
|
||||||
constexpr auto I = loopholes::CountValue<impl::AttributesCounterTag<T>>();
|
constexpr auto I = loopholes::CountValue<impl::AttributesCounterTag<T>>();
|
||||||
return [](auto... is) {
|
return
|
||||||
return utempl::Tuple{typename decltype(Magic(loopholes::Getter<MetaInfoKey<is, impl::AttributesCounterTag<T>>{}>{}))::Type{}...};
|
[](auto... is) -> Tuple<typename decltype(Magic(loopholes::Getter<MetaInfoKey<*is, impl::AttributesCounterTag<T>>{}>{}))::Type...> {
|
||||||
|
return {};
|
||||||
} | kSeq<I>;
|
} | kSeq<I>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,16 @@
|
||||||
module;
|
#pragma once
|
||||||
#include <fmt/compile.h>
|
#include <utempl/module.hpp>
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
export module utempl.string;
|
export module utempl.string;
|
||||||
import std;
|
import std;
|
||||||
// import fmt;
|
#else
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UTEMPL_EXPORT_BEGIN
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
export template <std::size_t>
|
|
||||||
struct ConstexprString;
|
|
||||||
} // namespace utempl
|
|
||||||
|
|
||||||
export {
|
|
||||||
template <std::size_t Size>
|
|
||||||
struct fmt::formatter<utempl::ConstexprString<Size>> : public fmt::formatter<std::string_view> {
|
|
||||||
constexpr auto parse(format_parse_context& ctx) const {
|
|
||||||
return ctx.begin();
|
|
||||||
};
|
|
||||||
constexpr auto format(const utempl::ConstexprString<Size>& str, auto& ctx) const {
|
|
||||||
return fmt::formatter<std::string_view>::format({str.begin()}, ctx);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
export namespace utempl {
|
|
||||||
|
|
||||||
template <std::size_t Size>
|
template <std::size_t Size>
|
||||||
struct ConstexprString {
|
struct ConstexprString {
|
||||||
std::array<char, Size> data;
|
std::array<char, Size> data;
|
||||||
|
@ -43,8 +32,8 @@ struct ConstexprString {
|
||||||
constexpr ConstexprString(const char (&data)[Size]) : data{} { // NOLINT
|
constexpr ConstexprString(const char (&data)[Size]) : data{} { // NOLINT
|
||||||
std::ranges::copy_n(data, Size, this->data.begin());
|
std::ranges::copy_n(data, Size, this->data.begin());
|
||||||
};
|
};
|
||||||
explicit constexpr ConstexprString(std::string data) : data{} {
|
explicit constexpr ConstexprString(std::string_view data) : data{} {
|
||||||
std::ranges::copy_n(data.begin(), Size, this->data.begin());
|
std::ranges::copy_n(data.begin(), data.size() > this->size() ? this->size() : data.size(), this->data.begin());
|
||||||
};
|
};
|
||||||
explicit constexpr ConstexprString(std::array<char, Size> data) : data(std::move(data)) {};
|
explicit constexpr ConstexprString(std::array<char, Size> data) : data(std::move(data)) {};
|
||||||
constexpr auto size() const {
|
constexpr auto size() const {
|
||||||
|
@ -77,11 +66,6 @@ struct ConstexprString {
|
||||||
constexpr ConstexprString(ConstexprString&&) = default;
|
constexpr ConstexprString(ConstexprString&&) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <ConstexprString Str>
|
|
||||||
consteval auto GetFmtCompiledString() {
|
|
||||||
return FMT_COMPILE(Str.data.begin());
|
|
||||||
};
|
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
constexpr auto operator<<(std::ostream& stream, const ConstexprString<N>& str) -> std::ostream& {
|
constexpr auto operator<<(std::ostream& stream, const ConstexprString<N>& str) -> std::ostream& {
|
||||||
stream << static_cast<std::string_view>(str);
|
stream << static_cast<std::string_view>(str);
|
||||||
|
@ -101,3 +85,5 @@ constexpr auto CreateStringWith(char c) {
|
||||||
template <std::size_t Size>
|
template <std::size_t Size>
|
||||||
ConstexprString(const char (&data)[Size]) -> ConstexprString<Size>; // NOLINT
|
ConstexprString(const char (&data)[Size]) -> ConstexprString<Size>; // NOLINT
|
||||||
} // namespace utempl
|
} // namespace utempl
|
||||||
|
|
||||||
|
UTEMPL_EXPORT_END
|
||||||
|
|
|
@ -1,9 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
#include <utempl/module.hpp>
|
||||||
|
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
|
|
||||||
module;
|
module;
|
||||||
#include <boost/pfr.hpp>
|
#include <boost/pfr.hpp>
|
||||||
export module utempl.go_interface;
|
export module utempl.go_interface;
|
||||||
import std;
|
import std;
|
||||||
import utempl.string;
|
import utempl.string;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <boost/pfr.hpp>
|
||||||
|
#include <utempl/constexpr_string.hpp>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
template <ConstexprString name, typename T>
|
template <ConstexprString name, typename T>
|
||||||
|
@ -40,7 +52,7 @@ constexpr auto Transform(Transformer&& transformer, From&& from) {
|
||||||
}(std::make_index_sequence<boost::pfr::tuple_size_v<To>>());
|
}(std::make_index_sequence<boost::pfr::tuple_size_v<To>>());
|
||||||
};
|
};
|
||||||
|
|
||||||
export struct DefaultFieldTransformer {
|
UTEMPL_EXPORT struct DefaultFieldTransformer {
|
||||||
constexpr auto operator()(auto&& arg) -> auto&& {
|
constexpr auto operator()(auto&& arg) -> auto&& {
|
||||||
return arg;
|
return arg;
|
||||||
};
|
};
|
||||||
|
@ -53,7 +65,7 @@ export struct DefaultFieldTransformer {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename Value, typename Transformer = DefaultFieldTransformer>
|
UTEMPL_EXPORT template <typename Value, typename Transformer = DefaultFieldTransformer>
|
||||||
struct GoInterface : Value {
|
struct GoInterface : Value {
|
||||||
constexpr GoInterface(Value&& value) : Value(std::move(value)) {}; // NOLINT
|
constexpr GoInterface(Value&& value) : Value(std::move(value)) {}; // NOLINT
|
||||||
constexpr GoInterface(const Value& value) : Value(value) {}; // NOLINT
|
constexpr GoInterface(const Value& value) : Value(value) {}; // NOLINT
|
||||||
|
|
|
@ -1,20 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utempl/module.hpp>
|
||||||
|
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
|
|
||||||
export module utempl.loopholes.core;
|
export module utempl.loopholes.core;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utempl::loopholes {
|
namespace utempl::loopholes {
|
||||||
|
|
||||||
export {
|
UTEMPL_EXPORT_BEGIN
|
||||||
template <auto I>
|
template <auto I>
|
||||||
struct Getter {
|
struct Getter {
|
||||||
friend constexpr auto Magic(Getter<I>);
|
friend constexpr auto Magic(Getter<I>);
|
||||||
};
|
};
|
||||||
template <auto I, auto Value = 0>
|
template <auto I, auto Value = 0>
|
||||||
struct Injector {
|
struct Injector {
|
||||||
friend constexpr auto Magic(Getter<I>) {
|
friend constexpr auto Magic(Getter<I>) {
|
||||||
return Value;
|
return Value;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
UTEMPL_EXPORT_END
|
||||||
template <auto, typename = void, typename... Ts>
|
template <auto, typename = void, typename... Ts>
|
||||||
struct InjectedImpl {
|
struct InjectedImpl {
|
||||||
static constexpr bool value = false;
|
static constexpr bool value = false;
|
||||||
|
@ -24,7 +36,7 @@ struct InjectedImpl<V, std::void_t<decltype(Magic(Getter<V>{}))>, Ts...> {
|
||||||
static constexpr bool value = true;
|
static constexpr bool value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <auto I, typename... Ts>
|
UTEMPL_EXPORT template <auto I, typename... Ts>
|
||||||
concept Injected = InjectedImpl<I, void, Ts...>::value;
|
concept Injected = InjectedImpl<I, void, Ts...>::value;
|
||||||
|
|
||||||
} // namespace utempl::loopholes
|
} // namespace utempl::loopholes
|
||||||
|
|
|
@ -1,7 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utempl/module.hpp>
|
||||||
|
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
|
|
||||||
export module utempl.loopholes.counter;
|
export module utempl.loopholes.counter;
|
||||||
export import utempl.loopholes.core;
|
export import utempl.loopholes.core;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
#include <utempl/loopholes/core.hpp>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utempl::loopholes {
|
namespace utempl::loopholes {
|
||||||
|
|
||||||
template <typename Tag, std::size_t Value>
|
template <typename Tag, std::size_t Value>
|
||||||
|
@ -20,13 +33,13 @@ consteval auto CounterHelper() -> std::size_t {
|
||||||
};
|
};
|
||||||
|
|
||||||
// For incerement counter need a unique Ts...
|
// For incerement counter need a unique Ts...
|
||||||
export template <typename Tag, typename... Ts, std::size_t R = CounterHelper<true, Tag, 0, Ts...>()>
|
UTEMPL_EXPORT template <typename Tag, typename... Ts, std::size_t R = CounterHelper<true, Tag, 0, Ts...>()>
|
||||||
consteval auto Counter(auto...) -> std::size_t {
|
consteval auto Counter(auto...) -> std::size_t {
|
||||||
return R;
|
return R;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Without increment
|
// Without increment
|
||||||
export template <typename Tag, typename... Ts, std::size_t R = CounterHelper<false, Tag, 0, Ts...>()>
|
UTEMPL_EXPORT template <typename Tag, typename... Ts, std::size_t R = CounterHelper<false, Tag, 0, Ts...>()>
|
||||||
consteval auto CountValue(auto...) -> std::size_t {
|
consteval auto CountValue(auto...) -> std::size_t {
|
||||||
return R;
|
return R;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
|
|
||||||
export module utempl.loopholes;
|
export module utempl.loopholes;
|
||||||
export import utempl.loopholes.core;
|
export import utempl.loopholes.core;
|
||||||
export import utempl.loopholes.counter;
|
export import utempl.loopholes.counter;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <utempl/loopholes/core.hpp>
|
||||||
|
#include <utempl/loopholes/counter.hpp>
|
||||||
|
#endif
|
||||||
|
|
147
src/menu.cpp
147
src/menu.cpp
|
@ -1,147 +0,0 @@
|
||||||
module;
|
|
||||||
#include <cstdio>
|
|
||||||
export module utempl.menu;
|
|
||||||
|
|
||||||
import fmt;
|
|
||||||
import std;
|
|
||||||
import utempl.string;
|
|
||||||
import utempl.optional;
|
|
||||||
import utempl.tuple;
|
|
||||||
import utempl.utils;
|
|
||||||
import utempl.type_list;
|
|
||||||
|
|
||||||
namespace utempl {
|
|
||||||
|
|
||||||
constexpr auto CountDigits(std::size_t num) -> std::size_t {
|
|
||||||
std::size_t count = 0;
|
|
||||||
do { // NOLINT
|
|
||||||
++count;
|
|
||||||
num /= 10; // NOLINT
|
|
||||||
} while(num != 0);
|
|
||||||
return count;
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr auto GetDigit(std::size_t num, std::size_t index) -> std::size_t {
|
|
||||||
for(std::size_t i = 0; i < index; ++i) {
|
|
||||||
num /= 10; // NOLINT
|
|
||||||
}
|
|
||||||
return num % 10; // NOLINT
|
|
||||||
};
|
|
||||||
|
|
||||||
template <std::size_t num>
|
|
||||||
consteval auto ToString() {
|
|
||||||
constexpr std::size_t digits = CountDigits(num);
|
|
||||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
|
||||||
return ConstexprString{std::array{static_cast<char>('0' + GetDigit(num, digits - 1 - Is))..., '\0'}};
|
|
||||||
}(std::make_index_sequence<digits>());
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Range>
|
|
||||||
constexpr auto GetMax(Range&& range) {
|
|
||||||
std::remove_cvref_t<decltype(range[0])> response = 0;
|
|
||||||
for(const auto& element : range) {
|
|
||||||
response = element > response ? element : response;
|
|
||||||
};
|
|
||||||
return response;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace menu {
|
|
||||||
|
|
||||||
template <std::size_t N1, std::size_t N2>
|
|
||||||
struct CallbackMessage {
|
|
||||||
ConstexprString<N1> message;
|
|
||||||
Optional<ConstexprString<N2>> need;
|
|
||||||
consteval CallbackMessage(const char (&need)[N2], const char (&message)[N1]) : // NOLINT
|
|
||||||
message(std::move(message)), need(std::move(need)) {};
|
|
||||||
consteval CallbackMessage(const char (&message)[N1]) : message(std::move(message)), need(std::nullopt) {}; // NOLINT
|
|
||||||
};
|
|
||||||
template <std::size_t N1, std::size_t N2>
|
|
||||||
CallbackMessage(const char (&)[N1], const char (&)[N2]) -> CallbackMessage<N2, N1>; // NOLINT
|
|
||||||
|
|
||||||
template <std::size_t N1>
|
|
||||||
CallbackMessage(const char (&)[N1]) -> CallbackMessage<N1, 0>; // NOLINT
|
|
||||||
|
|
||||||
export template <Tuple storage = Tuple{}, typename... Fs>
|
|
||||||
struct Menu {
|
|
||||||
private:
|
|
||||||
template <ConstexprString fmt, ConstexprString message, ConstexprString alignment, ConstexprString neededInput>
|
|
||||||
static consteval auto FormatMessage() {
|
|
||||||
constexpr auto fmtlib = GetFmtCompiledString<fmt>();
|
|
||||||
// + 1 - NULL Terminator
|
|
||||||
constexpr auto size = fmt::formatted_size(fmtlib,
|
|
||||||
static_cast<std::string_view>(neededInput),
|
|
||||||
static_cast<std::string_view>(message),
|
|
||||||
static_cast<std::string_view>(alignment)) +
|
|
||||||
1;
|
|
||||||
std::array<char, size> data{};
|
|
||||||
fmt::format_to(data.begin(),
|
|
||||||
fmtlib,
|
|
||||||
static_cast<std::string_view>(neededInput),
|
|
||||||
static_cast<std::string_view>(message),
|
|
||||||
static_cast<std::string_view>(alignment));
|
|
||||||
return ConstexprString<size>(data);
|
|
||||||
};
|
|
||||||
template <ConstexprString fmt, std::size_t I>
|
|
||||||
static consteval auto FormatMessageFor() {
|
|
||||||
constexpr ConstexprString message = Get<I>(storage).message;
|
|
||||||
constexpr ConstexprString neededInput = [&] {
|
|
||||||
if constexpr(Get<I>(storage).need) {
|
|
||||||
return *Get<I>(storage).need;
|
|
||||||
} else {
|
|
||||||
return ToString<I>();
|
|
||||||
};
|
|
||||||
}();
|
|
||||||
constexpr ConstexprString alignment =
|
|
||||||
CreateStringWith<GetMaxSize() - (Get<I>(storage).need ? Get<I>(storage).need->size() : CountDigits(I))>(' ');
|
|
||||||
return FormatMessage<fmt, message, alignment, neededInput>();
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
Tuple<Fs...> functionStorage;
|
|
||||||
|
|
||||||
static consteval auto GetMaxSize() -> std::size_t {
|
|
||||||
return [&]<auto... Is>(std::index_sequence<Is...>) {
|
|
||||||
constexpr auto list = ListFromTuple(storage);
|
|
||||||
return GetMax(std::array{(std::remove_cvref_t<decltype(*std::declval<decltype(Get<Is>(list))>().need)>::kSize != 0
|
|
||||||
? std::remove_cvref_t<decltype(*std::declval<decltype(Get<Is>(list))>().need)>::kSize
|
|
||||||
: CountDigits(Is))...});
|
|
||||||
}(std::index_sequence_for<Fs...>());
|
|
||||||
};
|
|
||||||
template <CallbackMessage message, std::invocable F>
|
|
||||||
constexpr auto With(F&& f) const {
|
|
||||||
return Menu<storage + Tuple{message}, Fs..., std::remove_cvref_t<F>>{.functionStorage =
|
|
||||||
this->functionStorage + Tuple(std::forward<F>(f))};
|
|
||||||
};
|
|
||||||
template <ConstexprString fmt, ConstexprString enter = "|> ">
|
|
||||||
constexpr auto Run(std::istream& in = std::cin, std::FILE* out = stdout) const -> std::size_t {
|
|
||||||
return [&]<auto... Is>(std::index_sequence<Is...>) -> std::size_t {
|
|
||||||
constexpr auto message = ((FormatMessageFor<fmt, Is>() + ...) + enter);
|
|
||||||
auto result = std::fwrite(message.begin(), 1, message.size(), out);
|
|
||||||
if(result < message.size()) {
|
|
||||||
return EOF;
|
|
||||||
};
|
|
||||||
if(std::fflush(out) != 0) {
|
|
||||||
return EOF;
|
|
||||||
};
|
|
||||||
std::string input;
|
|
||||||
std::getline(in, input);
|
|
||||||
(
|
|
||||||
[&]<auto I, CallbackMessage message = Get<I>(storage)>(Wrapper<I>) {
|
|
||||||
if constexpr(message.need) {
|
|
||||||
if(*message.need == input) {
|
|
||||||
Get<I>(this->functionStorage)();
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
if(ToString<I>() == input) {
|
|
||||||
Get<I>(this->functionStorage)();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}(Wrapper<Is>{}),
|
|
||||||
...);
|
|
||||||
return 0;
|
|
||||||
}(std::index_sequence_for<Fs...>());
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace menu
|
|
||||||
} // namespace utempl
|
|
|
@ -1,16 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
#include <utempl/module.hpp>
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
export module utempl.meta_info;
|
export module utempl.meta_info;
|
||||||
import utempl.loopholes;
|
import utempl.loopholes;
|
||||||
import utempl.type_list;
|
import utempl.type_list;
|
||||||
import std;
|
import std;
|
||||||
|
#else
|
||||||
|
#include <utempl/loopholes/counter.hpp>
|
||||||
|
#include <utempl/type_list.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
export struct Types {};
|
UTEMPL_EXPORT struct Types {};
|
||||||
|
|
||||||
export template <std::size_t Id, typename Tag>
|
UTEMPL_EXPORT template <std::size_t Id, typename Tag>
|
||||||
struct MetaInfoKey {};
|
struct MetaInfoKey {};
|
||||||
|
|
||||||
export template <typename T, typename Tag = Types>
|
UTEMPL_EXPORT template <typename T, typename Tag = Types>
|
||||||
struct MetaInfo {
|
struct MetaInfo {
|
||||||
static constexpr std::size_t kTypeId = loopholes::Counter<Tag, T>();
|
static constexpr std::size_t kTypeId = loopholes::Counter<Tag, T>();
|
||||||
using Type = T;
|
using Type = T;
|
||||||
|
@ -19,10 +26,10 @@ struct MetaInfo {
|
||||||
static constexpr auto _ = loopholes::Injector<MetaInfoKey<kTypeId, Tag>{}, TypeList<T>{}>{};
|
static constexpr auto _ = loopholes::Injector<MetaInfoKey<kTypeId, Tag>{}, TypeList<T>{}>{};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename T, typename Tag = Types>
|
UTEMPL_EXPORT template <typename T, typename Tag = Types>
|
||||||
inline constexpr std::size_t kTypeId = MetaInfo<T, Tag>::kTypeId;
|
inline constexpr std::size_t kTypeId = MetaInfo<T, Tag>::kTypeId;
|
||||||
|
|
||||||
export template <typename Tag,
|
UTEMPL_EXPORT template <typename Tag,
|
||||||
typename T,
|
typename T,
|
||||||
typename... Ts,
|
typename... Ts,
|
||||||
typename... TTs,
|
typename... TTs,
|
||||||
|
@ -32,10 +39,10 @@ consteval auto AddTypeToTag(TTs&&...) -> std::size_t {
|
||||||
return Id;
|
return Id;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <std::size_t Id, typename Tag = Types>
|
UTEMPL_EXPORT template <std::size_t Id, typename Tag = Types>
|
||||||
using GetMetaInfo = MetaInfo<typename decltype(Magic(loopholes::Getter<MetaInfoKey<Id, Tag>{}>{}))::Type>;
|
using GetMetaInfo = MetaInfo<typename decltype(Magic(loopholes::Getter<MetaInfoKey<Id, Tag>{}>{}))::Type>;
|
||||||
|
|
||||||
export template <std::size_t Id, typename Tag = Types>
|
UTEMPL_EXPORT template <std::size_t Id, typename Tag = Types>
|
||||||
using GetType = GetMetaInfo<Id, Tag>::Type;
|
using GetType = GetMetaInfo<Id, Tag>::Type;
|
||||||
|
|
||||||
template <typename Tag, std::size_t I = 0, typename... Ts, typename G>
|
template <typename Tag, std::size_t I = 0, typename... Ts, typename G>
|
||||||
|
@ -55,12 +62,12 @@ static consteval auto GetTypeListForTag(G g)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename Tag = Types, typename... Ts>
|
UTEMPL_EXPORT template <typename Tag = Types, typename... Ts>
|
||||||
consteval auto GetTypeListForTag() {
|
consteval auto GetTypeListForTag() {
|
||||||
return GetTypeListForTag<Tag>(TypeList<Ts...>{});
|
return GetTypeListForTag<Tag>(TypeList<Ts...>{});
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename Tag, typename... Ts, auto I = utempl::loopholes::CountValue<Tag, Ts...>() - 1>
|
UTEMPL_EXPORT template <typename Tag, typename... Ts, auto I = utempl::loopholes::CountValue<Tag, Ts...>() - 1>
|
||||||
consteval auto GetCurrentTagType() {
|
consteval auto GetCurrentTagType() {
|
||||||
return Magic(utempl::loopholes::Getter<MetaInfoKey<I, Tag>{}>());
|
return Magic(utempl::loopholes::Getter<MetaInfoKey<I, Tag>{}>());
|
||||||
};
|
};
|
||||||
|
|
20
src/module.hpp
Normal file
20
src/module.hpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
|
|
||||||
|
#define UTEMPL_EXPORT export
|
||||||
|
|
||||||
|
#define UTEMPL_EXPORT_BEGIN export {
|
||||||
|
#define UTEMPL_EXPORT_END }
|
||||||
|
#define UTEMPL_GLOBAL_MODULE module;
|
||||||
|
#define UTEMPL_IMPORT(modules, headers) modules
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define UTEMPL_EXPORT
|
||||||
|
#define UTEMPL_EXPORT_BEGIN
|
||||||
|
#define UTEMPL_EXPORT_END
|
||||||
|
#define UTEMPL_GLOBAL_MODULE
|
||||||
|
#define UTEMPL_IMPORT(modules, headers) headers
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,9 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
#include <utempl/module.hpp>
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
export module utempl.optional;
|
export module utempl.optional;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
struct Optional { // NOLINT
|
struct Optional { // NOLINT
|
||||||
bool flag = false;
|
bool flag = false;
|
||||||
union {
|
union {
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
#include <utempl/module.hpp>
|
||||||
|
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
export module utempl.overloaded;
|
export module utempl.overloaded;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <type_traits>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
export template <typename... Fs>
|
UTEMPL_EXPORT template <typename... Fs>
|
||||||
constexpr auto Overloaded(Fs&&... fs) {
|
constexpr auto Overloaded(Fs&&... fs) {
|
||||||
struct Overloaded : public std::remove_cvref_t<Fs>... {
|
struct Overloaded : public std::remove_cvref_t<Fs>... {
|
||||||
using Fs::operator()...;
|
using Fs::operator()...;
|
||||||
|
|
80
src/public_cast.cpp
Normal file
80
src/public_cast.cpp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utempl/module.hpp>
|
||||||
|
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
|
|
||||||
|
export module utempl.public_cast;
|
||||||
|
import utempl.loopholes;
|
||||||
|
import std;
|
||||||
|
import utempl.overloaded;
|
||||||
|
import utempl.string;
|
||||||
|
import nameof;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <nameof.hpp>
|
||||||
|
#include <utempl/loopholes/counter.hpp>
|
||||||
|
#include <utempl/overloaded.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace utempl {
|
||||||
|
|
||||||
|
namespace impl { // For headers
|
||||||
|
|
||||||
|
template <typename T, ConstexprString Str>
|
||||||
|
struct PublicCast {
|
||||||
|
template <std::size_t I>
|
||||||
|
struct Tag {};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Ptr>
|
||||||
|
using MainT = decltype(Overloaded([]<typename T, typename R, typename... Args>(R (T::*ptr)(Args...)) -> T {},
|
||||||
|
[]<typename T, typename R, typename... Args>(R (T::*ptr)(Args...) const) -> T {},
|
||||||
|
[]<typename T, typename R>(R T::* ptr) -> T {})(std::declval<Ptr>()));
|
||||||
|
|
||||||
|
template <auto ptr>
|
||||||
|
constexpr auto TransformPtr() {
|
||||||
|
return utempl::Overloaded(
|
||||||
|
[]<typename T, typename R, typename... Args>(R (T::*)(Args...)) {
|
||||||
|
return [](T* obj, Args... args) -> R {
|
||||||
|
return (obj->*ptr)(std::forward<Args>(args)...);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[]<typename T, typename R, typename... Args>(R (T::*)(Args...) const) {
|
||||||
|
return [](const T* obj, Args... args) -> R {
|
||||||
|
return (obj->*ptr)(std::forward<Args>(args)...);
|
||||||
|
};
|
||||||
|
})(ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
|
UTEMPL_EXPORT template <auto Ptr,
|
||||||
|
auto F = [] {},
|
||||||
|
typename T = impl::MainT<decltype(Ptr)>,
|
||||||
|
ConstexprString Str =
|
||||||
|
utempl::ConstexprString<nameof::nameof_member<Ptr>().size() + 1>{nameof::nameof_member<Ptr>()},
|
||||||
|
typename Tag = impl::PublicCast<T, Str>,
|
||||||
|
auto I = loopholes::Counter<Tag, decltype(F)>(),
|
||||||
|
auto = loopholes::Injector<typename Tag::template Tag<I>{}, Ptr>{}>
|
||||||
|
struct PublicCast {};
|
||||||
|
|
||||||
|
UTEMPL_EXPORT template <ConstexprString Name, std::size_t I = 0, typename T>
|
||||||
|
constexpr auto GetPrivateMember() -> decltype(Magic(loopholes::Getter<typename impl::PublicCast<T, Name>::template Tag<I>{}>{})) {
|
||||||
|
return Magic(loopholes::Getter<typename impl::PublicCast<T, Name>::template Tag<I>{}>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEMPL_EXPORT template <ConstexprString Name, std::size_t I = 0, typename T>
|
||||||
|
constexpr auto GetPrivateMember(const T&) -> decltype(GetPrivateMember<Name, I, std::decay_t<T>>()) {
|
||||||
|
return GetPrivateMember<Name, I, std::decay_t<T>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
UTEMPL_EXPORT template <utempl::ConstexprString Name, typename T, auto F = [] {}, typename... Args>
|
||||||
|
constexpr auto GetPrivateMemberOverloaded(T&& obj, Args&&... args) -> decltype(auto) {
|
||||||
|
return [&]<std::size_t... Is>(std::index_sequence<Is...>) -> decltype(auto) {
|
||||||
|
return Overloaded(impl::TransformPtr<GetPrivateMember<Name, Is, std::decay_t<T>>()>()...)(std::addressof(obj),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}(std::make_index_sequence<loopholes::CountValue<impl::PublicCast<std::decay_t<T>, Name>, decltype(F)>()>());
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utempl
|
|
@ -1,12 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utempl/module.hpp>
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
|
|
||||||
export module utempl.tuple;
|
export module utempl.tuple;
|
||||||
|
|
||||||
import utempl.type_list;
|
import utempl.type_list;
|
||||||
import utempl.overloaded;
|
import utempl.overloaded;
|
||||||
import std;
|
import std;
|
||||||
|
#else
|
||||||
|
#include <utempl/type_list.hpp>
|
||||||
|
#include <utility>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
export template <auto Value>
|
UTEMPL_EXPORT template <auto Value>
|
||||||
struct Wrapper {
|
struct Wrapper {
|
||||||
static constexpr auto kValue = Value;
|
static constexpr auto kValue = Value;
|
||||||
static constexpr auto value = Value;
|
static constexpr auto value = Value;
|
||||||
|
@ -35,10 +44,10 @@ struct TupleHelper<std::index_sequence<Is...>, Ts...> : public TupleLeaf<Is, Ts>
|
||||||
constexpr auto operator==(const TupleHelper&) const -> bool = default;
|
constexpr auto operator==(const TupleHelper&) const -> bool = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
struct Tuple;
|
struct Tuple;
|
||||||
|
|
||||||
export template <std::size_t I, typename... Ts>
|
UTEMPL_EXPORT template <std::size_t I, typename... Ts>
|
||||||
constexpr auto Get(Tuple<Ts...>& tuple) -> auto&
|
constexpr auto Get(Tuple<Ts...>& tuple) -> auto&
|
||||||
requires(I < sizeof...(Ts))
|
requires(I < sizeof...(Ts))
|
||||||
{
|
{
|
||||||
|
@ -46,7 +55,7 @@ constexpr auto Get(Tuple<Ts...>& tuple) -> auto&
|
||||||
return static_cast<TupleLeaf<I, Type>&>(tuple).value;
|
return static_cast<TupleLeaf<I, Type>&>(tuple).value;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <std::size_t I, typename... Ts>
|
UTEMPL_EXPORT template <std::size_t I, typename... Ts>
|
||||||
constexpr auto Get(const Tuple<Ts...>& tuple) -> const auto&
|
constexpr auto Get(const Tuple<Ts...>& tuple) -> const auto&
|
||||||
requires(I < sizeof...(Ts))
|
requires(I < sizeof...(Ts))
|
||||||
{
|
{
|
||||||
|
@ -54,7 +63,7 @@ constexpr auto Get(const Tuple<Ts...>& tuple) -> const auto&
|
||||||
return static_cast<const TupleLeaf<I, Type>&>(tuple).value;
|
return static_cast<const TupleLeaf<I, Type>&>(tuple).value;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <std::size_t I, typename... Ts>
|
UTEMPL_EXPORT template <std::size_t I, typename... Ts>
|
||||||
constexpr auto Get(Tuple<Ts...>&& tuple) -> decltype(auto)
|
constexpr auto Get(Tuple<Ts...>&& tuple) -> decltype(auto)
|
||||||
requires(I < sizeof...(Ts))
|
requires(I < sizeof...(Ts))
|
||||||
{
|
{
|
||||||
|
@ -62,12 +71,12 @@ constexpr auto Get(Tuple<Ts...>&& tuple) -> decltype(auto)
|
||||||
return std::move(static_cast<TupleLeaf<I, Type>&&>(tuple).value);
|
return std::move(static_cast<TupleLeaf<I, Type>&&>(tuple).value);
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <std::size_t I, typename T>
|
UTEMPL_EXPORT template <std::size_t I, typename T>
|
||||||
constexpr auto Get(T&& arg) -> decltype(get<I>(std::forward<T>(arg))) {
|
constexpr auto Get(T&& arg) -> decltype(get<I>(std::forward<T>(arg))) {
|
||||||
return get<I>(std::forward<T>(arg));
|
return get<I>(std::forward<T>(arg));
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
struct Tuple : TupleHelper<std::index_sequence_for<Ts...>, Ts...> {
|
struct Tuple : TupleHelper<std::index_sequence_for<Ts...>, Ts...> {
|
||||||
template <typename... TTs>
|
template <typename... TTs>
|
||||||
constexpr Tuple(TTs&&... args) /* NOLINT */ : TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{std::forward<TTs>(args)}...} {};
|
constexpr Tuple(TTs&&... args) /* NOLINT */ : TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{std::forward<TTs>(args)}...} {};
|
||||||
|
@ -106,7 +115,7 @@ struct Tuple : TupleHelper<std::index_sequence_for<Ts...>, Ts...> {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <>
|
UTEMPL_EXPORT template <>
|
||||||
struct Tuple<> {
|
struct Tuple<> {
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
constexpr auto operator+(const Tuple<Ts...>& other) const -> Tuple<Ts...> {
|
constexpr auto operator+(const Tuple<Ts...>& other) const -> Tuple<Ts...> {
|
||||||
|
@ -116,10 +125,10 @@ struct Tuple<> {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
Tuple(Ts&&...) -> Tuple<std::decay_t<Ts>...>;
|
Tuple(Ts&&...) -> Tuple<std::decay_t<Ts>...>;
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
consteval auto ListFromTuple(Tuple<Ts...>) -> TypeList<Ts...> {
|
consteval auto ListFromTuple(Tuple<Ts...>) -> TypeList<Ts...> {
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,25 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utempl/module.hpp>
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
|
|
||||||
export module utempl.type_list;
|
export module utempl.type_list;
|
||||||
|
|
||||||
import std;
|
import std;
|
||||||
import utempl.overloaded;
|
import utempl.overloaded;
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <utempl/overloaded.hpp>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
struct TypeList {};
|
struct TypeList {};
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
struct TypeList<T> {
|
struct TypeList<T> {
|
||||||
using Type = T;
|
using Type = T;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
inline constexpr auto kType = TypeList<T>{};
|
inline constexpr auto kType = TypeList<T>{};
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
inline constexpr auto kTypeList = TypeList<Ts...>{};
|
inline constexpr auto kTypeList = TypeList<Ts...>{};
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
concept IsTypeList = Overloaded(
|
concept IsTypeList = Overloaded(
|
||||||
[]<typename... Ts>(TypeList<TypeList<Ts...>>) {
|
[]<typename... Ts>(TypeList<TypeList<Ts...>>) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -37,45 +48,45 @@ struct Caster {};
|
||||||
template <std::size_t... Is, typename... Ts>
|
template <std::size_t... Is, typename... Ts>
|
||||||
struct Caster<std::index_sequence<Is...>, Ts...> : IndexedType<Is, Ts>... {};
|
struct Caster<std::index_sequence<Is...>, Ts...> : IndexedType<Is, Ts>... {};
|
||||||
|
|
||||||
export template <typename... Ts, typename... TTs>
|
UTEMPL_EXPORT template <typename... Ts, typename... TTs>
|
||||||
consteval auto operator==(const TypeList<Ts...>& first, const TypeList<TTs...>& second) -> bool {
|
consteval auto operator==(const TypeList<Ts...>& first, const TypeList<TTs...>& second) -> bool {
|
||||||
return std::same_as<decltype(first), decltype(second)>;
|
return std::same_as<decltype(first), decltype(second)>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename... Ts, typename... TTs>
|
UTEMPL_EXPORT template <typename... Ts, typename... TTs>
|
||||||
consteval auto operator+(const TypeList<Ts...>&, const TypeList<TTs...>&) -> TypeList<Ts..., TTs...> {
|
consteval auto operator+(const TypeList<Ts...>&, const TypeList<TTs...>&) -> TypeList<Ts..., TTs...> {
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <std::size_t I, typename... Ts>
|
UTEMPL_EXPORT template <std::size_t I, typename... Ts>
|
||||||
consteval auto Get(TypeList<Ts...>) -> decltype([]<typename T>(IndexedType<I, T>&&) -> T {
|
consteval auto Get(TypeList<Ts...>) -> decltype([]<typename T>(IndexedType<I, T>&&) -> T {
|
||||||
}(Caster<std::index_sequence_for<Ts...>, Ts...>{}));
|
}(Caster<std::index_sequence_for<Ts...>, Ts...>{}));
|
||||||
|
|
||||||
export template <typename T, typename... Ts>
|
UTEMPL_EXPORT template <typename T, typename... Ts>
|
||||||
consteval auto Find(TypeList<Ts...>) -> std::size_t {
|
consteval auto Find(TypeList<Ts...>) -> std::size_t {
|
||||||
std::array<bool, sizeof...(Ts)> arr{std::same_as<T, Ts>...};
|
std::array<bool, sizeof...(Ts)> arr{std::same_as<T, Ts>...};
|
||||||
return std::ranges::find(arr, true) - arr.begin();
|
return std::ranges::find(arr, true) - arr.begin();
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <template <typename...> typename F, typename... Ts>
|
UTEMPL_EXPORT template <template <typename...> typename F, typename... Ts>
|
||||||
consteval auto Find(TypeList<Ts...>) -> std::size_t {
|
consteval auto Find(TypeList<Ts...>) -> std::size_t {
|
||||||
std::array<bool, sizeof...(Ts)> arr{F<Ts>::value...};
|
std::array<bool, sizeof...(Ts)> arr{F<Ts>::value...};
|
||||||
return std::ranges::find(arr, true) - arr.begin();
|
return std::ranges::find(arr, true) - arr.begin();
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
consteval auto Reverse(TypeList<Ts...> list) {
|
consteval auto Reverse(TypeList<Ts...> list) {
|
||||||
return [&]<auto... Is>(std::index_sequence<Is...>) -> TypeList<decltype(Get<sizeof...(Ts) - Is - 1>(list))...> {
|
return [&]<auto... Is>(std::index_sequence<Is...>) -> TypeList<decltype(Get<sizeof...(Ts) - Is - 1>(list))...> {
|
||||||
return {};
|
return {};
|
||||||
}(std::index_sequence_for<Ts...>());
|
}(std::index_sequence_for<Ts...>());
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
consteval auto Transform(TypeList<Ts...>, auto&& f) -> TypeList<decltype(f(TypeList<Ts>{}))...> {
|
consteval auto Transform(TypeList<Ts...>, auto&& f) -> TypeList<decltype(f(TypeList<Ts>{}))...> {
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
consteval auto FilterTypeList(TypeList<Ts...>, auto&& f) {
|
consteval auto FilterTypeList(TypeList<Ts...>, auto&& f) {
|
||||||
return ((kTypeList<> +
|
return ((kTypeList<> +
|
||||||
[](auto&& list) {
|
[](auto&& list) {
|
||||||
|
@ -88,12 +99,12 @@ consteval auto FilterTypeList(TypeList<Ts...>, auto&& f) {
|
||||||
...);
|
...);
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
consteval auto Size(TypeList<Ts...>) -> std::size_t {
|
consteval auto Size(TypeList<Ts...>) -> std::size_t {
|
||||||
return sizeof...(Ts);
|
return sizeof...(Ts);
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <std::size_t N, std::size_t From = 0, typename... Ts>
|
UTEMPL_EXPORT template <std::size_t N, std::size_t From = 0, typename... Ts>
|
||||||
consteval auto TakeFrom(TypeList<Ts...> list)
|
consteval auto TakeFrom(TypeList<Ts...> list)
|
||||||
requires(N + From <= sizeof...(Ts))
|
requires(N + From <= sizeof...(Ts))
|
||||||
{
|
{
|
||||||
|
@ -102,12 +113,12 @@ consteval auto TakeFrom(TypeList<Ts...> list)
|
||||||
}(std::make_index_sequence<N>());
|
}(std::make_index_sequence<N>());
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename T, std::size_t N, typename... Ts>
|
UTEMPL_EXPORT template <typename T, std::size_t N, typename... Ts>
|
||||||
consteval auto PushTo(TypeList<Ts...> list) {
|
consteval auto PushTo(TypeList<Ts...> list) {
|
||||||
return TakeFrom<N>(list) + kType<T> + TakeFrom<sizeof...(Ts) - N, N>(list);
|
return TakeFrom<N>(list) + kType<T> + TakeFrom<sizeof...(Ts) - N, N>(list);
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <std::size_t N, typename... Ts>
|
UTEMPL_EXPORT template <std::size_t N, typename... Ts>
|
||||||
consteval auto Erase(TypeList<Ts...> list) {
|
consteval auto Erase(TypeList<Ts...> list) {
|
||||||
return TakeFrom<N>(list) + TakeFrom<sizeof...(Ts) - N - 1, N + 1>(list);
|
return TakeFrom<N>(list) + TakeFrom<sizeof...(Ts) - N - 1, N + 1>(list);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
export module utempl;
|
|
||||||
export import utempl.type_list;
|
|
||||||
export import utempl.tuple;
|
|
||||||
export import utempl.string;
|
|
||||||
export import utempl.menu;
|
|
||||||
export import utempl.loopholes;
|
|
||||||
export import utempl.attributes;
|
|
||||||
export import utempl.meta_info;
|
|
||||||
export import utempl.overloaded;
|
|
||||||
export import utempl.utils;
|
|
||||||
export import utempl.go_interface;
|
|
||||||
export import utempl.optional;
|
|
7
src/utempl.hpp
Normal file
7
src/utempl.hpp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
|
import utempl;
|
||||||
|
#else
|
||||||
|
#include <utempl/utempl_module.hpp>
|
||||||
|
#endif
|
31
src/utempl_module.cpp
Normal file
31
src/utempl_module.cpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
|
|
||||||
|
export module utempl;
|
||||||
|
export import utempl.type_list;
|
||||||
|
export import utempl.tuple;
|
||||||
|
export import utempl.string;
|
||||||
|
export import utempl.loopholes;
|
||||||
|
export import utempl.attributes;
|
||||||
|
export import utempl.meta_info;
|
||||||
|
export import utempl.overloaded;
|
||||||
|
export import utempl.utils;
|
||||||
|
export import utempl.go_interface;
|
||||||
|
export import utempl.optional;
|
||||||
|
export import utempl.public_cast;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <utempl/attributes.hpp>
|
||||||
|
#include <utempl/constexpr_string.hpp>
|
||||||
|
#include <utempl/go_interface.hpp>
|
||||||
|
#include <utempl/loopholes/counter.hpp>
|
||||||
|
#include <utempl/macro.hpp>
|
||||||
|
#include <utempl/meta_info.hpp>
|
||||||
|
#include <utempl/optional.hpp>
|
||||||
|
#include <utempl/overloaded.hpp>
|
||||||
|
#include <utempl/public_cast.hpp>
|
||||||
|
#include <utempl/tuple.hpp>
|
||||||
|
#include <utempl/type_list.hpp>
|
||||||
|
|
||||||
|
#endif
|
132
src/utils.cpp
132
src/utils.cpp
|
@ -1,27 +1,39 @@
|
||||||
export module utempl.utils;
|
#pragma once
|
||||||
|
|
||||||
|
#include <utempl/module.hpp>
|
||||||
|
|
||||||
|
#ifdef UTEMPL_MODULE
|
||||||
|
export module utempl.utils;
|
||||||
import std;
|
import std;
|
||||||
import fmt;
|
|
||||||
import utempl.string;
|
import utempl.string;
|
||||||
import utempl.tuple;
|
import utempl.tuple;
|
||||||
import utempl.type_list;
|
import utempl.type_list;
|
||||||
import utempl.overloaded;
|
import utempl.overloaded;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <optional>
|
||||||
|
#include <utempl/constexpr_string.hpp>
|
||||||
|
#include <utempl/overloaded.hpp>
|
||||||
|
#include <utempl/tuple.hpp>
|
||||||
|
#include <utempl/type_list.hpp>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using ForwardType = decltype(std::forward<T>(std::declval<T>()));
|
using ForwardType = decltype(std::forward<T>(std::declval<T>()));
|
||||||
|
|
||||||
export template <auto Value>
|
UTEMPL_EXPORT template <auto Value>
|
||||||
constexpr Wrapper<Value> kWrapper;
|
constexpr Wrapper<Value> kWrapper;
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
requires std::same_as<T, void> || requires { T{}; }
|
requires std::same_as<T, void> || requires { T{}; }
|
||||||
constexpr auto kDefaultCreator = [] {
|
constexpr auto kDefaultCreator = [] {
|
||||||
return T{};
|
return T{};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <>
|
UTEMPL_EXPORT template <>
|
||||||
constexpr auto kDefaultCreator<void> = [] {};
|
constexpr auto kDefaultCreator<void> = [] {};
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
|
@ -47,7 +59,7 @@ concept Function = []<typename R, typename... Ts>(TypeList<R(Ts...)>) {
|
||||||
|
|
||||||
static_assert(Function<decltype([]() {}), void()>);
|
static_assert(Function<decltype([]() {}), void()>);
|
||||||
|
|
||||||
export template <std::size_t N>
|
UTEMPL_EXPORT template <std::size_t N>
|
||||||
constexpr kSeqType<N> kSeq;
|
constexpr kSeqType<N> kSeq;
|
||||||
|
|
||||||
template <ConstexprString string, typename T = std::size_t>
|
template <ConstexprString string, typename T = std::size_t>
|
||||||
|
@ -62,14 +74,14 @@ consteval auto ParseNumber() -> T {
|
||||||
};
|
};
|
||||||
namespace literals {
|
namespace literals {
|
||||||
|
|
||||||
export template <char... cs>
|
UTEMPL_EXPORT template <char... cs>
|
||||||
consteval auto operator"" _c() {
|
consteval auto operator"" _c() {
|
||||||
return Wrapper<ParseNumber<ConstexprString<sizeof...(cs)>({cs...})>()>{};
|
return Wrapper<ParseNumber<ConstexprString<sizeof...(cs)>({cs...})>()>{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace literals
|
} // namespace literals
|
||||||
|
|
||||||
export template <std::size_t I, typename... Ts>
|
UTEMPL_EXPORT template <std::size_t I, typename... Ts>
|
||||||
constexpr auto Arg(Ts&&... args) -> decltype(auto)
|
constexpr auto Arg(Ts&&... args) -> decltype(auto)
|
||||||
requires(I < sizeof...(Ts))
|
requires(I < sizeof...(Ts))
|
||||||
{
|
{
|
||||||
|
@ -80,52 +92,52 @@ constexpr auto Arg(Ts&&... args) -> decltype(auto)
|
||||||
}(std::make_index_sequence<I>());
|
}(std::make_index_sequence<I>());
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <std::size_t Count>
|
UTEMPL_EXPORT template <std::size_t Count>
|
||||||
constexpr auto Times(auto&& f) {
|
constexpr auto Times(auto&& f) {
|
||||||
[&]<auto... Is>(std::index_sequence<Is...>) {
|
[&]<auto... Is>(std::index_sequence<Is...>) {
|
||||||
(Arg<0>(f, Is)(), ...);
|
(Arg<0>(f, Is)(), ...);
|
||||||
}(std::make_index_sequence<Count>());
|
}(std::make_index_sequence<Count>());
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
constexpr std::size_t kTupleSize = []() -> std::size_t {
|
constexpr std::size_t kTupleSize = []() -> std::size_t {
|
||||||
static_assert(!sizeof(T), "Not Found");
|
static_assert(!sizeof(T), "Not Found");
|
||||||
return 0;
|
return 0;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
constexpr std::size_t kTupleSize<T&&> = kTupleSize<std::remove_reference_t<T>>;
|
constexpr std::size_t kTupleSize<T&&> = kTupleSize<std::remove_reference_t<T>>;
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
constexpr std::size_t kTupleSize<T&> = kTupleSize<std::remove_reference_t<T>>;
|
constexpr std::size_t kTupleSize<T&> = kTupleSize<std::remove_reference_t<T>>;
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
constexpr std::size_t kTupleSize<const T> = kTupleSize<std::remove_cv_t<T>>;
|
constexpr std::size_t kTupleSize<const T> = kTupleSize<std::remove_cv_t<T>>;
|
||||||
|
|
||||||
export template <template <typename...> typename M, typename... Ts>
|
UTEMPL_EXPORT template <template <typename...> typename M, typename... Ts>
|
||||||
constexpr std::size_t kTupleSize<M<Ts...>> = sizeof...(Ts);
|
constexpr std::size_t kTupleSize<M<Ts...>> = sizeof...(Ts);
|
||||||
|
|
||||||
export template <template <typename, std::size_t> typename Array, typename T, std::size_t N>
|
UTEMPL_EXPORT template <template <typename, std::size_t> typename Array, typename T, std::size_t N>
|
||||||
constexpr std::size_t kTupleSize<Array<T, N>> = N;
|
constexpr std::size_t kTupleSize<Array<T, N>> = N;
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
struct TupleMaker {};
|
struct TupleMaker {};
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
struct TupleMaker<std::tuple<Ts...>> {
|
struct TupleMaker<std::tuple<Ts...>> {
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static constexpr auto Make(Args&&... args) {
|
static constexpr auto Make(Args&&... args) {
|
||||||
return std::tuple{std::forward<Args>(args)...};
|
return std::tuple{std::forward<Args>(args)...};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
struct TupleMaker<Tuple<Ts...>> {
|
struct TupleMaker<Tuple<Ts...>> {
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static constexpr auto Make(Args&&... args) {
|
static constexpr auto Make(Args&&... args) {
|
||||||
return Tuple{std::forward<Args>(args)...};
|
return Tuple{std::forward<Args>(args)...};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export template <typename T, std::size_t N>
|
UTEMPL_EXPORT template <typename T, std::size_t N>
|
||||||
struct TupleMaker<std::array<T, N>> {
|
struct TupleMaker<std::array<T, N>> {
|
||||||
template <typename Arg, typename... Args>
|
template <typename Arg, typename... Args>
|
||||||
static constexpr auto Make(Arg&& arg, Args&&... args)
|
static constexpr auto Make(Arg&& arg, Args&&... args)
|
||||||
|
@ -138,10 +150,10 @@ struct TupleMaker<std::array<T, N>> {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
struct TupleTieMaker {};
|
struct TupleTieMaker {};
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
struct TupleTieMaker<std::tuple<Ts...>> {
|
struct TupleTieMaker<std::tuple<Ts...>> {
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static constexpr auto Make(Args&... args) -> std::tuple<Args...> {
|
static constexpr auto Make(Args&... args) -> std::tuple<Args...> {
|
||||||
|
@ -149,7 +161,7 @@ struct TupleTieMaker<std::tuple<Ts...>> {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
struct TupleTieMaker<Tuple<Ts...>> {
|
struct TupleTieMaker<Tuple<Ts...>> {
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static constexpr auto Make(Args&... args) -> Tuple<Args...> {
|
static constexpr auto Make(Args&... args) -> Tuple<Args...> {
|
||||||
|
@ -157,12 +169,12 @@ struct TupleTieMaker<Tuple<Ts...>> {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename T = Tuple<>, typename... Args>
|
UTEMPL_EXPORT template <typename T = Tuple<>, typename... Args>
|
||||||
constexpr auto MakeTuple(Args&&... args) -> decltype(TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...)) {
|
constexpr auto MakeTuple(Args&&... args) -> decltype(TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...)) {
|
||||||
return TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...);
|
return TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...);
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename T = Tuple<>, typename... Args>
|
UTEMPL_EXPORT template <typename T = Tuple<>, typename... Args>
|
||||||
constexpr auto MakeTie(Args&... args) -> decltype(TupleTieMaker<std::remove_cvref_t<T>>::Make(args...)) {
|
constexpr auto MakeTie(Args&... args) -> decltype(TupleTieMaker<std::remove_cvref_t<T>>::Make(args...)) {
|
||||||
return TupleTieMaker<std::remove_cvref_t<T>>::Make(args...);
|
return TupleTieMaker<std::remove_cvref_t<T>>::Make(args...);
|
||||||
};
|
};
|
||||||
|
@ -210,17 +222,17 @@ struct IsSafeTuple<
|
||||||
static constexpr bool value = false;
|
static constexpr bool value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
constexpr bool kForceEnableTuple = false;
|
constexpr bool kForceEnableTuple = false;
|
||||||
|
|
||||||
export template <typename T, std::size_t N>
|
UTEMPL_EXPORT template <typename T, std::size_t N>
|
||||||
constexpr bool kForceEnableTuple<std::array<T, N>> = true;
|
constexpr bool kForceEnableTuple<std::array<T, N>> = true;
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
concept TupleLike = kForceEnableTuple<std::remove_cvref_t<T>> ||
|
concept TupleLike = kForceEnableTuple<std::remove_cvref_t<T>> ||
|
||||||
(requires { Get<0>(MakeTuple<T>(42)); } && IsSafeTuple<std::remove_cvref_t<T>>::value); // NOLINT
|
(requires { Get<0>(MakeTuple<T>(42)); } && IsSafeTuple<std::remove_cvref_t<T>>::value); // NOLINT
|
||||||
|
|
||||||
export template <typename F, typename Tuple>
|
UTEMPL_EXPORT template <typename F, typename Tuple>
|
||||||
concept TupleTransformer = requires(F f, Tuple&& tuple) {
|
concept TupleTransformer = requires(F f, Tuple&& tuple) {
|
||||||
{ f(std::move(tuple)) };
|
{ f(std::move(tuple)) };
|
||||||
};
|
};
|
||||||
|
@ -304,7 +316,7 @@ struct TupleMaker<LazyTuple<F>> {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike Tuple, TupleTransformer<Tuple> FF>
|
UTEMPL_EXPORT template <TupleLike Tuple, TupleTransformer<Tuple> FF>
|
||||||
constexpr auto operator|(Tuple&& tuple, FF&& f) {
|
constexpr auto operator|(Tuple&& tuple, FF&& f) {
|
||||||
return LazyTuple{[tuple = std::forward<Tuple>(tuple), f = std::forward<FF>(f)]() -> decltype(auto) {
|
return LazyTuple{[tuple = std::forward<Tuple>(tuple), f = std::forward<FF>(f)]() -> decltype(auto) {
|
||||||
return f(std::move(tuple));
|
return f(std::move(tuple));
|
||||||
|
@ -331,14 +343,14 @@ concept ForEachConcept = []<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||||
return (std::invocable<F, decltype(Get<Is>(std::declval<Tuple>()))> && ...);
|
return (std::invocable<F, decltype(Get<Is>(std::declval<Tuple>()))> && ...);
|
||||||
}(std::make_index_sequence<kTupleSize<Tuple>>());
|
}(std::make_index_sequence<kTupleSize<Tuple>>());
|
||||||
|
|
||||||
export template <TupleLike Tuple, UnpackConcept<Tuple> F>
|
UTEMPL_EXPORT template <TupleLike Tuple, UnpackConcept<Tuple> F>
|
||||||
constexpr auto Unpack(Tuple&& tuple, F&& f) -> decltype(auto) {
|
constexpr auto Unpack(Tuple&& tuple, F&& f) -> decltype(auto) {
|
||||||
return [&](auto... is) -> decltype(auto) {
|
return [&](auto... is) -> decltype(auto) {
|
||||||
return f(Get<is>(std::forward<Tuple>(tuple))...);
|
return f(Get<is>(std::forward<Tuple>(tuple))...);
|
||||||
} | kSeq<kTupleSize<Tuple>>;
|
} | kSeq<kTupleSize<Tuple>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename F>
|
UTEMPL_EXPORT template <typename F>
|
||||||
constexpr auto Unpack(F&& f) {
|
constexpr auto Unpack(F&& f) {
|
||||||
return [f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple) -> decltype(auto)
|
return [f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple) -> decltype(auto)
|
||||||
requires UnpackConcept<F, Tuple>
|
requires UnpackConcept<F, Tuple>
|
||||||
|
@ -347,14 +359,14 @@ constexpr auto Unpack(F&& f) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike Tuple, TupleLike R = Tuple, TransformConcept<Tuple> F>
|
UTEMPL_EXPORT template <TupleLike Tuple, TupleLike R = Tuple, TransformConcept<Tuple> F>
|
||||||
constexpr auto Transform(Tuple&& container, F&& f, TypeList<R> = {}) {
|
constexpr auto Transform(Tuple&& container, F&& f, TypeList<R> = {}) {
|
||||||
return Unpack(std::forward<Tuple>(container), [&]<typename... Ts>(Ts&&... args) {
|
return Unpack(std::forward<Tuple>(container), [&]<typename... Ts>(Ts&&... args) {
|
||||||
return MakeTuple<R>(f(std::forward<Ts>(args))...);
|
return MakeTuple<R>(f(std::forward<Ts>(args))...);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename F, typename R = void>
|
UTEMPL_EXPORT template <typename F, typename R = void>
|
||||||
constexpr auto Transform(F&& f, TypeList<R> result = {}) {
|
constexpr auto Transform(F&& f, TypeList<R> result = {}) {
|
||||||
return [f = std::forward<F>(f), result]<TupleLike TTuple, typename RR = decltype([] {
|
return [f = std::forward<F>(f), result]<TupleLike TTuple, typename RR = decltype([] {
|
||||||
if constexpr(std::same_as<R, void>) {
|
if constexpr(std::same_as<R, void>) {
|
||||||
|
@ -369,17 +381,17 @@ constexpr auto Transform(F&& f, TypeList<R> result = {}) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike Tuple, TupleLike R = Tuple, TransformConcept<Tuple> F>
|
UTEMPL_EXPORT template <TupleLike Tuple, TupleLike R = Tuple, TransformConcept<Tuple> F>
|
||||||
constexpr auto Map(Tuple&& tuple, F&& f, TypeList<R> result = {}) {
|
constexpr auto Map(Tuple&& tuple, F&& f, TypeList<R> result = {}) {
|
||||||
return Transform(std::forward<Tuple>(tuple), std::forward<F>(f), result);
|
return Transform(std::forward<Tuple>(tuple), std::forward<F>(f), result);
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename F, typename R = void>
|
UTEMPL_EXPORT template <typename F, typename R = void>
|
||||||
constexpr auto Map(F&& f, TypeList<R> result = {}) -> decltype(Transform(std::forward<F>(f), result)) {
|
constexpr auto Map(F&& f, TypeList<R> result = {}) -> decltype(Transform(std::forward<F>(f), result)) {
|
||||||
return Transform(std::forward<F>(f), result);
|
return Transform(std::forward<F>(f), result);
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <auto Tuple, TupleLike To = decltype(Tuple)>
|
UTEMPL_EXPORT template <auto Tuple, TupleLike To = decltype(Tuple)>
|
||||||
consteval auto PackConstexprWrapper()
|
consteval auto PackConstexprWrapper()
|
||||||
requires TupleLike<decltype(Tuple)>
|
requires TupleLike<decltype(Tuple)>
|
||||||
{
|
{
|
||||||
|
@ -388,14 +400,14 @@ consteval auto PackConstexprWrapper()
|
||||||
}(std::make_index_sequence<kTupleSize<decltype(Tuple)>>());
|
}(std::make_index_sequence<kTupleSize<decltype(Tuple)>>());
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike Tuple>
|
UTEMPL_EXPORT template <TupleLike Tuple>
|
||||||
constexpr auto Reverse(Tuple&& tuple) {
|
constexpr auto Reverse(Tuple&& tuple) {
|
||||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||||
return MakeTuple<Tuple>(Get<kTupleSize<Tuple> - Is - 1>(std::forward<Tuple>(tuple))...);
|
return MakeTuple<Tuple>(Get<kTupleSize<Tuple> - Is - 1>(std::forward<Tuple>(tuple))...);
|
||||||
}(std::make_index_sequence<kTupleSize<Tuple>>());
|
}(std::make_index_sequence<kTupleSize<Tuple>>());
|
||||||
};
|
};
|
||||||
|
|
||||||
export consteval auto Reverse() {
|
UTEMPL_EXPORT consteval auto Reverse() {
|
||||||
return []<TupleLike Tuple>(Tuple&& tuple) {
|
return []<TupleLike Tuple>(Tuple&& tuple) {
|
||||||
return Reverse(std::forward<Tuple>(tuple));
|
return Reverse(std::forward<Tuple>(tuple));
|
||||||
};
|
};
|
||||||
|
@ -443,7 +455,7 @@ concept LeftFoldConcept = decltype(Unpack(std::declval<Tuple>(), []<typename...
|
||||||
return kWrapper<decltype((LeftFoldIsOk<F, T>{} | ... | LeftFoldIsOk<F, Ts>{}))::value>;
|
return kWrapper<decltype((LeftFoldIsOk<F, T>{} | ... | LeftFoldIsOk<F, Ts>{}))::value>;
|
||||||
}))::kValue;
|
}))::kValue;
|
||||||
|
|
||||||
export template <TupleLike Tuple, std::move_constructible T, LeftFoldConcept<T, Tuple> F = decltype(kDefaultCreator<void>)&>
|
UTEMPL_EXPORT template <TupleLike Tuple, std::move_constructible T, LeftFoldConcept<T, Tuple> F = decltype(kDefaultCreator<void>)&>
|
||||||
constexpr auto LeftFold(Tuple&& tuple, T&& init, F&& f = kDefaultCreator<void>) -> decltype(auto) {
|
constexpr auto LeftFold(Tuple&& tuple, T&& init, F&& f = kDefaultCreator<void>) -> decltype(auto) {
|
||||||
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) -> decltype(auto) {
|
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) -> decltype(auto) {
|
||||||
return (LeftFoldHelper<ForwardType<T>, ForwardType<F>>{.data = std::forward<T>(init), .f = std::forward<F>(f)} | ... |
|
return (LeftFoldHelper<ForwardType<T>, ForwardType<F>>{.data = std::forward<T>(init), .f = std::forward<F>(f)} | ... |
|
||||||
|
@ -452,12 +464,12 @@ constexpr auto LeftFold(Tuple&& tuple, T&& init, F&& f = kDefaultCreator<void>)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike Tuple, std::move_constructible T, LeftFoldConcept<T, Tuple> F>
|
UTEMPL_EXPORT template <TupleLike Tuple, std::move_constructible T, LeftFoldConcept<T, Tuple> F>
|
||||||
constexpr auto Reduce(Tuple&& tuple, T&& init, F&& f) -> decltype(auto) {
|
constexpr auto Reduce(Tuple&& tuple, T&& init, F&& f) -> decltype(auto) {
|
||||||
return LeftFold(std::forward<Tuple>(tuple), std::forward<T>(init), std::forward<F>(f));
|
return LeftFold(std::forward<Tuple>(tuple), std::forward<T>(init), std::forward<F>(f));
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename T, typename F>
|
UTEMPL_EXPORT template <typename T, typename F>
|
||||||
constexpr auto Reduce(T&& init, F&& f) -> decltype(auto) {
|
constexpr auto Reduce(T&& init, F&& f) -> decltype(auto) {
|
||||||
return [init = std::forward<T>(init), f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple) -> decltype(auto)
|
return [init = std::forward<T>(init), f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple) -> decltype(auto)
|
||||||
requires LeftFoldConcept<F, T, Tuple>
|
requires LeftFoldConcept<F, T, Tuple>
|
||||||
|
@ -466,14 +478,14 @@ constexpr auto Reduce(T&& init, F&& f) -> decltype(auto) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike Tuple, TupleLike Tuple2>
|
UTEMPL_EXPORT template <TupleLike Tuple, TupleLike Tuple2>
|
||||||
constexpr auto TupleCat(Tuple&& tuple, Tuple2&& tuple2) {
|
constexpr auto TupleCat(Tuple&& tuple, Tuple2&& tuple2) {
|
||||||
return [&]<auto... Is, auto... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>) {
|
return [&]<auto... Is, auto... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>) {
|
||||||
return MakeTuple<Tuple>(Get<Is>(std::forward<Tuple>(tuple))..., Get<IIs>(std::forward<Tuple2>(tuple2))...);
|
return MakeTuple<Tuple>(Get<Is>(std::forward<Tuple>(tuple))..., Get<IIs>(std::forward<Tuple2>(tuple2))...);
|
||||||
}(std::make_index_sequence<kTupleSize<Tuple>>(), std::make_index_sequence<kTupleSize<Tuple2>>());
|
}(std::make_index_sequence<kTupleSize<Tuple>>(), std::make_index_sequence<kTupleSize<Tuple2>>());
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike... Tuples>
|
UTEMPL_EXPORT template <TupleLike... Tuples>
|
||||||
constexpr auto TupleCat(Tuples&&... tuples)
|
constexpr auto TupleCat(Tuples&&... tuples)
|
||||||
requires(sizeof...(tuples) >= 1)
|
requires(sizeof...(tuples) >= 1)
|
||||||
{
|
{
|
||||||
|
@ -484,12 +496,12 @@ constexpr auto TupleCat(Tuples&&... tuples)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike... Tuples, typename F>
|
UTEMPL_EXPORT template <TupleLike... Tuples, typename F>
|
||||||
constexpr auto Unpack(Tuples&&... tuples, F&& f) -> decltype(Unpack(TupleCat(std::forward<Tuples>(tuples)...), std::forward<F>(f))) {
|
constexpr auto Unpack(Tuples&&... tuples, F&& f) -> decltype(Unpack(TupleCat(std::forward<Tuples>(tuples)...), std::forward<F>(f))) {
|
||||||
return Unpack(TupleCat(std::forward<Tuples>(tuples)...), std::forward<F>(f));
|
return Unpack(TupleCat(std::forward<Tuples>(tuples)...), std::forward<F>(f));
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename... Ts>
|
UTEMPL_EXPORT template <typename... Ts>
|
||||||
constexpr auto Tie(Ts&... args) -> Tuple<Ts&...> {
|
constexpr auto Tie(Ts&... args) -> Tuple<Ts&...> {
|
||||||
return {args...};
|
return {args...};
|
||||||
};
|
};
|
||||||
|
@ -511,7 +523,7 @@ consteval auto PartialCallerF(TypeList<Ts...>) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike Tuple, std::move_constructible T>
|
UTEMPL_EXPORT template <TupleLike Tuple, std::move_constructible T>
|
||||||
constexpr auto FirstOf(Tuple&& tuple, T&& init)
|
constexpr auto FirstOf(Tuple&& tuple, T&& init)
|
||||||
requires kEveryElement<std::is_invocable, Tuple>
|
requires kEveryElement<std::is_invocable, Tuple>
|
||||||
{
|
{
|
||||||
|
@ -523,7 +535,7 @@ constexpr auto FirstOf(Tuple&& tuple, T&& init)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename T>
|
UTEMPL_EXPORT template <typename T>
|
||||||
constexpr auto FirstOf(T&& init) {
|
constexpr auto FirstOf(T&& init) {
|
||||||
return [init = std::forward<T>(init)]<TupleLike Tuple>(Tuple&& tuple) {
|
return [init = std::forward<T>(init)]<TupleLike Tuple>(Tuple&& tuple) {
|
||||||
return FirstOf(std::forward<Tuple>(tuple), std::move(init));
|
return FirstOf(std::forward<Tuple>(tuple), std::move(init));
|
||||||
|
@ -535,7 +547,7 @@ concept FilterConcept = decltype(Unpack(std::declval<Tuple>(), []<typename... Ts
|
||||||
return kWrapper<(Function<F, bool(Ts)> && ...)>;
|
return kWrapper<(Function<F, bool(Ts)> && ...)>;
|
||||||
}))::kValue;
|
}))::kValue;
|
||||||
|
|
||||||
export template <TupleLike Tuple, FilterConcept<Tuple> F>
|
UTEMPL_EXPORT template <TupleLike Tuple, FilterConcept<Tuple> F>
|
||||||
constexpr auto Filter(Tuple&& tuple, F&& f) {
|
constexpr auto Filter(Tuple&& tuple, F&& f) {
|
||||||
return LeftFold(
|
return LeftFold(
|
||||||
std::forward<Tuple>(tuple), MakeTuple<Tuple>(), [&]<TupleLike Accumulator, typename T>(Accumulator&& accumulator, T&& add) {
|
std::forward<Tuple>(tuple), MakeTuple<Tuple>(), [&]<TupleLike Accumulator, typename T>(Accumulator&& accumulator, T&& add) {
|
||||||
|
@ -547,7 +559,7 @@ constexpr auto Filter(Tuple&& tuple, F&& f) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename F>
|
UTEMPL_EXPORT template <typename F>
|
||||||
constexpr auto Filter(F&& f) {
|
constexpr auto Filter(F&& f) {
|
||||||
return [f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple)
|
return [f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple)
|
||||||
requires FilterConcept<F, Tuple>
|
requires FilterConcept<F, Tuple>
|
||||||
|
@ -556,7 +568,7 @@ constexpr auto Filter(F&& f) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike Tuple, ForEachConcept<Tuple> F>
|
UTEMPL_EXPORT template <TupleLike Tuple, ForEachConcept<Tuple> F>
|
||||||
constexpr auto ForEach(Tuple&& tuple, F&& f) {
|
constexpr auto ForEach(Tuple&& tuple, F&& f) {
|
||||||
Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
|
Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
|
||||||
(f(std::forward<Ts>(args)), ...);
|
(f(std::forward<Ts>(args)), ...);
|
||||||
|
@ -577,12 +589,12 @@ struct Curryer {
|
||||||
return {.f = this->f, .data = this->data + Tuple{std::forward<T>(arg)}};
|
return {.f = this->f, .data = this->data + Tuple{std::forward<T>(arg)}};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export template <typename F>
|
UTEMPL_EXPORT template <typename F>
|
||||||
constexpr auto Curry(F&& f) -> Curryer<std::remove_cvref_t<F>> {
|
constexpr auto Curry(F&& f) -> Curryer<std::remove_cvref_t<F>> {
|
||||||
return {.f = std::forward<F>(f), .data = Tuple{}};
|
return {.f = std::forward<F>(f), .data = Tuple{}};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike Tuple, typename T>
|
UTEMPL_EXPORT template <TupleLike Tuple, typename T>
|
||||||
constexpr auto Find(Tuple&& tuple, T&& find) -> std::size_t {
|
constexpr auto Find(Tuple&& tuple, T&& find) -> std::size_t {
|
||||||
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
|
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
|
||||||
using Type = std::remove_cvref_t<T>;
|
using Type = std::remove_cvref_t<T>;
|
||||||
|
@ -606,7 +618,7 @@ constexpr auto Find(Tuple&& tuple, T&& find) -> std::size_t {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <std::size_t N, TupleLike Tuple>
|
UTEMPL_EXPORT template <std::size_t N, TupleLike Tuple>
|
||||||
constexpr auto Take(Tuple&& tuple) {
|
constexpr auto Take(Tuple&& tuple) {
|
||||||
if constexpr(std::is_lvalue_reference_v<Tuple> && HasMakeTie<Tuple>) {
|
if constexpr(std::is_lvalue_reference_v<Tuple> && HasMakeTie<Tuple>) {
|
||||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||||
|
@ -619,21 +631,21 @@ constexpr auto Take(Tuple&& tuple) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <std::size_t N>
|
UTEMPL_EXPORT template <std::size_t N>
|
||||||
consteval auto Take() {
|
consteval auto Take() {
|
||||||
return [&]<TupleLike Tuple>(Tuple&& tuple) {
|
return [&]<TupleLike Tuple>(Tuple&& tuple) {
|
||||||
return Take<N>(std::forward<Tuple>(tuple));
|
return Take<N>(std::forward<Tuple>(tuple));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike Tuple, std::move_constructible T>
|
UTEMPL_EXPORT template <TupleLike Tuple, std::move_constructible T>
|
||||||
constexpr auto operator<<(Tuple&& tuple, T&& t) {
|
constexpr auto operator<<(Tuple&& tuple, T&& t) {
|
||||||
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
|
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
|
||||||
return MakeTuple<Tuple>(std::forward<Ts>(args)..., std::forward<T>(t));
|
return MakeTuple<Tuple>(std::forward<Ts>(args)..., std::forward<T>(t));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <std::size_t N, TupleLike Tuple = Tuple<>, typename T>
|
UTEMPL_EXPORT template <std::size_t N, TupleLike Tuple = Tuple<>, typename T>
|
||||||
constexpr auto Generate(T&& value)
|
constexpr auto Generate(T&& value)
|
||||||
requires(std::copyable<T> || N == 1 && std::move_constructible<T>)
|
requires(std::copyable<T> || N == 1 && std::move_constructible<T>)
|
||||||
{
|
{
|
||||||
|
@ -646,7 +658,7 @@ constexpr auto Generate(T&& value)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <TupleLike Tuple>
|
UTEMPL_EXPORT template <TupleLike Tuple>
|
||||||
constexpr auto Enumerate(Tuple&& tuple) {
|
constexpr auto Enumerate(Tuple&& tuple) {
|
||||||
return Unpack(std::forward<Tuple>(tuple), [](auto&&... vs) {
|
return Unpack(std::forward<Tuple>(tuple), [](auto&&... vs) {
|
||||||
return [&](auto... is) {
|
return [&](auto... is) {
|
||||||
|
@ -665,7 +677,7 @@ concept CallableSwitchConcept = std::same_as<R, void> || decltype(Unpack(std::de
|
||||||
return kWrapper<(Function<F, std::optional<R>(Ts)> && ...)>;
|
return kWrapper<(Function<F, std::optional<R>(Ts)> && ...)>;
|
||||||
}))::kValue;
|
}))::kValue;
|
||||||
|
|
||||||
export template <typename R = void,
|
UTEMPL_EXPORT template <typename R = void,
|
||||||
TupleLike KeysTuple,
|
TupleLike KeysTuple,
|
||||||
TupleLike ValuesTuple,
|
TupleLike ValuesTuple,
|
||||||
ComparableSwitchConcept<KeysTuple> Key,
|
ComparableSwitchConcept<KeysTuple> Key,
|
||||||
|
@ -702,14 +714,14 @@ constexpr auto Switch(KeysTuple&& keysTuple, ValuesTuple&& valuesTuple, Key&& ke
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <std::size_t N, typename R = Tuple<>>
|
UTEMPL_EXPORT template <std::size_t N, typename R = Tuple<>>
|
||||||
consteval auto GetIndexesTuple() {
|
consteval auto GetIndexesTuple() {
|
||||||
return [](auto... is) {
|
return [](auto... is) {
|
||||||
return MakeTuple<R>(*is...);
|
return MakeTuple<R>(*is...);
|
||||||
} | kSeq<N>;
|
} | kSeq<N>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export template <typename R = Tuple<>, typename... Ts>
|
UTEMPL_EXPORT template <typename R = Tuple<>, typename... Ts>
|
||||||
consteval auto GetTuple(TypeList<Ts...>, TypeList<R> = {}) {
|
consteval auto GetTuple(TypeList<Ts...>, TypeList<R> = {}) {
|
||||||
return MakeTuple<R>(kType<Ts>...);
|
return MakeTuple<R>(kType<Ts>...);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
module;
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
export module tests.go_interface;
|
|
||||||
import utempl;
|
#include <utempl/utempl.hpp>
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
module;
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
export module tests.menu;
|
|
||||||
import utempl;
|
|
||||||
|
|
||||||
namespace utempl {
|
|
||||||
|
|
||||||
TEST(Menu, Basic) {
|
|
||||||
testing::internal::CaptureStdout();
|
|
||||||
std::istringstream stream("t\n");
|
|
||||||
int value = 0;
|
|
||||||
menu::Menu{}
|
|
||||||
.With<{"t", "This is t"}>([&] {
|
|
||||||
std::cout << "Success!" << std::endl;
|
|
||||||
value = 1;
|
|
||||||
})
|
|
||||||
.Run<"[{0}]{2} - ({1})\n">(stream);
|
|
||||||
auto captured = testing::internal::GetCapturedStdout();
|
|
||||||
EXPECT_EQ(captured, "[t] - (This is t)\n|> Success!\n");
|
|
||||||
EXPECT_EQ(value, 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace utempl
|
|
|
@ -1,7 +1,6 @@
|
||||||
module;
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
export module tests.overloaded;
|
|
||||||
import utempl;
|
#include <utempl/utempl.hpp>
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue