diff --git a/.github/workflows/untitled.txt b/.github/workflows/untitled.txt new file mode 100644 index 00000000..e69de29b diff --git a/CMakeLists.txt b/CMakeLists.txt index a60ca89f..40a6840a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ -cmake_minimum_required(VERSION 3.8.0) +cmake_minimum_required(VERSION 3.28) # When updating to a newer version of CMake, see if we can use the following project(ctre HOMEPAGE_URL "https://compile-time.re" - VERSION 3.0 + VERSION 3.9 LANGUAGES CXX) set(PROJECT_DESCRIPTION "Fast compile-time regular expressions with support for matching/searching/capturing during compile-time or runtime.") @@ -25,10 +25,12 @@ cmake_dependent_option(CTRE_BUILD_PACKAGE_RPM "Create RPM Package (${PROJECT_NAME})" ON "CTRE_BUILD_PACKAGE;CTRE_RPMBUILD_FOUND" OFF) -add_library(${PROJECT_NAME} INTERFACE) +add_library(${PROJECT_NAME} STATIC) add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) -target_include_directories(${PROJECT_NAME} INTERFACE +target_sources(${PROJECT_NAME} PUBLIC FILE_SET sources TYPE CXX_MODULES FILES include/ctre.cppm) + +target_include_directories(${PROJECT_NAME} PUBLIC $ $) @@ -36,9 +38,9 @@ if (NOT CTRE_CXX_STANDARD) set(CTRE_CXX_STANDARD 20) endif() -target_compile_features(ctre INTERFACE cxx_std_${CTRE_CXX_STANDARD}) +target_compile_features(ctre PUBLIC cxx_std_${CTRE_CXX_STANDARD}) -install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets) +#install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets) if (NOT EXISTS "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake.in") file(WRITE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake.in [[ @@ -58,19 +60,21 @@ write_basic_package_version_file(ctre-config-version.cmake VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion) -install(EXPORT ${PROJECT_NAME}-targets - DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}" - NAMESPACE ${PROJECT_NAME}::) -install( - FILES - "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" - "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" - DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}) -install(DIRECTORY include/ DESTINATION include - FILES_MATCHING PATTERN *.hpp) +#install(EXPORT ${PROJECT_NAME}-targets +# DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}" +# NAMESPACE ${PROJECT_NAME}::) +#install( +# FILES +# "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" +# "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" +# DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}) +#install(DIRECTORY include/ DESTINATION include +# FILES_MATCHING PATTERN *.hpp) if(CTRE_BUILD_TESTS) add_subdirectory(tests) + add_executable(module-test module-test.cpp) + target_link_libraries(module-test ${PROJECT_NAME}) endif() if (NOT CTRE_BUILD_PACKAGE) diff --git a/Makefile b/Makefile index a2016f74..609f396b 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ single-header/unicode-db.hpp: include/unicode-db/unicode-db.hpp cp $+ $@ single-header/ctre.hpp: - python3 -m quom include/ctre.hpp ctre.hpp.tmp + python3.9 -m quom include/ctre.hpp ctre.hpp.tmp echo "/*" > single-header/ctre.hpp cat LICENSE >> single-header/ctre.hpp echo "*/" >> single-header/ctre.hpp @@ -75,7 +75,7 @@ single-header/ctre.hpp: rm ctre.hpp.tmp single-header/ctre-unicode.hpp: - python3 -m quom include/ctre-unicode.hpp ctre-unicode.hpp.tmp + python3.9 -m quom include/ctre-unicode.hpp ctre-unicode.hpp.tmp echo "/*" > single-header/ctre-unicode.hpp cat LICENSE >> single-header/ctre-unicode.hpp echo "*/" >> single-header/ctre-unicode.hpp diff --git a/include/ctll/fixed_string.hpp b/include/ctll/fixed_string.hpp index 0a87171c..f747a63b 100644 --- a/include/ctll/fixed_string.hpp +++ b/include/ctll/fixed_string.hpp @@ -1,11 +1,13 @@ #ifndef CTLL__FIXED_STRING__GPP #define CTLL__FIXED_STRING__GPP +#ifndef CTLL_IN_MODULE #include #include #include #include #include +#endif namespace ctll { diff --git a/include/ctll/grammars.hpp b/include/ctll/grammars.hpp index 2d5c2c0b..95f318f8 100644 --- a/include/ctll/grammars.hpp +++ b/include/ctll/grammars.hpp @@ -57,7 +57,7 @@ struct anything { template struct range { constexpr inline range() noexcept { } //template constexpr range(term) noexcept requires (A <= V) && (V <= B); - template > constexpr inline range(term) noexcept; + template > constexpr inline range(term) noexcept { } }; #ifdef __EDG__ @@ -70,9 +70,9 @@ template struct contains { template struct set { constexpr inline set() noexcept { } #ifdef __EDG__ - template ::value>> constexpr inline set(term) noexcept; + template ::value>> constexpr inline set(term) noexcept { } #else - template > constexpr inline set(term) noexcept; + template > constexpr inline set(term) noexcept { } #endif }; @@ -81,9 +81,9 @@ template struct neg_set { constexpr inline neg_set() noexcept { } #ifdef __EDG__ - template ::value>> constexpr inline neg_set(term) noexcept; + template ::value>> constexpr inline neg_set(term) noexcept { } #else - template > constexpr inline neg_set(term) noexcept; + template > constexpr inline neg_set(term) noexcept { } #endif }; diff --git a/include/ctll/parser.hpp b/include/ctll/parser.hpp index b355eb1e..924be67a 100644 --- a/include/ctll/parser.hpp +++ b/include/ctll/parser.hpp @@ -6,7 +6,9 @@ #include "grammars.hpp" #include "actions.hpp" +#ifndef CTLL_IN_MODULE #include +#endif namespace ctll { diff --git a/include/ctll/utilities.hpp b/include/ctll/utilities.hpp index fbb9f37f..57fafab7 100644 --- a/include/ctll/utilities.hpp +++ b/include/ctll/utilities.hpp @@ -1,7 +1,9 @@ #ifndef CTLL__UTILITIES__HPP #define CTLL__UTILITIES__HPP +#ifndef CTLL_IN_MODULE #include +#endif #if defined __cpp_nontype_template_parameter_class #define CTLL_CNTTP_COMPILER_CHECK 1 diff --git a/include/ctre.cppm b/include/ctre.cppm new file mode 100644 index 00000000..020122cd --- /dev/null +++ b/include/ctre.cppm @@ -0,0 +1,40 @@ +module; + +// this will enable in-module mode and include/import std library +#include "ctre/std_module.hpp" +// CTRE in in-module mode won't include anything +#include "ctre.hpp" + +export module ctre; + +// this won't export everything in ctre namespace, but only things I take here... +export namespace ctre { + // so you can pipe a range into a regex wrapper + using ctre::operator|; + + // modifiers + using ctre::singleline; + using ctre::multiline; + + // singleline niebloids + using ctre::match; // whole input range must match regex + using ctre::search; // input subrange must match regex + using ctre::starts_with; // prefix of input must match regex + + // singleline range niebloids + using ctre::search_all; // will look for each occurence of regex + using ctre::range; // alias to search_all + using ctre::split; // will split input range by the regex + using ctre::tokenize; // will split input to pieces matching regex + + // multiline niebloids + using ctre::multiline_match; + using ctre::multiline_search; + using ctre::multiline_starts_with; + + // multiline range niebloids + using ctre::multiline_search_all; + using ctre::multiline_range; + using ctre::multiline_split; + using ctre::multiline_tokenize; +} diff --git a/include/ctre/atoms.hpp b/include/ctre/atoms.hpp index c4381c6f..10c72b73 100644 --- a/include/ctre/atoms.hpp +++ b/include/ctre/atoms.hpp @@ -2,7 +2,10 @@ #define CTRE__ATOMS__HPP #include "atoms_characters.hpp" + +#ifndef CTRE_IN_MODULE #include +#endif namespace ctre { diff --git a/include/ctre/atoms_characters.hpp b/include/ctre/atoms_characters.hpp index d1938e50..98d39385 100644 --- a/include/ctre/atoms_characters.hpp +++ b/include/ctre/atoms_characters.hpp @@ -3,7 +3,10 @@ #include "utility.hpp" #include "flags_and_modes.hpp" + +#ifndef CTRE_IN_MODULE #include +#endif namespace ctre { diff --git a/include/ctre/capture_tuple.hpp b/include/ctre/capture_tuple.hpp new file mode 100644 index 00000000..a6d900e6 --- /dev/null +++ b/include/ctre/capture_tuple.hpp @@ -0,0 +1,337 @@ +#ifndef CTRE__CAPTURE_TUPLE__HPP +#define CTRE__CAPTURE_TUPLE__HPP + +#include "id.hpp" +#include "utf8.hpp" + +#ifndef CTRE_IN_MODULE +#include +#include +#include +#include +#include +#include +#if __has_include() +#include +#endif +#if __has_include() +#include +#endif +#endif + +namespace ctre { + +template struct capture_number_id { }; +template struct capture_name_id { }; + +struct no_capture_selected { + template constexpr friend auto operator+(no_capture_selected, T & rhs) -> T & { + return rhs; + } + template constexpr friend auto operator+(T & lhs, no_capture_selected) -> T & { + return lhs; + } + template constexpr friend auto operator+(no_capture_selected, const T & rhs) -> const T & { + return rhs; + } + template constexpr friend auto operator+(const T & lhs, no_capture_selected) -> const T & { + return lhs; + } + constexpr friend auto operator+(no_capture_selected, no_capture_selected) -> no_capture_selected { + return {}; + } +}; + +template struct capture_identifier { + constexpr friend bool operator==(capture_identifier, capture_number_id) noexcept { + return true; + } + template constexpr friend bool operator==(capture_identifier, capture_number_id) noexcept { + return false; + } + constexpr friend bool operator==(capture_identifier, capture_name_id) noexcept { + return true; + } + template constexpr friend bool operator==(capture_identifier, capture_name_id) noexcept { + return false; + } +}; + +template struct capture_tuple_storage { + using iterator_type = Iterator; + + [[no_unique_address]] Iterator first{}; + [[no_unique_address]] Sentinel last{}; + + constexpr capture_tuple_storage() = default; + constexpr capture_tuple_storage(const capture_tuple_storage &) = default; + constexpr capture_tuple_storage(capture_tuple_storage &&) = default; + + constexpr capture_tuple_storage & operator=(const capture_tuple_storage &) = default; + constexpr capture_tuple_storage & operator=(capture_tuple_storage &&) = default; + + + constexpr bool matched() noexcept { + return true; // TODO + } +}; + +template struct capture_tuple_item { + using identifier_type = Id; + using storage_type = Storage; + + static_assert(std::move_constructible); + static_assert(std::copy_constructible); + + + [[no_unique_address]] storage_type storage{}; + + //constexpr capture_tuple_item() = default; + + template constexpr friend auto operator==(const capture_tuple_item & item, capture_number_id rhs) noexcept { + if constexpr (identifier_type{} == rhs) { + return item; + } else { + return no_capture_selected{}; + } + } + + template constexpr friend auto operator==(const capture_tuple_item & item, capture_name_id rhs) noexcept { + if constexpr (identifier_type{} == rhs) { + return item; + } else { + return no_capture_selected{}; + } + } + + template constexpr friend auto operator==(capture_tuple_item & item, capture_number_id rhs) noexcept { + if constexpr (identifier_type{} == rhs) { + return item; + } else { + return no_capture_selected{}; + } + } + + template constexpr friend auto operator==(capture_tuple_item & item, capture_name_id rhs) noexcept { + if constexpr (identifier_type{} == rhs) { + return item; + } else { + return no_capture_selected{}; + } + } +}; + +template constexpr decltype(auto) select_if(T && arg) { + if constexpr (Value) { + return std::forward(arg); + } else { + return no_capture_selected{}; + } +} + +template constexpr auto & select_nth(Ts && ... args) { + static_assert(I < sizeof...(Ts)); + + const auto lmb = [&](std::index_sequence) -> decltype(auto) { + return (no_capture_selected{} + ... + select_if(std::forward(args))); + }; + + return lmb(std::make_index_sequence()); +} + +template class tuple { + static constexpr auto build_storage(Ts... args) { + return [...items = std::move(args)](auto && fnc) mutable -> decltype(auto) { + return fnc(items...); + }; + } + + static constexpr auto default_storage() { + return build_storage(Ts{}...); + } + + static constexpr auto copy_storage(const Ts & ... args) { + return build_storage(args...); + } + + using storage_type = decltype(build_storage(Ts{}...)); + + mutable storage_type storage; + +public: + + static constexpr auto size = std::integral_constant{}; + + constexpr tuple() noexcept: storage{default_storage()}{ } + + constexpr tuple(Ts... args) noexcept: storage{build_storage(args...)} { } + + constexpr tuple(tuple && orig) noexcept: storage{std::move(orig.storage)} { } + + constexpr tuple(const tuple & orig) noexcept: storage{orig.storage([](const auto & ... rhs) { return build_storage(rhs...); })} { } + + constexpr tuple & operator=(const tuple & orig) noexcept { + storage([&](auto & ... lhs){ + orig.storage([&](const auto & ... rhs){ + ((void)(lhs = rhs), ...); + }); + }); + return *this; + } + + constexpr tuple & operator=(tuple && orig) noexcept { + storage([&](auto & ... lhs){ + orig.storage([&](auto & ... rhs){ + ((void)std::swap(lhs, rhs), ...); + }); + }); + return *this; + } + + constexpr ~tuple() noexcept = default; + + // comparison + constexpr friend bool operator==(const tuple & lhs, const tuple & rhs) noexcept { + return lhs.storage([&](const auto & ... lhs_value){ + return rhs.storage([&](const auto & ... rhs_value){ + return ((lhs_value == rhs_value) && ...); + }); + }); + } + + constexpr friend auto operator<=>(const tuple & lhs, const tuple & rhs) noexcept { + return lhs.storage([&](const auto & ... lhs_value){ + return rhs.storage([&](const auto & ... rhs_value){ + using result_type = std::common_comparison_category_t rhs_value)...>; + + auto r = result_type::equivalent; + + ((r = (lhs_value <=> rhs_value), std::is_eq(r)) && ...); + + return r; + }); + }); + } + + // printing + template friend auto & operator<<(std::basic_ostream & str, const tuple & tpl) { + if constexpr (size()) { + tpl.storage([&](const auto & first, const auto & ... tail) { + ((str << first), ((void)(str << ' ' << tail), ...)); + }); + } + + return str; + } + + // support for get + template constexpr auto & get() & noexcept requires (I < size()) { + return storage([](auto & ... value) -> decltype(auto) { + return select_nth(value...); + }); + } + + template constexpr const auto & get() const & noexcept requires (I < size()) { + return storage([](const auto & ... value) -> decltype(auto) { + return select_nth(value...); + }); + } + + template constexpr auto get() && noexcept requires (I < size()) { + return storage([](auto & ... value) -> decltype(auto) { + return select_nth(std::move(value)...); + }); + } + + template constexpr auto get() const && noexcept requires (I < size()) { + return storage([](const auto & ... value) -> decltype(auto) { + return select_nth(std::move(value)...); + }); + } +}; + +template constexpr auto get = [](auto && tpl) noexcept -> decltype(auto) { + return tpl.get(); +}; + +template struct capture_tuple { + static constexpr auto build_lambda() { + return [...items = foo{}]() { + //return ((items == Id{}) + ... + no_capture_selected{}); + }; + } + + using tuple_storage_type = decltype(build_lambda()); + + tuple_storage_type internal_tuple{build_lambda()}; + + constexpr capture_tuple(...) noexcept { } + constexpr capture_tuple(const capture_tuple &) noexcept { } + constexpr capture_tuple(capture_tuple &&) noexcept { } + + constexpr capture_tuple & operator=(const capture_tuple & other) noexcept { + internal_tuple = other.internal_tuple; + return *this; + } + constexpr capture_tuple & operator=(capture_tuple && other) noexcept { + internal_tuple = std::move(other.internal_tuple); + return *this; + } + + constexpr capture_tuple & matched() noexcept { + // TODO + return *this; + } + + constexpr capture_tuple & unmatch() noexcept { + // TODO + return *this; + } + + + constexpr auto get_end_position() const noexcept { + return typename Storage::iterator_type{}; + } + + constexpr operator bool() const noexcept { + return true; + } + + template constexpr capture_tuple & start_capture(const typename Storage::iterator_type &) noexcept { + return *this; + } + + template constexpr capture_tuple & end_capture(const typename Storage::iterator_type &) noexcept { + return *this; + } + + + constexpr capture_tuple & set_start_mark(const typename Storage::iterator_type &) noexcept { + return *this; + } + + constexpr capture_tuple & set_end_mark(const typename Storage::iterator_type &) noexcept { + return *this; + } +}; + +template capture_tuple(Iterator, ctll::list) -> capture_tuple, CapturesIds...>; + +template using return_type = decltype(capture_tuple(std::declval(), find_captures(Pattern{}))); + +} + +namespace std { + +template struct tuple_size> : public decltype(ctre::tuple::size) { }; + +template struct tuple_element> { +public: + using type = decltype( + std::declval &>().template get() + ); +}; + +} + +#endif \ No newline at end of file diff --git a/include/ctre/evaluation.hpp b/include/ctre/evaluation.hpp index d2f329e9..b7c3b393 100644 --- a/include/ctre/evaluation.hpp +++ b/include/ctre/evaluation.hpp @@ -6,10 +6,13 @@ #include "atoms_unicode.hpp" #include "starts_with_anchor.hpp" #include "utility.hpp" -#include "return_type.hpp" +#include "capture_tuple.hpp" #include "find_captures.hpp" #include "first.hpp" + +#ifndef CTRE_IN_MODULE #include +#endif // remove me when MSVC fix the constexpr bug #ifdef _MSC_VER @@ -19,6 +22,10 @@ #endif namespace ctre { + +struct not_matched_tag_t { }; + +constexpr inline auto not_matched = not_matched_tag_t{}; template constexpr CTRE_FORCE_INLINE bool less_than_or_infinite([[maybe_unused]] size_t i) noexcept { if constexpr (Limit == 0) { diff --git a/include/ctre/find_captures.hpp b/include/ctre/find_captures.hpp index e6c49e26..58de1e8d 100644 --- a/include/ctre/find_captures.hpp +++ b/include/ctre/find_captures.hpp @@ -4,7 +4,7 @@ #include "atoms_characters.hpp" #include "atoms_unicode.hpp" #include "utility.hpp" -#include "return_type.hpp" +#include "capture_tuple.hpp" namespace ctre { @@ -112,12 +112,12 @@ template constexpr auto template constexpr auto find_captures(ctll::list, Tail...>, ctll::list) noexcept { - return find_captures(ctll::list(), ctll::list>()); + return find_captures(ctll::list(), ctll::list>()); } template constexpr auto find_captures(ctll::list, Tail...>, ctll::list) noexcept { - return find_captures(ctll::list(), ctll::list>()); + return find_captures(ctll::list(), ctll::list>()); } diff --git a/include/ctre/id.hpp b/include/ctre/id.hpp index 2d2ca9ae..50f244e6 100644 --- a/include/ctre/id.hpp +++ b/include/ctre/id.hpp @@ -1,7 +1,9 @@ #ifndef CTRE__ID__HPP #define CTRE__ID__HPP +#ifndef CTRE_IN_MODULE #include +#endif namespace ctre { diff --git a/include/ctre/iterators.hpp b/include/ctre/iterators.hpp index 35a1b6dd..3ff7684c 100644 --- a/include/ctre/iterators.hpp +++ b/include/ctre/iterators.hpp @@ -3,7 +3,10 @@ #include "literals.hpp" #include "wrapper.hpp" + +#ifndef CTRE_IN_MODULE #include +#endif namespace ctre { diff --git a/include/ctre/pcre_actions.hpp b/include/ctre/pcre_actions.hpp index a221968a..ec35a768 100644 --- a/include/ctre/pcre_actions.hpp +++ b/include/ctre/pcre_actions.hpp @@ -4,8 +4,11 @@ #include "pcre.hpp" #include "rotate.hpp" #include "id.hpp" + +#ifndef CTRE_IN_MODULE #include #include +#endif namespace ctre { diff --git a/include/ctre/return_type.hpp b/include/ctre/return_type.hpp index 01a64cfd..81e591ad 100644 --- a/include/ctre/return_type.hpp +++ b/include/ctre/return_type.hpp @@ -3,6 +3,8 @@ #include "id.hpp" #include "utf8.hpp" + +#ifndef CTRE_IN_MODULE #include #include #include @@ -12,6 +14,10 @@ #if __has_include() #include #endif +#if __has_include() +#include +#endif +#endif namespace ctre { @@ -37,7 +43,7 @@ template struct captured_content { public: using char_type = typename std::iterator_traits::value_type; - using name = Name; + //using name = Name; constexpr CTRE_FORCE_INLINE storage() noexcept {} @@ -117,8 +123,6 @@ template struct captured_content { } #endif - template struct identify; - template constexpr CTRE_FORCE_INLINE auto to_view() const noexcept { // random access, because C++ (waving hands around) constexpr bool must_be_nonreverse_contiguous_iterator = is_random_accessible>::iterator_category> && !is_reverse_iterator; @@ -420,7 +424,6 @@ template using return_type = decltyp } -// support for structured bindings #ifndef __EDG__ #ifdef __clang__ @@ -428,16 +431,33 @@ template using return_type = decltyp #pragma clang diagnostic ignored "-Wmismatched-tags" #endif +// support for std::format + namespace std { - template struct tuple_size> : public std::integral_constant::count()> { }; + +#if __has_include() + //template struct formatter; - template struct tuple_element> { - public: - using type = decltype( - std::declval &>().template get() - ); - }; -} +template +struct formatter::template storage, CharT> +{ + +}; + +#endif + +// support for structured bindings + +template struct tuple_size> : public std::integral_constant::count()> { }; + +template struct tuple_element> { +public: + using type = decltype( + std::declval &>().template get() + ); +}; + +} // end of namespace std:: #ifdef __clang__ #pragma clang diagnostic pop diff --git a/include/ctre/std_module.hpp b/include/ctre/std_module.hpp new file mode 100644 index 00000000..dfff7dd8 --- /dev/null +++ b/include/ctre/std_module.hpp @@ -0,0 +1,27 @@ +#ifndef CTRE_STD_MODULE_HPP +#define CTRE_STD_MODULE_HPP + +#if __cpp_lib_modules >= 202207L +import std; +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __has_include() +#include +#endif + +#endif + +#define CTRE_IN_MODULE +#define CTLL_IN_MODULE + +#endif diff --git a/include/ctre/tuple.hpp b/include/ctre/tuple.hpp new file mode 100644 index 00000000..f081077d --- /dev/null +++ b/include/ctre/tuple.hpp @@ -0,0 +1,189 @@ +#ifndef CTRE_TUPLE_HPP +#define CTRE_TUPLE_HPP + +#ifndef CTRE_IN_MODULE +#include +#include +#include +#include +#include +#endif + +namespace ctre { + +struct no_tuple_element_selected { + template constexpr friend auto operator+(no_tuple_element_selected, T & rhs) -> T & { + return rhs; + } + template constexpr friend auto operator+(T & lhs, no_tuple_element_selected) -> T & { + return lhs; + } + template constexpr friend auto operator+(no_tuple_element_selected, const T & rhs) -> const T & { + return rhs; + } + template constexpr friend auto operator+(const T & lhs, no_tuple_element_selected) -> const T & { + return lhs; + } + constexpr friend auto operator+(no_tuple_element_selected, no_tuple_element_selected) -> no_tuple_element_selected { + return {}; + } +}; + +template constexpr auto select_if(T && arg) -> decltype(auto) { + if constexpr (Value) { + return std::forward(arg); + } else { + return no_tuple_element_selected{}; + } +} + +template constexpr auto select_nth(Ts && ... args) -> decltype(auto) { + static_assert(I < sizeof...(Ts)); + + return [&](std::index_sequence) -> decltype(auto) { + return (no_tuple_element_selected{} + ... + select_if(std::forward(args))); + }(std::make_index_sequence()); +} + +template class tuple { + static constexpr auto build_storage(Ts... args) { + return [...items = std::move(args)](auto && fnc) mutable -> decltype(auto) { + return fnc(items...); + }; + } + + static constexpr auto default_storage() { + return build_storage(Ts{}...); + } + + using storage_type = decltype(build_storage(std::declval()...)); + + mutable storage_type storage; + +public: + + static constexpr auto size = std::integral_constant{}; + + constexpr tuple() noexcept requires(std::default_initializable && ...): storage{default_storage()}{ } + + constexpr tuple(Ts... args) noexcept: storage{build_storage(args...)} { } + + constexpr tuple(tuple && orig) noexcept requires(std::move_constructible && ...): storage{std::move(orig.storage)} { } + + constexpr tuple(const tuple & orig) noexcept requires(std::copy_constructible && ...): storage{orig.storage([](const auto & ... rhs) { return build_storage(rhs...); })} { } + + constexpr tuple & operator=(const tuple & orig) noexcept requires(std::is_copy_assignable_v && ...) { + storage([&](auto & ... lhs){ + orig.storage([&](const auto & ... rhs){ + ((void)(lhs = rhs), ...); + }); + }); + return *this; + } + + constexpr tuple & operator=(tuple && orig) noexcept requires(std::is_move_assignable_v && ...) { + storage([&](auto & ... lhs){ + orig.storage([&](auto & ... rhs){ + ((void)(lhs = std::move(rhs)), ...); + }); + }); + return *this; + } + + constexpr void swap(tuple & other) noexcept { + storage([&](auto & ... lhs){ + other.storage([&](auto & ... rhs){ + ((void)std::swap(lhs, rhs), ...); + }); + }); + } + + constexpr ~tuple() noexcept = default; + + // comparison + constexpr friend bool operator==(const tuple & lhs, const tuple & rhs) noexcept { + return lhs.storage([&](const auto & ... lhs_value){ + return rhs.storage([&](const auto & ... rhs_value){ + return ((lhs_value == rhs_value) && ...); + }); + }); + } + + constexpr friend auto operator<=>(const tuple & lhs, const tuple & rhs) noexcept { + return lhs.storage([&](const auto & ... lhs_value){ + return rhs.storage([&](const auto & ... rhs_value){ + using result_type = std::common_comparison_category_t rhs_value)...>; + + auto r = result_type::equivalent; + + ((r = (lhs_value <=> rhs_value), std::is_eq(r)) && ...); + + return r; + }); + }); + } + + // printing with iostream + template friend auto & operator<<(std::basic_ostream & str, const tuple & tpl) { + if constexpr (size()) { + tpl.storage([&](const auto & first, const auto & ... tail) { + ((str << first), ((void)(str << ' ' << tail), ...)); + }); + } + + return str; + } + + // support for get + template constexpr auto & get() & noexcept requires (I < size()) { + return storage([](auto & ... value) -> decltype(auto) { + return select_nth(value...); + }); + } + + template constexpr const auto & get() const & noexcept requires (I < size()) { + return storage([](const auto & ... value) -> decltype(auto) { + return select_nth(value...); + }); + } + + template constexpr auto get() && noexcept requires (I < size()) { + return storage([](auto & ... value) -> decltype(auto) { + return select_nth(std::move(value)...); + }); + } + + template constexpr auto get() const && noexcept requires (I < size()) { + return storage([](const auto & ... value) -> decltype(auto) { + return select_nth(std::move(value)...); + }); + } +}; + +// this is niebloid to avoid writing ctre::template get(tpl) +template constexpr auto get = [](auto && tpl) noexcept -> decltype(auto) { + return tpl.get(); +}; + +template constexpr auto tie(Ts & ... args) -> tuple { + return {args...}; +} + +} // namespace ctre + +// tuple protocol to support structured bindings + +namespace std { + +template struct tuple_size> : public decltype(ctre::tuple::size) { }; + +template struct tuple_element> { +public: + using type = decltype( + std::declval &>().template get() + ); +}; + +} // namespace std + +#endif \ No newline at end of file diff --git a/include/ctre/utf8.hpp b/include/ctre/utf8.hpp index 886657eb..be514ed3 100644 --- a/include/ctre/utf8.hpp +++ b/include/ctre/utf8.hpp @@ -4,8 +4,11 @@ #if __cpp_char8_t >= 201811 #include "utility.hpp" + +#ifndef CTRE_IN_MODULE #include #include +#endif #if __cpp_lib_char8_t >= 201811L #define CTRE_ENABLE_UTF8_RANGE diff --git a/include/ctre/wrapper.hpp b/include/ctre/wrapper.hpp index 55e35b48..5b5a4a55 100644 --- a/include/ctre/wrapper.hpp +++ b/include/ctre/wrapper.hpp @@ -4,9 +4,12 @@ #include "evaluation.hpp" #include "utility.hpp" #include "utf8.hpp" -#include "return_type.hpp" +#include "capture_tuple.hpp" #include "range.hpp" + +#ifndef CTRE_IN_MODULE #include +#endif namespace ctre { @@ -271,7 +274,7 @@ template constexpr auto operato template constexpr auto operator|(Range && range, regular_expression re) noexcept { return re.multi_exec(std::forward(range)); -} +}; // error reporting of problematic position in a regex template struct problem_at_position; // do not define! @@ -303,39 +306,43 @@ template struct regex_builder { // case-sensitive -template static constexpr inline auto match = regular_expression::type, match_method, ctll::list>(); +template constexpr auto match = regular_expression::type, match_method, ctll::list>(); + +template constexpr auto search = regular_expression::type, search_method, ctll::list>(); -template static constexpr inline auto search = regular_expression::type, search_method, ctll::list>(); +template constexpr auto starts_with = regular_expression::type, starts_with_method, ctll::list>(); -template static constexpr inline auto starts_with = regular_expression::type, starts_with_method, ctll::list>(); +template constexpr auto search_all = regular_expression::type, range_method, ctll::list>(); -template static constexpr inline auto range = regular_expression::type, range_method, ctll::list>(); +template constexpr auto range = search_all; -template static constexpr inline auto split = regular_expression::type, split_method, ctll::list>(); +template constexpr auto split = regular_expression::type, split_method, ctll::list>(); -template static constexpr inline auto tokenize = regular_expression::type, tokenize_method, ctll::list>(); +template constexpr auto tokenize = regular_expression::type, tokenize_method, ctll::list>(); -template static constexpr inline auto iterator = regular_expression::type, iterator_method, ctll::list>(); +template constexpr auto iterator = regular_expression::type, iterator_method, ctll::list>(); -static constexpr inline auto sentinel = regex_end_iterator(); +constexpr inline auto sentinel = regex_end_iterator(); // multiline -template static constexpr inline auto multiline_match = regular_expression::type, match_method, ctll::list>(); +template constexpr auto multiline_match = regular_expression::type, match_method, ctll::list>(); + +template constexpr auto multiline_search = regular_expression::type, search_method, ctll::list>(); -template static constexpr inline auto multiline_search = regular_expression::type, search_method, ctll::list>(); +template constexpr auto multiline_starts_with = regular_expression::type, starts_with_method, ctll::list>(); -template static constexpr inline auto multiline_starts_with = regular_expression::type, starts_with_method, ctll::list>(); +template constexpr auto multiline_search_all = regular_expression::type, range_method, ctll::list>(); -template static constexpr inline auto multiline_range = regular_expression::type, range_method, ctll::list>(); +template constexpr auto multiline_range = multiline_search_all; -template static constexpr inline auto multiline_split = regular_expression::type, split_method, ctll::list>(); +template constexpr auto multiline_split = regular_expression::type, split_method, ctll::list>(); -template static constexpr inline auto multiline_tokenize = regular_expression::type, tokenize_method, ctll::list>(); +template constexpr auto multiline_tokenize = regular_expression::type, tokenize_method, ctll::list>(); -template static constexpr inline auto multiline_iterator = regular_expression::type, iterator_method, ctll::list>(); +template constexpr auto multiline_iterator = regular_expression::type, iterator_method, ctll::list>(); -static constexpr inline auto multiline_sentinel = regex_end_iterator(); +constexpr inline auto multiline_sentinel = regex_end_iterator(); } diff --git a/module-test.cpp b/module-test.cpp new file mode 100644 index 00000000..10548bbf --- /dev/null +++ b/module-test.cpp @@ -0,0 +1,12 @@ +import ctre; + +#include +#include + +int main() { + for (auto item: "123456 2313 23132" | ctre::search_all<"[0-9]++">) { + std::cout << item << "\n"; + } + + return 0; +} \ No newline at end of file diff --git a/pokus2.cpp b/pokus2.cpp new file mode 100644 index 00000000..83f05e01 --- /dev/null +++ b/pokus2.cpp @@ -0,0 +1,48 @@ +#include +#include + +//bool match(std::string_view in) { +// auto r = ctre::search<"([a-z]+)">(in); +// return r; +//} + +const char * print_compare(auto val) { + if (std::is_eq(val)) { + return "=="; + } else if (std::is_lt(val)) { + return "<"; + } else if (std::is_gt(val)) { + return ">"; + } else { + return "!="; + } +} + +void print(const auto & a, const auto & b) { + std::cout << "(" << a << ") " << print_compare(a <=> b) << " (" << b << ")\n"; +} + +int main() { + + int a = 1, b = 2, c = 3, d = 4, e = 5, f = 6; + + print(ctre::tie(a,b,c), ctre::tie(d,e,f)); + + ctre::tuple tpl{}; + ctre::tuple tpl1{1,2,3}; + ctre::tuple tpl2{tpl1}; + + print(tpl1, tpl2); + + ctre::tuple tpl3{std::move(tpl2)}; + + print(tpl2, tpl3); + + tpl3 = tpl; + + print(tpl3, tpl); + + tpl3 = std::move(tpl1); + + print(tpl3, tpl1); +} \ No newline at end of file diff --git a/tests/api.cpp b/tests/api.cpp new file mode 100644 index 00000000..1cd2a3e2 --- /dev/null +++ b/tests/api.cpp @@ -0,0 +1,11 @@ +#include +#include "ctre.hpp" + +int do_something(std::string_view) { + return 42; +} + +int test(std::string_view in) { + ctre::range<"abc">(in) | std::views::transform(do_something); + return 41; +} \ No newline at end of file