<commit_before>#pragma once
#include <string>
#include <algorithm>

#include "augs/log.h"
#include "augs/math/vec2.h"
#include "augs/templates/container_templates.h"
#include "augs/misc/timing/timer.h"

namespace augs {
	template <class derived, class T = double>
	class measurements {
	protected:
		std::size_t measurement_index = 0;

		T last_average = static_cast<T>(1);
		T last_minimum = static_cast<T>(1);
		T last_maximum = static_cast<T>(1);
		T last_measurement = static_cast<T>(1);

		bool measured = false;

	public:
		std::wstring title = L"Untitled";
		std::vector<T> tracked;

		measurements(const std::size_t tracked_count = 20u) {
			tracked.resize(tracked_count, 0);
		}

		void measure(const T value) {
			measured = true;
			last_measurement = value;

			tracked[measurement_index] = last_measurement;
			++measurement_index;
			measurement_index %= tracked.size();

			T avg = 0;

			for (auto v : tracked) {
				avg += v;
			}

			last_average = avg / tracked.size();
			last_maximum = maximum_of(tracked);
			last_minimum = minimum_of(tracked);
		}

		std::wstring summary() const {
			if (!was_measured()) {
				return {};
			}

			const auto& self = *static_cast<const derived*>(this);
			return self.summary_impl();
		}

		bool operator<(const measurements& b) const {
			return get_average_units() < b.get_average_units();
		}

		bool operator>(const measurements& b) const {
			return get_average_units() > b.get_average_units();
		}

		T get_average_units() const {
			return last_average;
		}

		T get_maximum_units() const {
			return last_maximum;
		}

		T get_minimum_units() const {
			return last_minimum;
		}

		T get_last_measurement_units() const {
			return last_measurement;
		}

		bool was_measured() const {
			return measured;
		}
	};

	template <class T>
	class amount_measurements : public measurements<amount_measurements<T>, T> {
		using base = measurements<amount_measurements<T>, T>;
		friend class base;

		auto summary_impl() const {
			return typesafe_sprintf(L"%x: %f2\n", base::title, base::get_average_units());
		}

	public:
		using base::operator<;
		using base::base;
	};

	class time_measurements : public measurements<time_measurements, double> {
		timer tm;

		using base = measurements<time_measurements, double>;
		friend class base;

		auto summary_impl() const {
			const auto avg_secs = get_average_units();
			const bool division_by_secs_safe = std::abs(avg_secs) > AUGS_EPSILON<double>;

			if (division_by_secs_safe) {
				return typesafe_sprintf(
					L"%x: %f2 ms (%f2 FPS)\n", 
					title,
					avg_secs * 1000,
					1 / avg_secs
				);
			}
			else {
				return typesafe_sprintf(
					L"%x: %f2 ms\n", 
					title,
					avg_secs * 1000
				);
			}
		}

		using base::measure;

	public:
		using base::operator<;
		using base::base;

		void start() {
			tm.reset();
		}

		void stop() {
			measure(tm.get<std::chrono::seconds>());
		}
	};
}
<commit_msg>#249 fix friend declarations<commit_after>#pragma once
#include <string>
#include <algorithm>

#include "augs/log.h"
#include "augs/math/vec2.h"
#include "augs/templates/container_templates.h"
#include "augs/misc/timing/timer.h"

namespace augs {
	template <class derived, class T = double>
	class measurements {
	protected:
		std::size_t measurement_index = 0;

		T last_average = static_cast<T>(1);
		T last_minimum = static_cast<T>(1);
		T last_maximum = static_cast<T>(1);
		T last_measurement = static_cast<T>(1);

		bool measured = false;

	public:
		std::wstring title = L"Untitled";
		std::vector<T> tracked;

		measurements(const std::size_t tracked_count = 20u) {
			tracked.resize(tracked_count, 0);
		}

		void measure(const T value) {
			measured = true;
			last_measurement = value;

			tracked[measurement_index] = last_measurement;
			++measurement_index;
			measurement_index %= tracked.size();

			T avg = 0;

			for (auto v : tracked) {
				avg += v;
			}

			last_average = avg / tracked.size();
			last_maximum = maximum_of(tracked);
			last_minimum = minimum_of(tracked);
		}

		std::wstring summary() const {
			if (!was_measured()) {
				return {};
			}

			const auto& self = *static_cast<const derived*>(this);
			return self.summary_impl();
		}

		bool operator<(const measurements& b) const {
			return get_average_units() < b.get_average_units();
		}

		bool operator>(const measurements& b) const {
			return get_average_units() > b.get_average_units();
		}

		T get_average_units() const {
			return last_average;
		}

		T get_maximum_units() const {
			return last_maximum;
		}

		T get_minimum_units() const {
			return last_minimum;
		}

		T get_last_measurement_units() const {
			return last_measurement;
		}

		bool was_measured() const {
			return measured;
		}
	};

	template <class T>
	class amount_measurements : public measurements<amount_measurements<T>, T> {
		using base = measurements<amount_measurements<T>, T>;
		friend base;

		auto summary_impl() const {
			return typesafe_sprintf(L"%x: %f2\n", base::title, base::get_average_units());
		}

	public:
		using base::operator<;
		using base::base;
	};

	class time_measurements : public measurements<time_measurements, double> {
		timer tm;

		using base = measurements<time_measurements, double>;
		friend base;

		auto summary_impl() const {
			const auto avg_secs = get_average_units();
			const bool division_by_secs_safe = std::abs(avg_secs) > AUGS_EPSILON<double>;

			if (division_by_secs_safe) {
				return typesafe_sprintf(
					L"%x: %f2 ms (%f2 FPS)\n", 
					title,
					avg_secs * 1000,
					1 / avg_secs
				);
			}
			else {
				return typesafe_sprintf(
					L"%x: %f2 ms\n", 
					title,
					avg_secs * 1000
				);
			}
		}

		using base::measure;

	public:
		using base::operator<;
		using base::base;

		void start() {
			tm.reset();
		}

		void stop() {
			measure(tm.get<std::chrono::seconds>());
		}
	};
}

{'fraction_non_alphanumeric': 0.12737220037613267, 'fraction_numerical': 0.008377500427423492, 'mean_word_length': 3.6725239616613417, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 45, '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': '7561635', 'n_tokens_mistral': 2504, 'n_tokens_neox': 2048, 'n_words': 457}