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));
141 assert(element == State::unsatisfied);
142 element = State::satisfied;
145 constexpr void set_saturated(
const IdT
id)
noexcept
147 assert(is_valid(
id));
149 assert(m_Cursor <= index);
151 auto& element = m_Entries[index];
153 element == State::unsatisfied
154 || element == State::satisfied);
155 element = State::saturated;
159 constexpr bool is_consumable(
const IdT
id)
const noexcept
161 assert(is_valid(
id));
164 const auto state = m_Entries[index];
165 return m_Cursor <= index
166 && std::ranges::all_of(
167 m_Entries.begin() + m_Cursor,
168 m_Entries.begin() + index,
169 [](
const State s)
noexcept
171 return s == State::satisfied
172 || s == State::saturated;
174 && (state == State::unsatisfied
175 || state == State::satisfied);
178 constexpr void consume(
const IdT
id)
noexcept
180 assert(is_consumable(
id));
188 if (!std::in_range<std::underlying_type_t<IdT>>(m_Entries.size()))
191 throw std::runtime_error{
192 "Sequence already holds maximum amount of elements."
196 m_Entries.emplace_back(State::unsatisfied);
197 return static_cast<IdT
>(m_Entries.size() - 1);
201 constexpr Tag tag() const noexcept
204 std::bit_cast<std::ptrdiff_t>(
this)
216 std::vector<State> m_Entries{};
220 constexpr bool is_valid(
const IdT
id)
const noexcept
231 constexpr int operator ()(
const auto id,
const int cursor)
const noexcept
234 assert(std::cmp_less_equal(cursor, index));
236 return std::numeric_limits<int>::max()
237 - (
static_cast<int>(index) - cursor);
245 constexpr int operator ()(
const auto id,
const int cursor)
const noexcept
248 assert(std::cmp_less_equal(cursor, index));
250 return static_cast<int>(index) - cursor;
254 template <
typename Id, auto priorityStrategy>
255 class BasicSequenceInterface
257 template <
typename... Sequences>
261 using SequenceT = BasicSequence<Id, priorityStrategy>;
263 ~BasicSequenceInterface() =
default;
266 BasicSequenceInterface() =
default;
268 BasicSequenceInterface(
const BasicSequenceInterface&) =
delete;
269 BasicSequenceInterface& operator =(
const BasicSequenceInterface&) =
delete;
270 BasicSequenceInterface(BasicSequenceInterface&&) =
delete;
271 BasicSequenceInterface& operator =(BasicSequenceInterface&&) =
delete;
274 constexpr Tag tag() const noexcept
276 return m_Sequence->tag();
280 std::shared_ptr<SequenceT> m_Sequence{
281 std::make_shared<SequenceT>()
285 template <
typename... Sequences>
288 template <
typename... Ts>
292 static constexpr std::size_t sequenceCount =
sizeof...(Sequences);
296 requires (0 ==
sizeof...(Sequences))
299 template <
typename... Interfaces>
300 requires (
sizeof...(Interfaces) == sequenceCount)
302 explicit constexpr Config(Interfaces&... interfaces)
noexcept(1 == sequenceCount)
304 interfaces.m_Sequence...
310 constexpr auto& sequences() const noexcept
315 template <
typename... OtherSequences>
317 constexpr Config<Sequences..., OtherSequences...> concat(
318 const Config<OtherSequences...>& other
322 [](
auto... sequences)
324 return Config<Sequences..., OtherSequences...>{
325 std::move(sequences)...
328 std::tuple_cat(m_Sequences, other.sequences()));
332 std::tuple<std::shared_ptr<Sequences>...> m_Sequences;
335 explicit constexpr Config(std::shared_ptr<Sequences>... sequences)
noexcept(1 == sequenceCount)
336 requires (0 < sequenceCount)
338 if constexpr (1 < sequenceCount)
344 std::ranges::sort(tags);
345 if (!std::ranges::empty(std::ranges::unique(tags)))
347 throw std::invalid_argument{
348 "Expectations can not be assigned to the same sequence multiple times."
353 m_Sequences = std::tuple{
354 std::move(sequences)...
372 :
public sequence::detail::BasicSequenceInterface<
374 sequence::detail::LazyStrategy{}>
387 :
public sequence::detail::BasicSequenceInterface<
389 sequence::detail::GreedyStrategy{}>
400namespace mimicpp::sequence::detail
403 constexpr bool has_better_rating(
404 const std::span<const rating> lhs,
405 const std::span<const rating> rhs
409 for (
const auto& [lhsPriority, lhsTag] : lhs)
411 if (
const auto iter = std::ranges::find(rhs, lhsTag, &
rating::tag);
412 iter != std::ranges::end(rhs))
414 rating += lhsPriority < iter->priority
439 template <
typename Id, auto priorityStrategy>
441 constexpr auto in_sequence(sequence::detail::BasicSequenceInterface<Id, priorityStrategy>& sequence)
noexcept
443 using ConfigT = sequence::detail::Config<
444 sequence::detail::BasicSequence<Id, priorityStrategy>>;
463 auto firstPriorityStrategy,
465 auto secondPriorityStrategy,
466 typename... OtherIds,
467 auto... otherPriorityStrategies
471 sequence::detail::BasicSequenceInterface<FirstId, firstPriorityStrategy>& firstSequence,
472 sequence::detail::BasicSequenceInterface<SecondId, secondPriorityStrategy>& secondSequence,
473 sequence::detail::BasicSequenceInterface<OtherIds, otherPriorityStrategies>&... otherSequences
476 using ConfigT = sequence::detail::Config<
477 sequence::detail::BasicSequence<FirstId, firstPriorityStrategy>,
478 sequence::detail::BasicSequence<SecondId, secondPriorityStrategy>,
479 sequence::detail::BasicSequence<OtherIds, otherPriorityStrategies>...>;
The greedy sequence interface.
Definition Sequence.hpp:390
The lazy sequence interface.
Definition Sequence.hpp:375
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:470
constexpr auto in_sequence(sequence::detail::BasicSequenceInterface< Id, priorityStrategy > &sequence) noexcept
Attaches the expectation onto a sequence.
Definition Sequence.hpp:441
LazySequence SequenceT
The default sequence type (LazySequence).
Definition Sequence.hpp:397
Definition ControlPolicy.hpp:266
Tag
Definition Fwd.hpp:215
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:226