#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include namespace compile_time { namespace detail { template constexpr void repeat(std::index_sequence, TemplatedCallableType &&Callable) { (Callable.template operator()(), ...); } template constexpr bool repeatAnd(std::index_sequence, TemplatedCallableType &&Callable) { return (Callable.template operator()() && ...); } template constexpr bool repeatOr(std::index_sequence, TemplatedCallableType &&Callable) { return (Callable.template operator()() || ...); } template constexpr std::size_t count(std::index_sequence, TemplatedCallableType &&Callable) { return ((Callable.template operator()() ? 1 : 0) + ...); } template constexpr std::optional select(std::index_sequence Is, TemplatedCallableType &&Callable) { if (count(Is, Callable) == 1) return ((Callable.template operator()() ? Indices : 0) + ...); else return std::nullopt; } } // namespace detail /// Calls \ref Callable \ref IterationCount times. template constexpr void repeat(CallableType &&Callable) { detail::repeat(std::make_index_sequence(), std::forward(Callable)); } /// Calls \ref Callable \ref IterationCount times, while applying logical AND /// operation to the return values. template constexpr bool repeatAnd(CallableType &&Callable) { return detail::repeatAnd(std::make_index_sequence(), std::forward(Callable)); } /// Calls \ref Callable \ref IterationCount times, while applying logical OR /// operation to the return values. template constexpr bool repeatOr(CallableType &&Callable) { return detail::repeatOr(std::make_index_sequence(), std::forward(Callable)); } /// Calls \ref Callable \ref IterationCount times, makes sure at most one of /// those invocations has a non-zero return value, then returns its index if /// there is one, or `std::nullopt` if there's none. template constexpr std::optional select(CallableType &&Callable) { return detail::select(std::make_index_sequence(), std::forward(Callable)); } namespace examples { using namespace std::string_view_literals; template consteval std::size_t fullSize(std::array Components, std::string_view Separator) { std::size_t Result = Separator.size() * Count; compile_time::repeat([&Result, &Components] { Result += std::get(Components).size(); }); return Result; } inline constexpr std::array Components = { "instruction"sv, "0x401000:Code_x86_64"sv, "0x402000:Code_x86_64"sv, "0x403000:Code_x86_64"sv }; static_assert(fullSize(Components, "/"sv) == 75); } // namespace examples namespace detail { template inline constexpr bool split(std::array &Result, std::string_view Separator, std::string_view Input) { std::size_t Position = Input.find(Separator); if constexpr (I < N - 1) { if (Position == std::string_view::npos) return false; Result[I] = Input.substr(0, Position); return split(Result, Separator, Input.substr(Position + 1)); } else { if (Position != std::string_view::npos) return false; Result[I] = Input; return true; } } } // namespace detail /// I'm forced to implement my own split because `llvm::StringRef`'s alternative /// is not `constexpr`-compatible. /// /// This also uses `std::string_view` instead of `llvm::StringRef` because its /// `find` member is constexpr - hence at least that member doesn't have to be /// reimplemented template inline constexpr std::optional> split(std::string_view Separator, std::string_view Input) { if (std::array Result; detail::split(Result, Separator, Input)) return Result; else return std::nullopt; } } // namespace compile_time