#include "Timeline_Stream.h" #include #include #include namespace renderive { int Timeline_Stream_Snapshot::upper() const { return lower + time_point_size - 1; } bool Timeline_Stream_Snapshot::coord_by_stream_tick(int stream_tick, int& coord) const { if (times.empty()) return false; if (stream_tick < lower_stream_tick || stream_tick > upper_stream_tick) return false; int count = static_cast(times.size()); if (start_coord_to_end_coord) coord = lower + (upper_stream_tick - stream_tick); else coord = lower + (time_point_size - count) + (stream_tick - lower_stream_tick); return coord >= lower && coord <= upper(); } Time_Of_Day Timeline_Stream_Snapshot::time_by_tick(int tick) const { int offset = tick - lower; int count = static_cast(times.size()); int index = start_coord_to_end_coord ? count - 1 - offset : offset - (time_point_size - count); if (index < 0 || index >= count) return {}; return times[static_cast(index)]; } Timeline_Stream::Timeline_Stream() = default; int Timeline_Stream::push_time(Time_Of_Day time) { int tick = next_tick_value.fetch_add(1, std::memory_order_acq_rel); if (tick == std::numeric_limits::max()) { int expected = std::numeric_limits::min(); next_tick_value.compare_exchange_strong(expected, 1, std::memory_order_acq_rel, std::memory_order_acquire); tick = 0; } std::uint64_t sequence = write_sequence.fetch_add(1, std::memory_order_acq_rel); auto sample = std::make_shared(Sample{sequence, tick, time}); time_slots[sequence % Max_Buffered_Time_Count].store(std::move(sample), std::memory_order_release); return tick; } Timeline_Stream_Snapshot Timeline_Stream::capture(int time_point_size, int tick_space, bool start_coord_to_end_coord) const { time_point_size = std::max(1, time_point_size); tick_space = std::max(1, tick_space); Timeline_Stream_Snapshot snapshot; std::uint64_t write = write_sequence.load(std::memory_order_acquire); snapshot.version = write + 1; snapshot.start_coord_to_end_coord = start_coord_to_end_coord; snapshot.time_point_size = time_point_size; if (write == 0) { snapshot.lower = 0; return snapshot; } std::uint64_t available = std::min(write, Max_Buffered_Time_Count); std::uint64_t count = std::min(static_cast(time_point_size), available); std::uint64_t first_sequence = write - count; std::pmr::vector samples; samples.reserve(static_cast(count)); for (std::uint64_t sequence = first_sequence; sequence < write; ++sequence) { auto sample = time_slots[sequence % Max_Buffered_Time_Count].load(std::memory_order_acquire); if (sample && sample->sequence == sequence) samples.push_back(*sample); } if (samples.empty()) { snapshot.lower = 0; return snapshot; } snapshot.lower_stream_tick = samples.front().tick; snapshot.upper_stream_tick = samples.back().tick; snapshot.lower = snapshot.upper_stream_tick - time_point_size + 1; snapshot.times.reserve(samples.size()); for (const auto& sample : samples) snapshot.times.push_back(sample.time); snapshot.ticks.reserve(samples.size() / static_cast(tick_space) + 1); for (const auto& sample : samples) { int coord{}; if ((tick_space == 1 || sample.tick % tick_space == 0) && snapshot.coord_by_stream_tick(sample.tick, coord)) snapshot.ticks.push_back({sample.time, coord}); } std::sort(snapshot.ticks.begin(), snapshot.ticks.end(), [](const Timeline_Tick& left, const Timeline_Tick& right) { return left.tick < right.tick; }); return snapshot; } }