Loading...
Searching...
No Matches
predicate_detail.hpp
Go to the documentation of this file.
// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
#include <array>
#include <cctype>
#include <concepts>
#include <stdexcept>
#include <string>
#include <seqan3/utility/concept.hpp>
#include <seqan3/utility/detail/type_name_as_string.hpp>
#include <seqan3/utility/type_traits/basic.hpp>
namespace seqan3::detail
{
// ----------------------------------------------------------------------------
// constexpr_pseudo_bitset (could be replaced with constexpr std::bitset or github.com/ClaasBontus/bitset2)
// ----------------------------------------------------------------------------
template <size_t N>
class constexpr_pseudo_bitset : public std::array<bool, N>
{
private:
using base_t = std::array<bool, N>;
public:
using base_t::base_t;
constexpr constexpr_pseudo_bitset operator|(constexpr_pseudo_bitset rhs) const noexcept
{
for (size_t i = 0; i < N; ++i)
rhs[i] = rhs[i] || base_t::operator[](i);
return rhs;
}
constexpr constexpr_pseudo_bitset operator~() const noexcept
{
constexpr_pseudo_bitset ret{};
for (size_t i = 0; i < N; ++i)
ret[i] = !base_t::operator[](i);
return ret;
}
};
// ----------------------------------------------------------------------------
// condition_message_v
// ----------------------------------------------------------------------------
template <char op, typename condition_head_t, typename... condition_ts>
inline std::string const condition_message_v{
std::string{"("}
+ (condition_head_t::msg + ... + (std::string{" "} + std::string{{op, op}} + std::string{" "} + condition_ts::msg))
+ std::string{")"}};
// ----------------------------------------------------------------------------
// char_predicate
// ----------------------------------------------------------------------------
template <typename condition_t>
struct char_predicate_base;
template <typename condition_t>
concept char_predicate = requires {
requires std::predicate<std::remove_reference_t<condition_t>, char>;
requires std::is_base_of_v<char_predicate_base<std::remove_cvref_t<condition_t>>, std::remove_cvref_t<condition_t>>;
std::remove_reference_t<condition_t>::msg;
//The msg type can be added with a std::string.
{
std::string{} + std::remove_reference_t<condition_t>::msg
} -> std::convertible_to<decltype(std::remove_reference_t<condition_t>::msg)>;
};
// ----------------------------------------------------------------------------
// char_predicate
// ----------------------------------------------------------------------------
template <char_predicate... condition_ts>
requires (sizeof...(condition_ts) >= 2)
struct char_predicate_disjunction;
template <char_predicate condition_t>
struct char_predicate_negator;
template <typename derived_t>
struct char_predicate_base
{
using data_t = constexpr_pseudo_bitset<257>; // sizeof(char) plus EOF
template <char_predicate rhs_t>
constexpr auto operator||(rhs_t const &) const
{
return char_predicate_disjunction<derived_t, rhs_t>{};
}
constexpr auto operator!() const
{
return char_predicate_negator<derived_t>{};
}
template <std::integral value_t>
constexpr bool operator()(value_t const val) const noexcept
requires (sizeof(value_t) == 1)
{
return derived_t::data[static_cast<unsigned char>(val)];
}
template <std::integral value_t>
constexpr bool operator()(value_t const val) const noexcept
requires (sizeof(value_t) != 1)
{
// std::char_traits is only guaranteed to be defined for character types.
// libc++ deprecates other specialisations in llvm-17, and removes them in llvm-18.
// We map the non-character types to corresponding chracter types.
// For example, `seqan3::is_eof(EOF)` will call this function with `value_t == int`.
using char_value_t = std::conditional_t<
seqan3::builtin_character<value_t>,
value_t,
std::conditional_t<
std::same_as<value_t, std::char_traits<char>::int_type>,
char,
std::conditional_t<
std::same_as<value_t, std::char_traits<wchar_t>::int_type>,
wchar_t,
std::conditional_t<
std::same_as<value_t, std::char_traits<char8_t>::int_type>,
char8_t,
std::conditional_t<
std::same_as<value_t, std::char_traits<char16_t>::int_type>,
char16_t,
std::conditional_t<std::same_as<value_t, std::char_traits<char32_t>::int_type>,
char32_t,
void>>>>>>;
static_assert(!std::same_as<char_value_t, void>, "There is no valid character representation.");
using char_trait = std::char_traits<char_value_t>;
return (static_cast<std::make_unsigned_t<value_t>>(val) < 256) ? operator()(static_cast<uint8_t>(val))
: (char_trait::eq_int_type(val, char_trait::eof())) ? derived_t::data[256]
: false;
}
std::string message() const
{
return derived_t::msg;
}
};
// ----------------------------------------------------------------------------
// char_predicate_disjunction
// ----------------------------------------------------------------------------
template <char_predicate... condition_ts>
requires (sizeof...(condition_ts) >= 2)
struct char_predicate_disjunction : public char_predicate_base<char_predicate_disjunction<condition_ts...>>
{
static inline std::string const msg = detail::condition_message_v<'|', condition_ts...>;
using base_t = char_predicate_base<char_predicate_disjunction<condition_ts...>>;
using typename base_t::data_t;
static constexpr data_t data = (condition_ts::data | ...);
};
template <char_predicate condition_t>
struct char_predicate_negator : public char_predicate_base<char_predicate_negator<condition_t>>
{
static inline std::string const msg = std::string{'!'} + condition_t::msg;
using base_t = char_predicate_base<char_predicate_negator<condition_t>>;
using typename base_t::data_t;
static constexpr data_t data = ~condition_t::data;
};
// ----------------------------------------------------------------------------
// is_in_interval_type
// ----------------------------------------------------------------------------
template <uint8_t interval_first, uint8_t interval_last>
requires (interval_first <= interval_last)
struct is_in_interval_type : public char_predicate_base<is_in_interval_type<interval_first, interval_last>>
{
static inline std::string const msg = std::string{"is_in_interval<'"} + std::string{interval_first}
+ std::string{"', '"} + std::string{interval_last} + std::string{"'>"};
using base_t = char_predicate_base<is_in_interval_type<interval_first, interval_last>>;
using typename base_t::data_t;
static constexpr data_t data = []() constexpr
{
data_t ret{};
for (size_t i = interval_first; i <= static_cast<size_t>(interval_last); ++i)
ret[i] = true;
return ret;
}();
};
// ----------------------------------------------------------------------------
// is_char_type
// ----------------------------------------------------------------------------
template <int char_v>
struct is_char_type : public char_predicate_base<is_char_type<char_v>>
{
static_assert(char_v == EOF || static_cast<uint64_t>(char_v) < 256, "TODO");
static inline std::string const msg =
std::string{"is_char<'"} + ((char_v == EOF) ? std::string{"EOF"} : std::string{char_v}) + std::string{"'>"};
using base_t = char_predicate_base<is_char_type<char_v>>;
using typename base_t::data_t;
static constexpr data_t data = []() constexpr
{
data_t ret{};
if (char_v == EOF)
ret[256] = true;
else
ret[static_cast<uint8_t>(char_v)] = true;
return ret;
}();
};
} // namespace seqan3::detail
array
basic.hpp
Provides various type traits on generic types.
cctype
std::is_base_of_v
T is_base_of_v
stdexcept
string
type_name_as_string.hpp
Provides traits to inspect some information of a type, for example its name.
concept.hpp
Provides concepts that do not have equivalents in C++20.
Hide me