63 using ReflectionBlock = DataBlock<Reflection, N>;
69 [[nodiscard]] ReflectionBlock& reflectionBlock(pos_t block)
71 return reflection_[block];
74 [[nodiscard]] ReflectionBlock
const& reflectionBlock(pos_t block)
const
76 return reflection_[block];
83 [[nodiscard]]
Reflection reflection(Index node)
const
85 return reflection_[node.pos][node.offset];
88 [[nodiscard]]
Reflection reflection(Node node)
const
90 return reflection(derived().
index(node));
93 [[nodiscard]]
Reflection reflection(Code code)
const
95 return reflection(derived().
index(code));
98 [[nodiscard]]
Reflection reflection(Key key)
const
100 return reflection(derived().
index(key));
103 [[nodiscard]]
Reflection reflection(Point coord, depth_t depth = 0)
const
105 return reflection(derived().
index(coord, depth));
112 [[nodiscard]] reflection_t reflectiveness(Index node)
const
114 return reflection(node).reflectiveness();
117 [[nodiscard]] reflection_t reflectiveness(Node node)
const
119 return reflectiveness(derived().
index(node));
122 [[nodiscard]] reflection_t reflectiveness(Code code)
const
124 return reflectiveness(derived().
index(code));
127 [[nodiscard]] reflection_t reflectiveness(Key key)
const
129 return reflectiveness(derived().
index(key));
132 [[nodiscard]] reflection_t reflectiveness(Point coord, depth_t depth = 0)
const
134 return reflectiveness(derived().
index(coord, depth));
141 [[nodiscard]] count_t hits(Index node)
const {
return reflection(node).hits; }
143 [[nodiscard]] count_t hits(Node node)
const {
return hits(derived().
index(node)); }
145 [[nodiscard]] count_t hits(Code code)
const {
return hits(derived().
index(code)); }
147 [[nodiscard]] count_t hits(Key key)
const {
return hits(derived().
index(key)); }
149 [[nodiscard]] count_t hits(Point coord, depth_t depth = 0)
const
151 return hits(derived().
index(coord, depth));
158 [[nodiscard]] count_t misses(Index node)
const {
return reflection(node).misses; }
160 [[nodiscard]] count_t misses(Node node)
const {
return misses(derived().
index(node)); }
162 [[nodiscard]] count_t misses(Code code)
const {
return misses(derived().
index(code)); }
164 [[nodiscard]] count_t misses(Key key)
const {
return misses(derived().
index(key)); }
166 [[nodiscard]] count_t misses(Point coord, depth_t depth = 0)
const
168 return misses(derived().
index(coord, depth));
175 void setReflection(Index node,
Reflection value)
178 node, [
this, value](Index node) { reflection_[node.pos][node.offset] = value; },
179 [
this, value](pos_t pos) { reflection_[pos].fill(value); });
182 Node setReflection(Node node,
Reflection value,
bool propagate =
true)
184 return derived().apply(
185 node, [
this, value](Index node) { reflection_[node.pos][node.offset] = value; },
186 [
this, value](pos_t pos) { reflection_[pos].fill(value); }, propagate);
189 Node setReflection(Code code,
Reflection value,
bool propagate =
true)
191 return derived().apply(
192 code, [
this, value](Index node) { reflection_[node.pos][node.offset] = value; },
193 [
this, value](pos_t pos) { reflection_[pos].fill(value); }, propagate);
196 Node setReflection(Key key,
Reflection value,
bool propagate =
true)
198 return setReflection(derived().toCode(key), value, propagate);
201 Node setReflection(Point coord,
Reflection value,
bool propagate =
true,
204 return setReflection(derived().toCode(coord, depth), value, propagate);
211 void setHits(Index node, count_t value)
213 return derived().apply(
215 [
this, value](Index node) { reflection_[node.pos][node.offset].hits = value; },
216 [
this, value](pos_t pos) {
217 for (
auto& r : reflection_[pos]) {
223 Node setHits(Node node, count_t value,
bool propagate =
true)
225 return derived().apply(
227 [
this, value](Index node) { reflection_[node.pos][node.offset].hits = value; },
228 [
this, value](pos_t pos) {
229 for (
auto& r : reflection_[pos]) {
236 Node setHits(Code code, count_t value,
bool propagate =
true)
238 return derived().apply(
240 [
this, value](Index node) { reflection_[node.pos][node.offset].hits = value; },
241 [
this, value](pos_t pos) {
242 for (
auto& r : reflection_[pos]) {
249 Node setHits(Key key, count_t value,
bool propagate =
true)
251 return setHits(derived().toCode(key), value, propagate);
254 Node setHits(Point coord, count_t value,
bool propagate =
true, depth_t depth = 0)
256 return setHits(derived().toCode(coord, depth), value, propagate);
263 void setMisses(Index node, count_t value)
265 return derived().apply(
267 [
this, value](Index node) { reflection_[node.pos][node.offset].misses = value; },
268 [
this, value](pos_t pos) {
269 for (
auto& r : reflection_[pos]) {
275 Node setMisses(Node node, count_t value,
bool propagate =
true)
277 return derived().apply(
279 [
this, value](Index node) { reflection_[node.pos][node.offset].misses = value; },
280 [
this, value](pos_t pos) {
281 for (
auto& r : reflection_[pos]) {
288 Node setMisses(Code code, count_t value,
bool propagate =
true)
290 return derived().apply(
292 [
this, value](Index node) { reflection_[node.pos][node.offset].misses = value; },
293 [
this, value](pos_t pos) {
294 for (
auto& r : reflection_[pos]) {
301 Node setMisses(Key key, count_t value,
bool propagate =
true)
303 return setMisses(derived().toCode(key), value, propagate);
306 Node setMisses(Point coord, count_t value,
bool propagate =
true, depth_t depth = 0)
308 return setMisses(derived().toCode(coord, depth), value, propagate);
315 void updateReflection(Index node,
int hits_change,
int misses_change)
319 [
this, hits_change, misses_change](Index node) {
320 reflection_[node.pos][node.offset].hits += hits_change;
321 reflection_[node.pos][node.offset].misses += misses_change;
323 [
this, hits_change, misses_change](pos_t pos) {
324 for (
auto& e : reflection_[pos]) {
325 e.hits += hits_change;
326 e.misses += misses_change;
331 template <
class UnaryOp,
332 std::enable_if_t<std::is_invocable_v<UnaryOp, Reflection>,
bool> =
true>
333 void updateReflection(Index node, UnaryOp unary_op)
337 [
this, unary_op](Index node) {
338 reflection_[node.pos][node.offset] =
339 unary_op(reflection_[node.pos][node.offset]);
341 [
this, unary_op](pos_t pos) {
342 for (
auto& e : reflection_[pos]) {
350 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, Reflection>,
bool> =
true>
351 void updateReflection(Index node, BinaryOp binary_op)
355 [
this, binary_op](Index node) {
356 reflection_[node.pos][node.offset] =
357 binary_op(node, reflection_[node.pos][node.offset]);
359 [
this, binary_op](pos_t pos) {
361 for (
auto& e : reflection_[pos]) {
362 e = binary_op(Index(pos, i++), e);
367 Node updateReflection(Node node,
int hits_change,
int misses_change,
368 bool propagate =
true)
370 return derived().apply(
372 [
this, hits_change, misses_change](Index node) {
373 reflection_[node.pos][node.offset].hits += hits_change;
374 reflection_[node.pos][node.offset].misses += misses_change;
376 [
this, hits_change, misses_change](pos_t pos) {
377 for (
auto& e : reflection_[pos]) {
378 e.hits += hits_change;
379 e.misses += misses_change;
385 template <
class UnaryOp,
386 std::enable_if_t<std::is_invocable_v<UnaryOp, Reflection>,
bool> =
true>
387 Node updateReflection(Node node, UnaryOp unary_op,
bool propagate =
true)
389 return derived().apply(
391 [
this, unary_op](Index node) {
392 reflection_[node.pos][node.offset] =
393 unary_op(reflection_[node.pos][node.offset]);
395 [
this, unary_op](pos_t pos) {
396 for (
auto& e : reflection_[pos]) {
405 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, Reflection>,
bool> =
true>
406 Node updateReflection(Node node, BinaryOp binary_op,
bool propagate =
true)
408 return derived().apply(
410 [
this, binary_op](Index node) {
411 reflection_[node.pos][node.offset] =
412 binary_op(node, reflection_[node.pos][node.offset]);
414 [
this, binary_op](pos_t pos) {
416 for (
auto& e : reflection_[pos]) {
417 e = binary_op(Index(pos, i++), e);
423 Node updateReflection(Code code,
int hits_change,
int misses_change,
424 bool propagate =
true)
426 return derived().apply(
428 [
this, hits_change, misses_change](Index node) {
429 reflection_[node.pos][node.offset].hits += hits_change;
430 reflection_[node.pos][node.offset].misses += misses_change;
432 [
this, hits_change, misses_change](pos_t pos) {
433 for (
auto& e : reflection_[pos]) {
434 e.hits += hits_change;
435 e.misses += misses_change;
441 template <
class UnaryOp,
442 std::enable_if_t<std::is_invocable_v<UnaryOp, Reflection>,
bool> =
true>
443 Node updateReflection(Code code, UnaryOp unary_op,
bool propagate =
true)
445 return derived().apply(
447 [
this, unary_op](Index node) {
448 reflection_[node.pos][node.offset] =
449 unary_op(reflection_[node.pos][node.offset]);
451 [
this, unary_op](pos_t pos) {
452 for (
auto& e : reflection_[pos]) {
461 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, Reflection>,
bool> =
true>
462 Node updateReflection(Code code, BinaryOp binary_op,
bool propagate =
true)
464 return derived().apply(
466 [
this, binary_op](Index node) {
467 reflection_[node.pos][node.offset] =
468 binary_op(node, reflection_[node.pos][node.offset]);
470 [
this, binary_op](pos_t pos) {
472 for (
auto& e : reflection_[pos]) {
473 e = binary_op(Index(pos, i++), e);
479 Node updateReflection(Key key,
int hits_change,
int misses_change,
480 bool propagate =
true)
482 return updateReflection(derived().toCode(key), hits_change, misses_change, propagate);
485 template <
class UnaryOp,
486 std::enable_if_t<std::is_invocable_v<UnaryOp, Reflection>,
bool> =
true>
487 Node updateReflection(Key key, UnaryOp unary_op,
bool propagate =
true)
489 return updateReflection(derived().toCode(key), unary_op, propagate);
494 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, Reflection>,
bool> =
true>
495 Node updateReflection(Key key, BinaryOp binary_op,
bool propagate =
true)
497 return updateReflection(derived().toCode(key), binary_op, propagate);
500 Node updateReflection(Point coord,
int hits_change,
int misses_change,
501 bool propagate =
true, depth_t depth = 0)
503 return updateReflection(derived().toCode(coord, depth), hits_change, misses_change,
507 template <
class UnaryOp,
508 std::enable_if_t<std::is_invocable_v<UnaryOp, Reflection>,
bool> =
true>
509 Node updateReflection(Point coord, UnaryOp unary_op,
bool propagate =
true,
512 return updateReflection(derived().toCode(coord, depth), unary_op, propagate);
517 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, Reflection>,
bool> =
true>
518 Node updateReflection(Point coord, BinaryOp binary_op,
bool propagate =
true,
521 return updateReflection(derived().toCode(coord, depth), binary_op, propagate);
528 [[nodiscard]]
constexpr PropagationCriteria reflectionPropagationCriteria()
531 return prop_criteria_;
534 constexpr void setReflectionPropagationCriteria(PropagationCriteria prop_criteria,
535 bool propagate =
true)
noexcept
537 if (prop_criteria_ == prop_criteria) {
541 prop_criteria_ = prop_criteria;
543 derived().setModified();
546 derived().propagateModified();
561 template <
class Derived2>
563 : reflection_(other.reflection_), prop_criteria_(other.prop_criteria_)
567 template <
class Derived2>
569 : reflection_(std::move(other.reflection_))
570 , prop_criteria_(std::move(other.prop_criteria_))
588 template <
class Derived2>
592 reflection_ = rhs.reflection_;
593 prop_criteria_ = rhs.prop_criteria_;
597 template <
class Derived2>
601 reflection_ = std::move(rhs.reflection_);
602 prop_criteria_ = std::move(rhs.prop_criteria_);
612 std::swap(reflection_, other.reflection_);
613 std::swap(prop_criteria_, other.prop_criteria_);
620 [[nodiscard]]
constexpr Derived& derived() {
return *
static_cast<Derived*
>(
this); }
622 [[nodiscard]]
constexpr Derived
const& derived()
const
624 return *
static_cast<Derived const*
>(
this);
631 void createBlock(Index node)
633 reflection_.emplace_back();
634 reflection_.back().fill(reflection_[node.pos][node.offset]);
641 void resize(std::size_t count)
644 reflection_.resize(count);
651 void reserveImpl(std::size_t new_cap) { reflection_.reserve(new_cap); }
659 auto node = derived().rootIndex();
660 reflection_[node.pos][node.offset] = {0, 0};
667 void fill(Index node, pos_t children)
669 reflection_[children].fill(reflection_[node.pos][node.offset]);
676 void clearImpl() { reflection_.resize(1); }
678 void clearImpl(pos_t) {}
684 void updateBlock(pos_t block, std::array<bool, N> modified_parent)
686 for (offset_t i{}; N != i; ++i) {
687 if (modified_parent[i]) {
688 Index node(block, i);
689 updateNode(node, derived().children(node));
694 void updateNode(Index node, pos_t children)
698 switch (reflectionPropagationCriteria()) {
699 case PropagationCriteria::MIN:
700 reflection_[node.pos][node.offset] = min(children);
702 case PropagationCriteria::MAX:
703 reflection_[node.pos][node.offset] = max(children);
705 case PropagationCriteria::MEAN:
706 reflection_[node.pos][node.offset] = mean(children);
708 case PropagationCriteria::NONE:
return;
712 [[nodiscard]]
constexpr Reflection min(pos_t block)
const
714 Reflection res(std::numeric_limits<count_t>::max(),
715 std::numeric_limits<count_t>::max());
716 for (
auto r : reflection_[block]) {
717 res.hits = std::min(res.hits, r.hits);
718 res.misses = std::min(res.misses, r.misses);
723 [[nodiscard]]
constexpr Reflection max(pos_t block)
const
725 Reflection res(std::numeric_limits<count_t>::lowest(),
726 std::numeric_limits<count_t>::lowest());
727 for (
auto r : reflection_[block]) {
728 res.hits = std::max(res.hits, r.hits);
729 res.misses = std::max(res.misses, r.misses);
734 [[nodiscard]]
constexpr Reflection mean(pos_t block)
const
736 count_t hits{}, misses{};
737 for (
auto r : reflection_[block]) {
741 return Reflection(hits /
static_cast<count_t
>(N), misses /
static_cast<count_t
>(N));
748 [[nodiscard]]
bool isPrunable(pos_t block)
const
751 return std::all_of(std::cbegin(reflection_[block]) + 1, std::cend(reflection_[block]),
752 [
a = reflection_[block].front()](
auto b) {
return a ==
b; });
755 void preparePrune(Index node) {}
761 [[nodiscard]]
static constexpr std::size_t sizeofNodeTimesN(Index)
noexcept
763 return sizeofBlockLowerBound();
766 [[nodiscard]]
static constexpr std::size_t sizeofBlock(pos_t)
noexcept
768 return sizeofBlockLowerBound();
771 [[nodiscard]]
static constexpr std::size_t sizeofBlockLowerBound()
noexcept
773 return sizeof(
typename decltype(reflection_)::value_type);
776 [[nodiscard]]
static constexpr std::size_t sizeofMap()
noexcept
778 return sizeof(reflection_) +
sizeof(prop_criteria_);
785 [[nodiscard]]
static constexpr MapType mapType()
noexcept
787 return MapType::REFLECTION;
790 [[nodiscard]]
static constexpr std::size_t serializedSizeBlock()
noexcept
792 return sizeof(
typename decltype(reflection_)::value_type);
795 template <
class Container>
796 constexpr std::size_t serializedSize(Container
const& c)
const
798 return c.size() * serializedSizeBlock();
801 template <
class Container>
802 void readNodes(
ReadBuffer& in, Container
const& c)
804 for (
auto const [pos, offsets] : c) {
806 in.read(reflection_[pos].data(), serializedSizeBlock());
808 DataBlock<reflection_t, N> reflection;
809 in.read(reflection.data(), serializedSizeBlock());
810 for (offset_t i{}; N != i; ++i) {
811 reflection_[pos][i] = offsets[i] ? reflection[i] : reflection_[pos][i];
817 template <
class BlockRange>
818 void writeBlocks(
WriteBuffer& out, BlockRange
const& blocks)
const
820 for (
auto block : blocks) {
821 out.write(reflection_[block].data(), serializedSizeBlock());
829 void dotFileInfo(std::ostream& out, Index node)
const
831 out << reflection_[node.pos][node.offset];
836 Container<ReflectionBlock> reflection_;
839 PropagationCriteria prop_criteria_ = PropagationCriteria::MAX;
841 template <
class Derived2, offset_t N2,
class Index2,
class Node2,
class Code2,