Line data Source code
1 : #pragma once
2 :
3 : #include <jage/engine/concurrency/double_buffer.hpp>
4 : #include <jage/engine/memory/cacheline_size.hpp>
5 : #include <jage/engine/memory/cacheline_slot.hpp>
6 : #include <jage/engine/time/cache_match_status.hpp>
7 :
8 : #include <jage/engine/time/internal/concepts/cache_snapshot.hpp>
9 :
10 : #include <array>
11 : #include <atomic>
12 : #include <cstdint>
13 : #include <utility>
14 :
15 : namespace jage::engine::time::internal {
16 : template <std::uint64_t Capacity, internal::concepts::cache_snapshot TSnapshot,
17 : template <class, template <class> class> class TBuffer,
18 : template <class> class TAtomic>
19 : class snapshot_cache {
20 : alignas(memory::cacheline_size) std::array<
21 : memory::cacheline_slot<TBuffer<TSnapshot, TAtomic>>, Capacity> buffer_{};
22 : alignas(memory::cacheline_size) TAtomic<std::uint64_t> write_index_{0UZ};
23 :
24 : public:
25 : [[nodiscard]] constexpr auto capacity() const noexcept -> std::uint64_t {
26 : return Capacity;
27 : }
28 :
29 : auto
30 26 : push(const internal::concepts::cache_snapshot auto &input_snapshot) -> void {
31 26 : const auto write_index = write_index_.load(std::memory_order::acquire);
32 26 : buffer_[write_index % Capacity].write(input_snapshot);
33 26 : write_index_.store(write_index + 1, std::memory_order::release);
34 26 : }
35 :
36 8 : [[nodiscard]] auto find(const typename TSnapshot::duration &event_real_time)
37 : -> std::pair<TSnapshot, cache_match_status> {
38 8 : const auto write_index = write_index_.load(std::memory_order::acquire);
39 8 : const auto newest_index = (write_index + Capacity - 1UZ) % Capacity;
40 :
41 20 : for (auto offset = 0UZ; offset < Capacity; ++offset) {
42 18 : const auto index = (newest_index + Capacity - offset) % Capacity;
43 18 : const auto snap = buffer_[index].read();
44 18 : if (event_real_time >= snap.real_time) {
45 : return {
46 : snap,
47 6 : cache_match_status::matched,
48 6 : };
49 : }
50 : }
51 :
52 : return {
53 2 : buffer_[write_index % Capacity].read(),
54 2 : cache_match_status::evicted,
55 2 : };
56 : }
57 :
58 7 : [[nodiscard]] auto find(const std::uint64_t frame_index)
59 : -> std::pair<TSnapshot, cache_match_status> {
60 7 : const auto write_index = write_index_.load(std::memory_order::acquire);
61 7 : const auto newest_index = (write_index + Capacity - 1UZ) % Capacity;
62 7 : const auto oldest_index = write_index % Capacity;
63 :
64 7 : if (const auto newest_snap = buffer_[newest_index].read();
65 7 : newest_snap.frame < frame_index) [[unlikely]] {
66 1 : return {newest_snap, cache_match_status::ahead};
67 6 : } else if (const auto oldest_snap = buffer_[oldest_index].read();
68 6 : oldest_snap.frame > frame_index) [[unlikely]] {
69 1 : return {oldest_snap, cache_match_status::evicted};
70 : }
71 : return {
72 5 : buffer_[frame_index % Capacity].read(),
73 5 : cache_match_status::matched,
74 5 : };
75 : }
76 : };
77 : } // namespace jage::engine::time::internal
|