<commit_before>#pragma once
#include "augs/templates/snapshotted_player.h"

namespace augs {
	template <class A, class B>
	auto snapshotted_player<A, B>::get_current_step() const {
		return current_step;
	}

	template <class A, class B>
	auto snapshotted_player<A, B>::get_total_steps() const {
		if (step_to_entropy.size() > 0) {
			return std::max(current_step, (*step_to_entropy.rbegin()).first);
		}

		return current_step;
	}

	template <class A, class B>
	void snapshotted_player<A, B>::begin_replaying() {
		advance_mode = advance_type::REPLAYING;
	}

	template <class A, class B>
	void snapshotted_player<A, B>::begin_recording() {
		advance_mode = advance_type::RECORDING;
	}

	template <class A, class B>
	const fixed_delta_timer& snapshotted_player<A, B>::get_timer() const { 
		return timer;
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::finish() {
		step_to_entropy.clear();
		current_step = 0;

		pause();
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::pause() {
		advance_mode = advance_type::PAUSED;
	}

	template <class A, class B>
   	bool snapshotted_player<A, B>::is_paused() const {
		return advance_mode == advance_type::PAUSED;
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::request_steps(const int amount) {
		additional_steps += amount;
	}

	template <class A, class B>
	double snapshotted_player<A, B>::get_speed() const {
		return is_paused() ? 0.0 : speed;
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::set_speed(const double new_speed) {
		speed = new_speed;
	}

	template <class A, class B>
	template <class I, class SetSnapshot>
	void snapshotted_player<A, B>::seek_to(
		typename snapshotted_player<A, B>::step_type seeked_step,
		const I& input,
		SetSnapshot&& set_snapshot
	) {
		auto set = [&](const auto i) {
			set_snapshot(i, snapshots.at(i));
			current_step = i * snapshot_frequency_in_steps;
		};

		const auto seeked_adj_snapshot = std::min(
			static_cast<unsigned>(snapshots.size() - 1),
			seeked_step / snapshot_frequency_in_steps
		);

		if (seeked_step < current_step) {
			set(seeked_adj_snapshot);
		}

		/* At this point the current step is <= than the target step. */

		{
			/* Maybe we can speed up the forward seek by setting some future snapshot. */

			const auto step_of_adj_snapshot = seeked_adj_snapshot * snapshot_frequency_in_steps;

			const auto distance_from_adj_snapshot = seeked_step - step_of_adj_snapshot;
			const auto distance_from_seeked_step = seeked_step - current_step;

			if (distance_from_adj_snapshot < distance_from_seeked_step) {
				set(seeked_adj_snapshot);
			}
		}

		/* Advance how much is needed from the time of the set snapshot. */

		while (current_step < seeked_step) {
			advance_single_step(input);
		}
	}

	template <class A, class B>
	template <class MakeSnapshot>
	void snapshotted_player<A, B>::push_snapshot_if_needed(MakeSnapshot&& make_snapshot) {
		if (current_step % snapshot_frequency_in_steps == 0) {
			const auto snapshot_index = current_step / snapshot_frequency_in_steps;

			const bool valid_snapshot_exists = snapshot_index < snapshots.size();

			if (!valid_snapshot_exists) {
				snapshots.emplace_back(make_snapshot(snapshot_index));
			}
		}
	}

	template <class entropy_type, class B>
	template <class I>
	void snapshotted_player<entropy_type, B>::advance_single_step(const I& in) {
		auto& step_i = current_step;
		auto& applied_entropy = in.total_collected;

		push_snapshot_if_needed(in.make_snapshot);

		{
			const auto next_snapshot_index = 1 + step_i / snapshot_frequency_in_steps;
			const bool outdated_snapshots_to_delete_exist = next_snapshot_index < snapshots.size();

			if (outdated_snapshots_to_delete_exist) {
				snapshots.erase(
					snapshots.begin() + next_snapshot_index,
					snapshots.end()
				);
			}
		}
		
		switch (advance_mode) {
			case advance_type::REPLAYING:
				if (const auto found_entropy = mapped_or_nullptr(step_to_entropy, step_i)) {
					applied_entropy = *found_entropy;
				}
				<commit_msg>Extensive logging for snapshotted_player for debugging<commit_after>#pragma once
#include "augs/templates/snapshotted_player.h"

#define LOG_PLAYER 1

template <class... Args>
void PLR_LOG(Args&&... args) {
#if LOG_PLAYER
	LOG(std::forward<Args>(args)...);
#else
	((void)args, ...);
#endif
}

#if LOG_PLAYER
#define PLR_LOG_NVPS LOG_NVPS
#else
#define PLR_LOG_NVPS PLR_LOG
#endif

namespace augs {
	template <class A, class B>
	auto snapshotted_player<A, B>::get_current_step() const {
		return current_step;
	}

	template <class A, class B>
	auto snapshotted_player<A, B>::get_total_steps() const {
		if (step_to_entropy.size() > 0) {
			return std::max(current_step, (*step_to_entropy.rbegin()).first);
		}

		return current_step;
	}

	template <class A, class B>
	void snapshotted_player<A, B>::begin_replaying() {
		advance_mode = advance_type::REPLAYING;
	}

	template <class A, class B>
	void snapshotted_player<A, B>::begin_recording() {
		advance_mode = advance_type::RECORDING;
	}

	template <class A, class B>
	const fixed_delta_timer& snapshotted_player<A, B>::get_timer() const { 
		return timer;
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::finish() {
		step_to_entropy.clear();
		current_step = 0;

		pause();
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::pause() {
		advance_mode = advance_type::PAUSED;
	}

	template <class A, class B>
   	bool snapshotted_player<A, B>::is_paused() const {
		return advance_mode == advance_type::PAUSED;
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::request_steps(const int amount) {
		additional_steps += amount;
	}

	template <class A, class B>
	double snapshotted_player<A, B>::get_speed() const {
		return is_paused() ? 0.0 : speed;
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::set_speed(const double new_speed) {
		speed = new_speed;
	}

	template <class A, class B>
	template <class I, class SetSnapshot>
	void snapshotted_player<A, B>::seek_to(
		typename snapshotted_player<A, B>::step_type seeked_step,
		const I& input,
		SetSnapshot&& set_snapshot
	) {
		auto set = [&](const auto i) {
			PLR_LOG("Set snapshot num %x (size: %x)", i, snapshots.size());

			set_snapshot(i, snapshots.at(i));
			current_step = i * snapshot_frequency_in_steps;

			PLR_LOG("New current step: %x", current_step);
		};

		const auto seeked_adj_snapshot = std::min(
			static_cast<unsigned>(snapshots.size() - 1),
			seeked_step / snapshot_frequency_in_steps
		);

		PLR_LOG("Seeking from %x to %x", current_step, seeked_step);
		PLR_LOG("Adjacent snapshot: #%x", seeked_adj_snapshot);

		if (seeked_step < current_step) {
			PLR_LOG("Seek backwards");
			set(seeked_adj_snapshot);
		}

		/* At this point the current step is <= than the target step. */

		{
			/* Maybe we can speed up the forward seek by setting some future snapshot. */

			const auto step_of_adj_snapshot = seeked_adj_snapshot * snapshot_frequency_in_steps;

			const auto distance_from_adj_snapshot = seeked_step - step_of_adj_snapshot;
			const auto distance_from_seeked_step = seeked_step - current_step;

			PLR_LOG_NVPS(
				step_of_adj_snapshot,
				distance_from_adj_snapshot,
				distance_from_seeked_step
			);

			if (distance_from_adj_snapshot < distance_from_seeked_step) {
				PLR_LOG("Speedup the forward seek");

				set(seeked_adj_snapshot);
			}
		}

		/* Advance how much is needed from the time of the set snapshot. */

		PLR_LOG("Advancing the rest from %x to %x.", current_step, seeked_step);

		while (current_step < seeked_step) {
			advance_single_step(input);
		}
	}

	template <class A, class B>
	template <class MakeSnapshot>
	void snapshotted_player<A, B>::push_snapshot_if_needed(MakeSnapshot&& make_snapshot) {
		if (current_step % snapshot_frequency_in_steps == 0) {
			const auto snapshot_index = current_step / snapshot_frequency_in_steps;

			const bool valid_snapshot_exists = snapshot_index < snapshots.size();

			if (!valid_snapshot_exists) {
				ensure_eq(snapshot_index, snapshots.size());

				PLR_LOG("Snapshot step: %x. Snapshot #%x pushed.", current_step, snapshot_index);
				snapshots.emplace_back(make_snapshot(snapshot_index));
			}
			else {
				PLR_LOG("Snapshot step: %x. Snapshot #%x exists.", current_step, snapshot_index);
			}
		}
	}

	template <class entropy_type, class B>
	template <class I>
	void snapshotted_player<entropy_type, B>::advance_single_step(const I& in) {
		auto& step_i = current_step;
		auto& applied_entropy = in.total_collected;

		push_snapshot_if_needed(in.make_snapshot);

		{
			const auto next_snapshot_index = 1 + step_i / snapshot_frequency_in_steps;
			const bool outdated_snapshots_to_delete_exist = next_snapshot_index < snapshots.size();

			if (outdated_snapshots_to_delete_exist) {
				snapshots.erase(
					snapshots.begin() + next_snapshot_index,
					snapshots.end()
				);
			}
		}
		
		switch (advance_mode) {
			case advance_type::REPLAYING:
				if (const auto found_entropy = mapped_or_nullptr(step_to_entropy, step_i)) {
					applied_entropy = *found_entropy;
				}
				
{'fraction_non_alphanumeric': 0.11040316379215644, 'fraction_numerical': 0.0016478084148083048, 'mean_word_length': 4.520921770770164, 'pattern_counts': {'":': 0, '<': 83, '<?xml version=': 0, '>': 73, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '515149', 'n_tokens_mistral': 3535, 'n_tokens_neox': 3210, 'n_words': 728}