3#include <tess/storage/chunk_page.h>
4#include <tess/topology/step_policy.h>
19namespace tess::movement {
30template <
typename Tag>
32 template <
typename Page>
33 [[nodiscard]]
static constexpr bool eval(
const Page& page,
35 static_assert(Page::schema_type::template contains<Tag>,
36 "MovementClass references a field absent from the schema.");
37 return static_cast<bool>(page.template field<Tag>(
id));
43template <
typename Tag>
45 template <
typename Page>
46 [[nodiscard]]
static constexpr bool eval(
const Page& page,
48 static_assert(Page::schema_type::template contains<Tag>,
49 "MovementClass references a field absent from the schema.");
50 return page.template field<Tag>(
id) != 0;
55template <
typename Term>
57 template <
typename Page>
58 [[nodiscard]]
static constexpr bool eval(
const Page& page,
60 return !Term::eval(page,
id);
65template <
typename... Terms>
67 template <
typename Page>
68 [[nodiscard]]
static constexpr bool eval(
const Page& page,
70 return (
true && ... && Terms::eval(page,
id));
75template <
typename... Terms>
77 template <
typename Page>
78 [[nodiscard]]
static constexpr bool eval(
const Page& page,
80 return (
false || ... || Terms::eval(page,
id));
94template <
typename Value>
95[[nodiscard]]
constexpr std::uint32_t normalize_cost(Value value)
noexcept {
96 static_assert(std::is_integral_v<std::remove_cvref_t<Value>>,
97 "MovementClass cost field must be integral.");
98 if constexpr (std::is_signed_v<std::remove_cvref_t<Value>>) {
102 }
else if (value == 0) {
105 if (
static_cast<std::uint64_t
>(value) >
106 std::numeric_limits<std::uint32_t>::max()) {
107 return std::numeric_limits<std::uint32_t>::max();
109 return static_cast<std::uint32_t
>(value);
116 template <
typename Page>
117 [[nodiscard]]
static constexpr std::uint32_t eval(
const Page&,
124template <std::u
int32_t N>
126 template <
typename Page>
127 [[nodiscard]]
static constexpr std::uint32_t eval(
const Page&,
134template <
typename CostTag>
136 template <
typename Page>
137 [[nodiscard]]
static constexpr std::uint32_t eval(
const Page& page,
139 static_assert(Page::schema_type::template contains<CostTag>,
140 "MovementClass references a field absent from the schema.");
141 return normalize_cost(page.template field<CostTag>(
id));
167template <
typename Base,
typename Overlay>
169 template <
typename Page>
170 [[nodiscard]]
static constexpr std::uint32_t eval(
const Page& page,
172 const auto base = Base::eval(page,
id);
176 const auto sum =
static_cast<std::uint64_t
>(base) +
177 static_cast<std::uint64_t
>(Overlay::eval(page,
id));
178 constexpr auto ceiling =
179 static_cast<std::uint64_t
>(std::numeric_limits<std::uint32_t>::max());
180 return static_cast<std::uint32_t
>(sum > ceiling ? ceiling : sum);
187template <
typename SelTag,
typename WhenSet,
typename WhenClear>
189 template <
typename Page>
190 [[nodiscard]]
static constexpr std::uint32_t eval(
const Page& page,
192 static_assert(Page::schema_type::template contains<SelTag>,
193 "MovementClass references a field absent from the schema.");
194 return static_cast<bool>(page.template field<SelTag>(
id))
195 ? WhenSet::eval(page,
id)
196 : WhenClear::eval(page,
id);
203template <
typename PassExpr,
typename CostExpr,
206 using pass_expr = PassExpr;
207 using cost_expr = CostExpr;
208 using step_policy = StepPolicyT;
210 template <
typename Page>
211 [[nodiscard]]
static constexpr bool passable(
const Page& page,
213 return PassExpr::eval(page,
id);
216 template <
typename Page>
217 [[nodiscard]]
static constexpr std::uint32_t entry_cost(
219 return CostExpr::eval(page,
id);
225template <
typename C,
typename Page>
229 C::passable(page,
id)
230 } -> std::convertible_to<bool>;
232 C::entry_cost(page,
id)
233 } -> std::convertible_to<std::uint32_t>;
243template <
typename PassableTag>
245 using passable_tag = PassableTag;
247 template <
typename Page>
248 [[nodiscard]]
static constexpr auto passable_span(Page& page)
noexcept {
249 return page.template field_span<PassableTag>();
258template <
typename PassableTag,
typename CostTag>
261 FieldCost<CostTag>> {};
278using movement_class_of =
279 std::conditional_t<std::derived_from<T, movement_class_tag>, T,
286template <
typename ClassOrTag>
288 using source_class = movement_class_of<ClassOrTag>;
290 using step_policy = step_policy_of<source_class>;
292 template <
typename Page>
293 [[nodiscard]]
static constexpr bool passable(
const Page& page,
295 return source_class::passable(page,
id);
298 template <
typename Page>
299 [[nodiscard]]
static constexpr std::uint32_t entry_cost(
Checks whether a movement class advertises the exact field-span fast path.
Definition movement_class.h:271
Checks that C provides movement operations compatible with Page.
Definition movement_class.h:226
Requires every supplied passability term to evaluate true.
Definition movement_class.h:66
Requires at least one supplied passability term to evaluate true.
Definition movement_class.h:76
Produces compile-time constant entry cost N for every tile.
Definition movement_class.h:125
Definition step_policy.h:26
Reads and normalizes integral entry cost field CostTag.
Definition movement_class.h:135
Evaluates the truthiness of field Tag at a resolved tile.
Definition movement_class.h:31
Combines compile-time passability and entry-cost expressions.
Definition movement_class.h:205
Evaluates whether integral field Tag is nonzero at a resolved tile.
Definition movement_class.h:44
Negates one compile-time passability term.
Definition movement_class.h:56
Definition movement_class.h:168
Combines a truthy field and positive cost field into weighted movement.
Definition movement_class.h:261
Selects between two cost expressions using field SelTag.
Definition movement_class.h:188
Adapts a truthy passability field to unit-cost movement.
Definition movement_class.h:244
Produces unit entry cost for every tile.
Definition movement_class.h:115
Marks types that implement the compile-time movement-class contract.
Definition movement_class.h:24