From 7307815e99a79dac42f2a9c06b0fe6171ea11ba0 Mon Sep 17 00:00:00 2001
From: HampusM <hampus@hampusmat.com>
Date: Fri, 1 Jul 2022 16:01:04 +0200
Subject: refactor: use ranges

---
 src/CMakeLists.txt                 |   1 +
 src/engine/data/vector2.cpp        |  20 ++++++
 src/engine/data/vector2.hpp        |   5 ++
 src/game/RLE_reader.cpp            |  44 ++++++++------
 src/game/cell_helper.hpp           |   9 ++-
 src/game/cell_helper_impl.hpp      | 121 +++++++++++++++++++------------------
 src/game/components/statusline.cpp |  23 ++++---
 src/game/game.cpp                  |  86 ++++++++++++++------------
 src/game/game.hpp                  |   5 +-
 src/interfaces/cell_helper.hpp     |   5 +-
 src/util/algorithm.hpp             |  38 ------------
 src/util/algorithm_impl.hpp        |  67 --------------------
 src/util/ranges.hpp                |  47 --------------
 src/util/ranges_impl.hpp           |  59 ------------------
 14 files changed, 184 insertions(+), 346 deletions(-)
 delete mode 100644 src/util/algorithm.hpp
 delete mode 100644 src/util/algorithm_impl.hpp
 delete mode 100644 src/util/ranges.hpp
 delete mode 100644 src/util/ranges_impl.hpp

(limited to 'src')

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2a98dd7..147f0e0 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -64,6 +64,7 @@ target_link_libraries_system(
 	yacppdic
 	ctre
 	backward
+	range-v3
 )
 
 target_link_options(${PROJECT_NAME} PRIVATE -fsanitize=address)
diff --git a/src/engine/data/vector2.cpp b/src/engine/data/vector2.cpp
index 84986bd..80fc43c 100644
--- a/src/engine/data/vector2.cpp
+++ b/src/engine/data/vector2.cpp
@@ -82,11 +82,31 @@ auto Vector2::operator==(const Vector2 &rhs) const noexcept -> bool
 	return _x == rhs._x && _y == rhs._y;
 }
 
+auto Vector2::operator!=(const Vector2 &rhs) const noexcept -> bool
+{
+	return !(*this == rhs);
+}
+
 auto Vector2::operator<(const Vector2 &rhs) const noexcept -> bool
 {
 	return std::tie(_x, _y) < std::tie(rhs._x, rhs._y);
 }
 
+auto Vector2::operator>(const Vector2 &rhs) const noexcept -> bool
+{
+	return std::tie(_x, _y) > std::tie(rhs._x, rhs._y);
+}
+
+auto Vector2::operator<=(const Vector2 &rhs) const noexcept -> bool
+{
+	return *this < rhs || *this == rhs;
+}
+
+auto Vector2::operator>=(const Vector2 &rhs) const noexcept -> bool
+{
+	return *this > rhs || *this == rhs;
+}
+
 auto Vector2Hasher::operator()(const Vector2 &vector2) const noexcept -> std::size_t
 {
 	std::size_t result_hash = 0;
diff --git a/src/engine/data/vector2.hpp b/src/engine/data/vector2.hpp
index 03c2562..da96e72 100644
--- a/src/engine/data/vector2.hpp
+++ b/src/engine/data/vector2.hpp
@@ -43,8 +43,13 @@ public:
 	auto operator*(const Vector2 &rhs) const noexcept -> Vector2;
 
 	auto operator==(const Vector2 &rhs) const noexcept -> bool;
+	auto operator!=(const Vector2 &rhs) const noexcept -> bool;
 
 	auto operator<(const Vector2 &rhs) const noexcept -> bool;
+	auto operator>(const Vector2 &rhs) const noexcept -> bool;
+
+	auto operator<=(const Vector2 &rhs) const noexcept -> bool;
+	auto operator>=(const Vector2 &rhs) const noexcept -> bool;
 
 	/**
 	 *  Returns Vector2({.x = 0, .y = 1})
diff --git a/src/game/RLE_reader.cpp b/src/game/RLE_reader.cpp
index df2823c..79890f1 100644
--- a/src/game/RLE_reader.cpp
+++ b/src/game/RLE_reader.cpp
@@ -1,14 +1,19 @@
 #include "RLE_reader.hpp"
 
-#include <ctre.hpp>
 #include <cctype>
+#include <ctre.hpp>
+#include <range/v3/algorithm/find_if.hpp>
+#include <range/v3/algorithm/fold_left.hpp>
+#include <range/v3/range/conversion.hpp>
+#include <range/v3/view/drop.hpp>
+#include <range/v3/view/iota.hpp>
+#include <range/v3/view/join.hpp>
 #include <string>
 #include <vector>
 
 #include "engine/data/bounds.hpp"
 #include "engine/data/vector2.hpp"
 #include "errors/RLE_reader.hpp"
-#include "util/algorithm_impl.hpp"
 #include "util/io_impl.hpp"
 #include "util/string_impl.hpp"
 
@@ -32,15 +37,14 @@ auto RLEReader::read_RLE_file(const std::filesystem::path &path) const
 		content_lines.pop_back();
 	}
 
-	const auto header_line_iter = container_find(
+	const auto header_line_iter = ranges::find_if(
 		content_lines,
 		[](const std::string &line)
 		{
 			return ctre::starts_with<"x = \\d+, y = \\d+">(line);
-			// return ctre::match<"x = \\d+, y = \\d+(, rule = [a-zA-Z0-9/]+)?">(line);
 		});
 
-	if (header_line_iter == content_lines.end())
+	if (header_line_iter == ranges::end(content_lines))
 	{
 		throw InvalidRLEFileError(path, "No header line");
 	}
@@ -64,26 +68,28 @@ auto RLEReader::read_RLE_file(const std::filesystem::path &path) const
 
 	auto pattern_pos = Vector2({.x = 0, .y = 0});
 
-	const auto first_pattern_line_iter = header_line_iter + 1;
+	const auto header_line_index =
+		static_cast<int32_t>(header_line_iter - content_lines.begin());
 
-	for (auto pattern_line_iter = first_pattern_line_iter;
-		 pattern_line_iter != content_lines.end();
-		 ++pattern_line_iter)
+	const auto pattern_lines = content_lines |
+							   ranges::views::drop(header_line_index + 1) |
+							   ranges::to<std::vector>();
+
+	for (const auto &pattern_line : pattern_lines)
 	{
-		if (!ctre::match<"[bo$0-9!]+">(*pattern_line_iter))
+		if (!ctre::match<"[bo$0-9!]+">(pattern_line))
 		{
 			throw InvalidRLEFileError(path, "Invalid pattern line");
 		}
 	}
 
-	auto pattern = std::string();
-
-	for (auto pattern_line_iter = first_pattern_line_iter;
-		 pattern_line_iter != content_lines.end();
-		 ++pattern_line_iter)
-	{
-		pattern.append(*pattern_line_iter);
-	}
+	auto pattern = ranges::fold_left(
+		pattern_lines,
+		std::string(),
+		[](const std::string &acc, const std::string &line)
+		{
+			return acc + line;
+		});
 
 	auto run_count_str = std::string();
 
@@ -111,7 +117,7 @@ auto RLEReader::read_RLE_file(const std::filesystem::path &path) const
 			continue;
 		}
 
-		for (auto run_index = 0; run_index < run_count; run_index++)
+		for (const auto &run_index : ranges::views::iota(0, run_count))
 		{
 			if (pattern_size.validate_coords(pattern_pos) != CoordsValidation::VALID)
 			{
diff --git a/src/game/cell_helper.hpp b/src/game/cell_helper.hpp
index cf84a75..c54b12e 100644
--- a/src/game/cell_helper.hpp
+++ b/src/game/cell_helper.hpp
@@ -5,7 +5,6 @@
 
 #include "engine/data/vector2.hpp"
 
-#include <list>
 #include <memory>
 #include <vector>
 
@@ -19,17 +18,17 @@ public:
 		-> bool override;
 
 	[[nodiscard]] auto
-	get_birth_cell_positions(const std::list<Vector2> &cell_positions) const noexcept
-		-> std::list<Vector2> override;
+	get_birth_cell_positions(const std::vector<Vector2> &cell_positions) const noexcept
+		-> std::vector<Vector2> override;
 
 	[[nodiscard]] auto find_neighbours(const Vector2 &cell_pos) const noexcept
 		-> std::vector<Vector2> override;
 
 private:
-	std::shared_ptr<IMatrix<MatrixElement>> _matrix;
+	const std::shared_ptr<IMatrix<MatrixElement>> _matrix;
 
 	static auto _get_position_neighbours(const Vector2 &position) noexcept
-		-> std::list<Vector2>;
+		-> std::vector<Vector2>;
 };
 
 #include "cell_helper_impl.hpp"
diff --git a/src/game/cell_helper_impl.hpp b/src/game/cell_helper_impl.hpp
index bd40794..c03b80c 100644
--- a/src/game/cell_helper_impl.hpp
+++ b/src/game/cell_helper_impl.hpp
@@ -2,18 +2,15 @@
 
 #include "cell_helper.hpp"
 
-#include "util/algorithm.hpp"
-
-template <typename MatrixElement>
-constexpr auto has_matrix_value(
-	const std::shared_ptr<IMatrix<MatrixElement>> &matrix,
-	const MatrixElement &value) noexcept
-{
-	return [&matrix, &value](const Vector2 &pos)
-	{
-		return matrix->get(pos) == value;
-	};
-}
+#include <memory>
+#include <range/v3/action/insert.hpp>
+#include <range/v3/action/sort.hpp>
+#include <range/v3/action/unique.hpp>
+#include <range/v3/algorithm/count_if.hpp>
+#include <range/v3/algorithm/fold_left.hpp>
+#include <range/v3/range/conversion.hpp>
+#include <range/v3/view/filter.hpp>
+#include <utility>
 
 template <typename MatrixElement>
 CellHelper<MatrixElement>::CellHelper(
@@ -26,74 +23,82 @@ template <typename MatrixElement>
 auto CellHelper<MatrixElement>::is_cell_dying(const Vector2 &cell_pos) const noexcept
 	-> bool
 {
-	const auto neighbour_cell_positions =
-		container_filter(find_neighbours(cell_pos), has_matrix_value(_matrix, 'x'));
-
-	const auto neighbour_cell_cnt = neighbour_cell_positions.size();
+	int64_t neighbour_cell_cnt = ranges::count_if(
+		find_neighbours(cell_pos),
+		[this](const Vector2 &pos)
+		{
+			return _matrix->get(pos) == 'x';
+		});
 
 	return neighbour_cell_cnt < 2 || neighbour_cell_cnt >= 4;
 }
 
 template <typename MatrixElement>
 auto CellHelper<MatrixElement>::get_birth_cell_positions(
-	const std::list<Vector2> &cell_positions) const noexcept -> std::list<Vector2>
+	const std::vector<Vector2> &cell_positions) const noexcept -> std::vector<Vector2>
 {
-	auto all_empty_neighbour_positions = std::list<Vector2>();
-
-	for (const auto &cell_pos : cell_positions)
-	{
-		const std::vector<Vector2> empty_neighbour_positions =
-			container_filter(find_neighbours(cell_pos), has_matrix_value(_matrix, ' '));
-
-		all_empty_neighbour_positions.insert(
-			all_empty_neighbour_positions.end(),
-			empty_neighbour_positions.begin(),
-			empty_neighbour_positions.end());
-	}
-
-	// Remove duplicates
-	all_empty_neighbour_positions.sort();
-	all_empty_neighbour_positions.unique();
-
-	auto birth_cell_positions = container_filter(
-		all_empty_neighbour_positions,
-		[this](const Vector2 &cell_pos)
-		{
-			const auto neighbour_cell_positions = container_filter(
-				find_neighbours(cell_pos),
-				has_matrix_value(_matrix, 'x'));
-
-			return neighbour_cell_positions.size() == 3;
-		});
-
-	return birth_cell_positions;
+	std::vector<Vector2> empty_neighbour_positions =
+		ranges::fold_left(
+			cell_positions,
+			std::vector<Vector2>(),
+			[this](std::vector<Vector2> acc, const Vector2 &pos)
+			{
+				std::vector<Vector2> neighbours = find_neighbours(pos);
+
+				auto empty_neighbours =
+					neighbours | ranges::views::filter(
+									 [this](const Vector2 &neighbour_pos)
+									 {
+										 return _matrix->get(neighbour_pos) == ' ';
+									 });
+
+				ranges::actions::insert(acc, acc.end(), empty_neighbours);
+
+				return acc;
+			}) |
+		ranges::actions::sort | ranges::actions::unique;
+
+	auto birth_cell_positions = empty_neighbour_positions |
+								ranges::views::filter(
+									[this](const Vector2 &cell_pos)
+									{
+										auto neighbours = find_neighbours(cell_pos);
+
+										int64_t neighbour_cell_cnt = ranges::count_if(
+											neighbours,
+											[this](const Vector2 &neighbour_pos)
+											{
+												return _matrix->get(neighbour_pos) == 'x';
+											});
+
+										return neighbour_cell_cnt == 3;
+									});
+
+	return birth_cell_positions | ranges::to<std::vector>();
 }
 
 template <typename MatrixElement>
 auto CellHelper<MatrixElement>::find_neighbours(const Vector2 &cell_pos) const noexcept
 	-> std::vector<Vector2>
 {
-	std::vector<Vector2> cell_positions = {};
-
 	const auto matrix_size =
 		Bounds({.width = _matrix->get_column_cnt(), .height = _matrix->get_row_cnt()});
 
 	const auto neighbours = _get_position_neighbours(cell_pos);
 
-	for (const auto &neighbour_pos : neighbours)
-	{
-		if (matrix_size.validate_coords(neighbour_pos) == CoordsValidation::VALID)
-		{
-			cell_positions.push_back(neighbour_pos);
-		}
-	}
-
-	return cell_positions;
+	return neighbours |
+		   ranges::views::filter(
+			   [&matrix_size](const Vector2 &neighbour_pos)
+			   {
+				   return matrix_size.validate_coords(neighbour_pos) ==
+						  CoordsValidation::VALID;
+			   }) |
+		   ranges::to<std::vector>();
 }
 
 template <typename MatrixElement>
 auto CellHelper<MatrixElement>::_get_position_neighbours(const Vector2 &position) noexcept
-	-> std::list<Vector2>
+	-> std::vector<Vector2>
 {
 	return {
 		position + Vector2::up(),
diff --git a/src/game/components/statusline.cpp b/src/game/components/statusline.cpp
index aac1c27..8344c22 100644
--- a/src/game/components/statusline.cpp
+++ b/src/game/components/statusline.cpp
@@ -1,12 +1,11 @@
 #include "statusline.hpp"
 
 #include <fmt/color.h>
+#include <range/v3/view/iota.hpp>
 #include <utility>
 
 #include "engine/data/vector2.hpp"
 #include "interfaces/matrix.hpp"
-#include "util/ranges.hpp"
-#include "util/ranges_impl.hpp"
 
 StatusLine::StatusLine(std::shared_ptr<ComponentMatrix> component_matrix) noexcept
 	: _component_matrix(std::move(component_matrix)), _need_render(false)
@@ -55,7 +54,8 @@ void StatusLine::set_section_status(
 
 	auto pos = Vector2({.x = section_start + start, .y = 0});
 
-	const auto column_cnt = static_cast<std::int32_t>(_component_matrix->get_column_cnt());
+	const auto column_cnt =
+		static_cast<std::int32_t>(_component_matrix->get_column_cnt());
 
 	const auto section_length = _section_lengths[section];
 
@@ -73,7 +73,7 @@ void StatusLine::set_section_status(
 		_component_matrix->set(pos, {.value = ' ', .style = section_style});
 		padding_remaining--;
 
-		for (auto index : IotaView(0U, padding_remaining))
+		for (auto index : ranges::views::iota(0U, padding_remaining))
 		{
 			pos += Vector2::right();
 
@@ -103,11 +103,13 @@ void StatusLine::set_section_status(
 
 	_matrix_write_string(
 		pos,
-		status.substr(status_offset_start, static_cast<std::uint32_t>(final_status_length)));
+		status.substr(
+			status_offset_start,
+			static_cast<std::uint32_t>(final_status_length)));
 
 	pos = pos.to_direction(Vector2::right(), final_status_length);
 
-	for (auto index : IotaView(0U, section_style.padding_right))
+	for (auto index : ranges::views::iota(0U, section_style.padding_right))
 	{
 		_component_matrix->set(pos, {.value = ' '});
 
@@ -119,7 +121,9 @@ void StatusLine::set_section_status(
 	set_need_render(true);
 }
 
-void StatusLine::set_section_length(StatusLineSection section, std::int32_t length) noexcept
+void StatusLine::set_section_length(
+	StatusLineSection section,
+	std::int32_t length) noexcept
 {
 	_section_lengths[section] = length;
 }
@@ -143,7 +147,8 @@ void StatusLine::_matrix_write_string(
 	}
 }
 
-auto StatusLine::_get_section_start_x(StatusLineSection section) const noexcept -> std::int32_t
+auto StatusLine::_get_section_start_x(StatusLineSection section) const noexcept
+	-> std::int32_t
 {
 	std::int32_t section_start = 0;
 
@@ -169,7 +174,7 @@ void StatusLine::_clear_section(StatusLineSection section, std::int32_t start) n
 
 	auto section_length = _section_lengths[section];
 
-	for (auto index : IotaView(0, section_length - start))
+	for (auto index : ranges::views::iota(0, section_length - start))
 	{
 		_component_matrix->set(pos, ComponentElement({.value = ' '}));
 
diff --git a/src/game/game.cpp b/src/game/game.cpp
index a121089..86b6eac 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -1,20 +1,23 @@
 #include "game.hpp"
 
+#include <cstdlib>
+#include <filesystem>
 #include <fmt/color.h>
 #include <fmt/core.h>
 #include <fmt/format.h>
-#include <yacppdic/factory.hpp>
-#include <cstdlib>
-#include <filesystem>
 #include <iostream>
 #include <iterator>
+#include <range/v3/action/remove.hpp>
+#include <range/v3/algorithm/contains.hpp>
+#include <range/v3/range/conversion.hpp>
+#include <range/v3/view/filter.hpp>
 #include <stdexcept>
 #include <utility>
+#include <yacppdic/factory.hpp>
 
 #include "engine/data/bounds.hpp"
 #include "engine/escape.hpp"
 #include "engine/graphics/matrix_iterator.hpp"
-#include "engine/graphics/matrix_iterator_impl.hpp"
 #include "engine/keycodes.hpp"
 #include "errors/RLE_reader.hpp"
 #include "errors/io.hpp"
@@ -24,9 +27,8 @@
 #include "interfaces/input.hpp"
 #include "interfaces/matrix.hpp"
 #include "interfaces/status_manager.hpp"
-#include "util/algorithm_impl.hpp"
 #include "util/fs.hpp"
-#include "util/string_impl.hpp"
+#include "util/string.hpp"
 
 Game::Game(
 	IStatusLineFactory statusline_factory,
@@ -190,7 +192,7 @@ void Game::on_start()
 
 					 scene_matrix->set(col_pos, col);
 
-					 if (!container_has(_living_cell_positions, col_pos))
+					 if (!ranges::contains(_living_cell_positions, col_pos))
 					 {
 						 _living_cell_positions.push_back(col_pos);
 					 }
@@ -311,7 +313,7 @@ void Game::_on_normal_mode_update() noexcept
 		}
 
 		_set_space(matrix, position, ' ');
-		_living_cell_positions.remove(position);
+		std::erase(_living_cell_positions, position);
 		break;
 	}
 
@@ -390,38 +392,7 @@ void Game::_on_normal_mode_update() noexcept
 
 	_last_gen_update_time = time_now;
 
-	auto matrix = _scene->get_matrix();
-
-	const auto dying_cell_positions = container_filter(
-		_living_cell_positions,
-		[this](const Vector2 &cell_pos)
-		{
-			return _cell_helper->is_cell_dying(cell_pos);
-		});
-
-	auto birth_cell_positions =
-		_cell_helper->get_birth_cell_positions(_living_cell_positions);
-
-	for (const auto &dying_cell_pos : dying_cell_positions)
-	{
-		_set_space(matrix, dying_cell_pos, ' ');
-
-		const auto cell_found = container_find(_living_cell_positions, dying_cell_pos);
-
-		if (cell_found != _living_cell_positions.end())
-		{
-			_living_cell_positions.erase(cell_found);
-		}
-	}
-
-	for (const auto &birth_cell_pos : birth_cell_positions)
-	{
-		if (birth_cell_pos.get_y() >= _minimum_cursor_pos_y)
-		{
-			_set_space(matrix, birth_cell_pos, 'x');
-			_living_cell_positions.push_back(birth_cell_pos);
-		}
-	}
+	_process_next_generation();
 }
 
 void Game::_on_command_mode_update() noexcept
@@ -640,3 +611,38 @@ void Game::_erase_line_from_cursor() noexcept
 	std::cout.flush();
 }
 
+void Game::_process_next_generation() noexcept
+{
+	const auto dying_cell_positions =
+		_living_cell_positions |
+		ranges::views::filter(
+			[this](const Vector2 &cell_pos)
+			{
+				return _cell_helper->is_cell_dying(cell_pos);
+			}) |
+		ranges::to<std::vector>();
+
+	auto birth_cell_positions =
+		_cell_helper->get_birth_cell_positions(_living_cell_positions);
+
+	auto matrix = _scene->get_matrix();
+
+	for (const auto &dying_cell_pos : dying_cell_positions)
+	{
+		_set_space(matrix, dying_cell_pos, ' ');
+
+		if (ranges::contains(_living_cell_positions, dying_cell_pos))
+		{
+			ranges::actions::remove(_living_cell_positions, dying_cell_pos);
+		}
+	}
+
+	for (const auto &birth_cell_pos : birth_cell_positions)
+	{
+		if (birth_cell_pos.get_y() >= _minimum_cursor_pos_y)
+		{
+			_set_space(matrix, birth_cell_pos, 'x');
+			_living_cell_positions.push_back(birth_cell_pos);
+		}
+	}
+}
diff --git a/src/game/game.hpp b/src/game/game.hpp
index 13e229e..9fc5237 100644
--- a/src/game/game.hpp
+++ b/src/game/game.hpp
@@ -29,6 +29,7 @@ class IGenerationTracker;
 class IRLEReader;
 class IStatusManager;
 class IUserInputObserver;
+
 template <typename ElementType>
 class IMatrix;
 
@@ -107,7 +108,7 @@ private:
 
 	std::int64_t _generations_per_second = DEFAULT_GENERATIONS_PER_SECOND;
 
-	std::list<Vector2> _living_cell_positions;
+	std::vector<Vector2> _living_cell_positions;
 
 	void _on_normal_mode_update() noexcept;
 
@@ -129,4 +130,6 @@ private:
 	static void _erase_entire_line() noexcept;
 
 	static void _erase_line_from_cursor() noexcept;
+
+	void _process_next_generation() noexcept;
 };
diff --git a/src/interfaces/cell_helper.hpp b/src/interfaces/cell_helper.hpp
index 69bf8b0..38e214d 100644
--- a/src/interfaces/cell_helper.hpp
+++ b/src/interfaces/cell_helper.hpp
@@ -6,7 +6,6 @@
 
 #include <yacppdic/factory.hpp>
 
-#include <list>
 #include <memory>
 #include <vector>
 
@@ -20,8 +19,8 @@ public:
 		-> bool = 0;
 
 	[[nodiscard]] virtual auto
-	get_birth_cell_positions(const std::list<Vector2> &cell_positions) const noexcept
-		-> std::list<Vector2> = 0;
+	get_birth_cell_positions(const std::vector<Vector2> &cell_positions) const noexcept
+		-> std::vector<Vector2> = 0;
 
 	[[nodiscard]] virtual auto find_neighbours(const Vector2 &cell_pos) const noexcept
 		-> std::vector<Vector2> = 0;
diff --git a/src/util/algorithm.hpp b/src/util/algorithm.hpp
deleted file mode 100644
index 60c68e2..0000000
--- a/src/util/algorithm.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma once
-
-#include "util/concepts.hpp"
-
-#include <concepts>
-
-template <typename ContainerType, typename Value>
-requires Container<ContainerType>
-constexpr auto container_find(const ContainerType &container, const Value &value) noexcept
-	-> typename ContainerType::const_iterator;
-
-template <typename ContainerType, typename Predicate>
-requires Container<ContainerType> &&
-	std::predicate<Predicate, typename ContainerType::value_type>
-constexpr auto
-container_find(const ContainerType &container, Predicate predicate) noexcept ->
-	typename ContainerType::const_iterator;
-
-template <typename ContainerType, typename Value>
-requires Container<ContainerType>
-constexpr auto container_has(const ContainerType &container, const Value &value) noexcept
-	-> bool;
-
-template <typename ContainerType, typename Predicate>
-requires Container<ContainerType> && HasPushBack<ContainerType> &&
-	std::predicate<Predicate, typename ContainerType::value_type>
-constexpr auto
-container_filter(const ContainerType &container, Predicate predicate) noexcept
-	-> ContainerType;
-
-template <typename ContainerType, typename Predicate>
-requires Container<ContainerType> &&
-	std::predicate<Predicate, typename ContainerType::value_type>
-constexpr auto
-container_filter(const ContainerType &container, Predicate predicate) noexcept
-	-> ContainerType;
-
-#include "algorithm_impl.hpp"
diff --git a/src/util/algorithm_impl.hpp b/src/util/algorithm_impl.hpp
deleted file mode 100644
index d7c5e3b..0000000
--- a/src/util/algorithm_impl.hpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#pragma once
-
-#include "algorithm.hpp"
-
-#include <algorithm>
-
-template <typename ContainerType, typename Value>
-requires Container<ContainerType>
-constexpr auto container_find(const ContainerType &container, const Value &value) noexcept
-	-> typename ContainerType::const_iterator
-{
-	return std::find(container.begin(), container.end(), value);
-}
-
-template <typename ContainerType, typename Predicate>
-requires Container<ContainerType> &&
-	std::predicate<Predicate, typename ContainerType::value_type>
-constexpr auto
-container_find(const ContainerType &container, Predicate predicate) noexcept ->
-	typename ContainerType::const_iterator
-{
-	return std::find_if(container.begin(), container.end(), predicate);
-}
-
-template <typename ContainerType, typename Value>
-requires Container<ContainerType>
-constexpr auto container_has(const ContainerType &container, const Value &value) noexcept
-	-> bool
-{
-	return container_find(container, value) != container.end();
-}
-
-template <typename ContainerType, typename Predicate>
-requires Container<ContainerType> && HasPushBack<ContainerType> &&
-	std::predicate<Predicate, typename ContainerType::value_type>
-constexpr auto
-container_filter(const ContainerType &container, Predicate predicate) noexcept
-	-> ContainerType
-{
-	ContainerType filtered_container;
-
-	std::copy_if(
-		std::begin(container),
-		std::end(container),
-		std::back_inserter(filtered_container),
-		predicate);
-
-	return filtered_container;
-}
-
-template <typename ContainerType, typename Predicate>
-requires Container<ContainerType> &&
-	std::predicate<Predicate, typename ContainerType::value_type>
-constexpr auto
-container_filter(const ContainerType &container, Predicate predicate) noexcept
-	-> ContainerType
-{
-	ContainerType filtered_container;
-
-	std::copy_if(
-		std::begin(container),
-		std::end(container),
-		std::inserter(filtered_container, filtered_container.begin()),
-		predicate);
-
-	return filtered_container;
-}
diff --git a/src/util/ranges.hpp b/src/util/ranges.hpp
deleted file mode 100644
index c47c7b5..0000000
--- a/src/util/ranges.hpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#pragma once
-
-#include <concepts>
-#include <iterator>
-
-template <std::weakly_incrementable Value>
-class IotaViewIterator
-{
-public:
-	constexpr explicit IotaViewIterator(Value value) noexcept;
-
-	constexpr auto operator++() noexcept -> const IotaViewIterator &;
-	constexpr auto operator++(int) noexcept -> IotaViewIterator;
-
-	constexpr auto operator*() const noexcept -> Value;
-
-	constexpr auto operator==(const IotaViewIterator &rhs) const noexcept -> bool;
-	constexpr auto operator!=(const IotaViewIterator &rhs) const noexcept -> bool;
-
-private:
-	Value _value;
-};
-
-/**
- * A range factory that generates a sequence of elements by repeatedly incrementing an
- * initial value.
- *
- * This class was created because C++20 ranges is a complete shitshow in Clang.
- * https://github.com/llvm/llvm-project/issues/52696
- */
-template <std::weakly_incrementable Value, std::semiregular Bound>
-requires std::equality_comparable_with<Value, Bound> && std::copyable<Value>
-class IotaView
-{
-public:
-	constexpr IotaView(Value value, Bound bound) noexcept;
-
-	[[nodiscard]] constexpr auto begin() const noexcept -> IotaViewIterator<Value>;
-
-	[[nodiscard]] constexpr auto end() const noexcept -> IotaViewIterator<Value>;
-
-private:
-	Value _value;
-	Bound _bound;
-};
-
-#include "ranges_impl.hpp"
diff --git a/src/util/ranges_impl.hpp b/src/util/ranges_impl.hpp
deleted file mode 100644
index 1f1a577..0000000
--- a/src/util/ranges_impl.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#pragma once
-
-#include "ranges.hpp"
-
-// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
-#define IOTA_VIEW_ITERATOR(return_type)                                                  \
-	template <std::weakly_incrementable Value>                                           \
-	constexpr return_type IotaViewIterator<Value>
-
-IOTA_VIEW_ITERATOR()::IotaViewIterator(Value value) noexcept : _value(value) {}
-
-IOTA_VIEW_ITERATOR(auto)::operator++() noexcept -> const IotaViewIterator &
-{
-	++_value;
-
-	return *this;
-}
-
-IOTA_VIEW_ITERATOR(auto)::operator++(int) noexcept -> IotaViewIterator
-{
-	auto copy = *this;
-
-	++(*this);
-
-	return copy;
-}
-
-IOTA_VIEW_ITERATOR(auto)::operator*() const noexcept -> Value
-{
-	return _value;
-}
-
-IOTA_VIEW_ITERATOR(auto)::operator==(const IotaViewIterator &rhs) const noexcept -> bool
-{
-	return _value == rhs._value;
-}
-
-IOTA_VIEW_ITERATOR(auto)::operator!=(const IotaViewIterator &rhs) const noexcept -> bool
-{
-	return !(*this == rhs);
-}
-
-// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
-#define IOTA_VIEW(return_type)                                                           \
-	template <std::weakly_incrementable Value, std::semiregular Bound>                   \
-	requires std::equality_comparable_with<Value, Bound> && std::copyable<Value>         \
-	constexpr return_type IotaView<Value, Bound>
-
-IOTA_VIEW()::IotaView(Value value, Bound bound) noexcept : _value(value), _bound(bound) {}
-
-IOTA_VIEW(auto)::begin() const noexcept -> IotaViewIterator<Value>
-{
-	return IotaViewIterator(_value);
-}
-
-IOTA_VIEW(auto)::end() const noexcept -> IotaViewIterator<Value>
-{
-	return IotaViewIterator(_bound);
-}
-- 
cgit v1.2.3-18-g5258