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 {
96 return s == State::satisfied
97 || s == State::saturated;
100 if (iter != m_Entries.cend())
102 mimicpp::detail::report_error(
104 "Unfulfilled sequence. {} out of {} expectation(s) are satisfied.",
105 std::ranges::distance(m_Entries.cbegin(), iter),
111 BasicSequence() =
default;
113 BasicSequence(
const BasicSequence&) =
delete;
114 BasicSequence& operator=(
const BasicSequence&) =
delete;
115 BasicSequence(BasicSequence&&) =
delete;
116 BasicSequence& operator=(BasicSequence&&) =
delete;
119 constexpr std::optional<int> priority_of(
const IdT
id)
const noexcept
121 assert(is_valid(
id));
123 if (is_consumable(
id))
134 constexpr void set_satisfied(
const IdT
id)
noexcept
136 assert(is_valid(
id));
140 assert(element == State::unsatisfied);
141 element = State::satisfied;
144 constexpr void set_saturated(
const IdT
id)
noexcept
146 assert(is_valid(
id));
148 assert(m_Cursor <= index);
150 auto& element = m_Entries[index];
152 element == State::unsatisfied
153 || element == State::satisfied);
154 element = State::saturated;
158 constexpr bool is_consumable(
const IdT
id)
const noexcept
160 assert(is_valid(
id));
163 const auto state = m_Entries[index];
164 return m_Cursor <= index
165 && std::ranges::all_of(
166 m_Entries.begin() + m_Cursor,
167 m_Entries.begin() + index,
168 [](
const State s)
noexcept {
169 return s == State::satisfied
170 || s == State::saturated;
172 && (state == State::unsatisfied
173 || state == State::satisfied);
176 constexpr void consume(
const IdT
id)
noexcept
178 assert(is_consumable(
id));
186 if (!std::in_range<std::underlying_type_t<IdT>>(m_Entries.size()))
189 throw std::runtime_error{
190 "Sequence already holds maximum amount of elements."};
193 m_Entries.emplace_back(State::unsatisfied);
194 return static_cast<IdT
>(m_Entries.size() - 1);
198 constexpr Tag tag() const noexcept
201 std::bit_cast<std::ptrdiff_t>(
this)};
212 std::vector<State> m_Entries{};
216 constexpr bool is_valid(
const IdT
id)
const noexcept
227 constexpr int operator()(
const auto id,
const int cursor)
const noexcept
230 assert(std::cmp_less_equal(cursor, index));
232 return std::numeric_limits<int>::max()
233 - (
static_cast<int>(index) - cursor);
241 constexpr int operator()(
const auto id,
const int cursor)
const noexcept
244 assert(std::cmp_less_equal(cursor, index));
246 return static_cast<int>(index) - cursor;
250 template <
typename Id, auto priorityStrategy>
251 class BasicSequenceInterface
253 template <
typename... Sequences>
257 using SequenceT = BasicSequence<Id, priorityStrategy>;
259 ~BasicSequenceInterface() =
default;
262 BasicSequenceInterface() =
default;
264 BasicSequenceInterface(
const BasicSequenceInterface&) =
delete;
265 BasicSequenceInterface& operator=(
const BasicSequenceInterface&) =
delete;
266 BasicSequenceInterface(BasicSequenceInterface&&) =
delete;
267 BasicSequenceInterface& operator=(BasicSequenceInterface&&) =
delete;
270 constexpr Tag tag() const noexcept
272 return m_Sequence->tag();
276 std::shared_ptr<SequenceT> m_Sequence{
277 std::make_shared<SequenceT>()};
280 template <
typename... Sequences>
283 template <
typename... Ts>
287 static constexpr std::size_t sequenceCount =
sizeof...(Sequences);
291 requires(0 ==
sizeof...(Sequences))
294 template <
typename... Interfaces>
295 requires(
sizeof...(Interfaces) == sequenceCount)
296 [[nodiscard]]
explicit constexpr Config(Interfaces&... interfaces)
noexcept(1 == sequenceCount)
298 interfaces.m_Sequence...}
303 constexpr auto& sequences() const noexcept
308 template <
typename... OtherSequences>
310 constexpr Config<Sequences..., OtherSequences...> concat(
311 const Config<OtherSequences...>& other)
const
314 [](
auto... sequences) {
315 return Config<Sequences..., OtherSequences...>{
316 std::move(sequences)...};
318 std::tuple_cat(m_Sequences, other.sequences()));
322 std::tuple<std::shared_ptr<Sequences>...> m_Sequences;
325 explicit constexpr Config(std::shared_ptr<Sequences>... sequences)
noexcept(1 == sequenceCount)
326 requires(0 < sequenceCount)
328 if constexpr (1 < sequenceCount)
331 sequences->tag()...};
333 std::ranges::sort(tags);
334 if (!std::ranges::empty(std::ranges::unique(tags)))
336 throw std::invalid_argument{
337 "Expectations can not be assigned to the same sequence multiple times."};
341 m_Sequences = std::tuple{
342 std::move(sequences)...};
359 :
public sequence::detail::BasicSequenceInterface<
361 sequence::detail::LazyStrategy{}>
374 :
public sequence::detail::BasicSequenceInterface<
376 sequence::detail::GreedyStrategy{}>
387namespace mimicpp::sequence::detail
390 constexpr bool has_better_rating(
391 const std::span<const rating> lhs,
392 const std::span<const rating> rhs)
noexcept
395 for (
const auto& [lhsPriority, lhsTag] : lhs)
397 if (
const auto iter = std::ranges::find(rhs, lhsTag, &
rating::tag);
398 iter != std::ranges::end(rhs))
400 rating += lhsPriority < iter->priority
425 template <
typename Id, auto priorityStrategy>
427 constexpr auto in_sequence(sequence::detail::BasicSequenceInterface<Id, priorityStrategy>&
sequence)
noexcept
429 using ConfigT = sequence::detail::Config<
430 sequence::detail::BasicSequence<Id, priorityStrategy>>;
448 auto firstPriorityStrategy,
450 auto secondPriorityStrategy,
451 typename... OtherIds,
452 auto... otherPriorityStrategies>
455 sequence::detail::BasicSequenceInterface<FirstId, firstPriorityStrategy>& firstSequence,
456 sequence::detail::BasicSequenceInterface<SecondId, secondPriorityStrategy>& secondSequence,
457 sequence::detail::BasicSequenceInterface<OtherIds, otherPriorityStrategies>&... otherSequences)
459 using ConfigT = sequence::detail::Config<
460 sequence::detail::BasicSequence<FirstId, firstPriorityStrategy>,
461 sequence::detail::BasicSequence<SecondId, secondPriorityStrategy>,
462 sequence::detail::BasicSequence<OtherIds, otherPriorityStrategies>...>;
The greedy sequence interface.
Definition Sequence.hpp:377
The lazy sequence interface.
Definition Sequence.hpp:362
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:454
constexpr auto in_sequence(sequence::detail::BasicSequenceInterface< Id, priorityStrategy > &sequence) noexcept
Attaches the expectation onto a sequence.
Definition Sequence.hpp:427
LazySequence SequenceT
The default sequence type (LazySequence).
Definition Sequence.hpp:384
Definition ArgRequirementPolicies.hpp:106
Tag
Definition Fwd.hpp:355
Definition BoostTest.hpp:20
constexpr std::underlying_type_t< T > to_underlying(const T value) noexcept
Definition Utility.hpp:71
Tag tag
Definition Fwd.hpp:365