6#ifndef MIMICPP_SEQUENCE_HPP
7#define MIMICPP_SEQUENCE_HPP
79 template <
typename Id, auto priorityStrategy>
80 requires std::is_enum_v<Id>
81 && std::signed_integral<std::underlying_type_t<Id>>
82 && std::convertible_to<
83 std::invoke_result_t<
decltype(priorityStrategy),
Id,
int>,
90 ~BasicSequence() noexcept(false)
92 const auto iter = std::ranges::find_if_not(
93 m_Entries.cbegin() + m_Cursor,
95 [](
const State s)
noexcept
97 return s == State::satisfied
98 || s == State::saturated;
101 if (iter != m_Entries.cend())
103 mimicpp::detail::report_error(
105 "Unfulfilled sequence. {} out of {} expectation(s) are satisfied.",
106 std::ranges::distance(m_Entries.cbegin(), iter),
112 BasicSequence() =
default;
114 BasicSequence(
const BasicSequence&) =
delete;
115 BasicSequence& operator =(
const BasicSequence&) =
delete;
116 BasicSequence(BasicSequence&&) =
delete;
117 BasicSequence& operator =(BasicSequence&&) =
delete;
120 constexpr std::optional<int> priority_of(
const IdT
id)
const noexcept
122 assert(is_valid(
id));
124 if (is_consumable(
id))
135 constexpr void set_satisfied(
const IdT
id)
noexcept
137 assert(is_valid(
id));
139 assert(m_Cursor <= index);
142 assert(element == State::unsatisfied);
143 element = State::satisfied;
146 constexpr void set_saturated(
const IdT
id)
noexcept
148 assert(is_valid(
id));
150 assert(m_Cursor <= index);
152 auto& element = m_Entries[index];
154 element == State::unsatisfied
155 || element == State::satisfied);
156 element = State::saturated;
160 constexpr bool is_consumable(
const IdT
id)
const noexcept
162 assert(is_valid(
id));
165 const auto state = m_Entries[index];
166 return m_Cursor <= index
167 && std::ranges::all_of(
168 m_Entries.begin() + m_Cursor,
169 m_Entries.begin() + index,
170 [](
const State s)
noexcept
172 return s == State::satisfied
173 || s == State::saturated;
175 && (state == State::unsatisfied
176 || state == State::satisfied);
179 constexpr void consume(
const IdT
id)
noexcept
181 assert(is_consumable(
id));
189 if (!std::in_range<std::underlying_type_t<IdT>>(m_Entries.size()))
192 throw std::runtime_error{
193 "Sequence already holds maximum amount of elements."
197 m_Entries.emplace_back(State::unsatisfied);
198 return static_cast<IdT
>(m_Entries.size() - 1);
202 constexpr Tag tag() const noexcept
205 std::bit_cast<std::ptrdiff_t>(
this)
217 std::vector<State> m_Entries{};
221 constexpr bool is_valid(
const IdT
id)
const noexcept
232 constexpr int operator ()(
const auto id,
const int cursor)
const noexcept
235 assert(std::cmp_less_equal(cursor, index));
237 return std::numeric_limits<int>::max()
238 - (
static_cast<int>(index) - cursor);
246 constexpr int operator ()(
const auto id,
const int cursor)
const noexcept
249 assert(std::cmp_less_equal(cursor, index));
251 return static_cast<int>(index) - cursor;
255 template <
typename Id, auto priorityStrategy>
256 class BasicSequenceInterface
258 template <
typename... Sequences>
262 using SequenceT = BasicSequence<Id, priorityStrategy>;
264 ~BasicSequenceInterface() =
default;
267 BasicSequenceInterface() =
default;
269 BasicSequenceInterface(
const BasicSequenceInterface&) =
delete;
270 BasicSequenceInterface& operator =(
const BasicSequenceInterface&) =
delete;
271 BasicSequenceInterface(BasicSequenceInterface&&) =
delete;
272 BasicSequenceInterface& operator =(BasicSequenceInterface&&) =
delete;
275 constexpr Tag tag() const noexcept
277 return m_Sequence->tag();
281 std::shared_ptr<SequenceT> m_Sequence{
282 std::make_shared<SequenceT>()
286 template <
typename... Sequences>
289 template <
typename... Ts>
293 static constexpr std::size_t sequenceCount =
sizeof...(Sequences);
297 requires (0 ==
sizeof...(Sequences))
300 template <
typename... Interfaces>
301 requires (
sizeof...(Interfaces) == sequenceCount)
303 explicit constexpr Config(Interfaces&... interfaces)
noexcept(1 == sequenceCount)
305 interfaces.m_Sequence...
311 constexpr auto& sequences() const noexcept
316 template <
typename... OtherSequences>
318 constexpr Config<Sequences..., OtherSequences...> concat(
319 const Config<OtherSequences...>& other
323 [](
auto... sequences)
325 return Config<Sequences..., OtherSequences...>{
326 std::move(sequences)...
329 std::tuple_cat(m_Sequences, other.sequences()));
333 std::tuple<std::shared_ptr<Sequences>...> m_Sequences;
336 explicit constexpr Config(std::shared_ptr<Sequences>... sequences)
noexcept(1 == sequenceCount)
337 requires (0 < sequenceCount)
339 if constexpr (1 < sequenceCount)
345 std::ranges::sort(tags);
346 if (!std::ranges::empty(std::ranges::unique(tags)))
348 throw std::invalid_argument{
349 "Expectations can not be assigned to the same sequence multiple times."
354 m_Sequences = std::tuple{
355 std::move(sequences)...
373 :
public sequence::detail::BasicSequenceInterface<
375 sequence::detail::LazyStrategy{}>
388 :
public sequence::detail::BasicSequenceInterface<
390 sequence::detail::GreedyStrategy{}>
401namespace mimicpp::sequence::detail
404 constexpr bool has_better_rating(
405 const std::span<const rating> lhs,
406 const std::span<const rating> rhs
410 for (
const auto& [lhsPriority, lhsTag] : lhs)
412 if (
const auto iter = std::ranges::find(rhs, lhsTag, &
rating::tag);
413 iter != std::ranges::end(rhs))
415 rating += lhsPriority < iter->priority
440 template <
typename Id, auto priorityStrategy>
442 constexpr auto in_sequence(sequence::detail::BasicSequenceInterface<Id, priorityStrategy>& sequence)
noexcept
444 using ConfigT = sequence::detail::Config<
445 sequence::detail::BasicSequence<Id, priorityStrategy>>;
464 auto firstPriorityStrategy,
466 auto secondPriorityStrategy,
467 typename... OtherIds,
468 auto... otherPriorityStrategies
472 sequence::detail::BasicSequenceInterface<FirstId, firstPriorityStrategy>& firstSequence,
473 sequence::detail::BasicSequenceInterface<SecondId, secondPriorityStrategy>& secondSequence,
474 sequence::detail::BasicSequenceInterface<OtherIds, otherPriorityStrategies>&... otherSequences
477 using ConfigT = sequence::detail::Config<
478 sequence::detail::BasicSequence<FirstId, firstPriorityStrategy>,
479 sequence::detail::BasicSequence<SecondId, secondPriorityStrategy>,
480 sequence::detail::BasicSequence<OtherIds, otherPriorityStrategies>...>;
The greedy sequence interface.
Definition Sequence.hpp:391
The lazy sequence interface.
Definition Sequence.hpp:376
constexpr auto in_sequences(sequence::detail::BasicSequenceInterface< FirstId, firstPriorityStrategy > &firstSequence, sequence::detail::BasicSequenceInterface< SecondId, secondPriorityStrategy > &secondSequence, sequence::detail::BasicSequenceInterface< OtherIds, otherPriorityStrategies > &... otherSequences)
Attaches the expectation onto the listed sequences.
Definition Sequence.hpp:471
constexpr auto in_sequence(sequence::detail::BasicSequenceInterface< Id, priorityStrategy > &sequence) noexcept
Attaches the expectation onto a sequence.
Definition Sequence.hpp:442
LazySequence SequenceT
The default sequence type (LazySequence).
Definition Sequence.hpp:398
Definition ControlPolicy.hpp:267
Tag
Definition Fwd.hpp:119
Definition BoostTest.hpp:20
constexpr std::underlying_type_t< T > to_underlying(const T value) noexcept
Definition Utility.hpp:73
Tag tag
Definition Fwd.hpp:130