#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include #include "llvm/ADT/StringRef.h" namespace compile_time { namespace detail { template using RVHelper = decltype(std::declval().template operator()<0>()); template requires(std::is_same_v, void>) constexpr void repeat(std::index_sequence, TemplatedCallableType &&Callable) { (Callable.template operator()(), ...); } template requires(!std::is_same_v, void>) constexpr auto repeat(std::index_sequence, TemplatedCallableType &&Callable) { return std::tie(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 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 auto repeat(CallableType &&Callable) { if constexpr (IterationCount > 0) return 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 detail { template inline constexpr bool split(std::array &Result, llvm::StringRef Separator, llvm::StringRef Input) { size_t Position = Input.find(Separator); if constexpr (I < N - 1) { if (Position == llvm::StringRef::npos) return false; Result[I] = Input.substr(0, Position); return split(Result, Separator, Input.substr(Position + 1)); } else { if (Position != llvm::StringRef::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 `llvm::StringRef` 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(llvm::StringRef Separator, llvm::StringRef Input) { if (std::array Result; detail::split(Result, Separator, Input)) return Result; else return std::nullopt; } } // namespace compile_time