created retentive class family
This commit is contained in:
parent
4d59b8a53d
commit
75df9ad96d
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
add_library(nm_utils STATIC
|
add_library(nm_utils STATIC
|
||||||
"Window.cpp"
|
"Window.cpp"
|
||||||
"RetentiveArray.hpp")
|
"RetentiveArray.hpp" "RetentiveObject.hpp" "RetentiveEntity.hpp")
|
||||||
|
|
||||||
target_include_directories(nm_utils PUBLIC ${SDL2_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(nm_utils PUBLIC ${SDL2_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_link_libraries(nm_utils PUBLIC ${SDL2_LIBRARIES})
|
target_link_libraries(nm_utils PUBLIC ${SDL2_LIBRARIES})
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include "RetentiveEntity.hpp"
|
||||||
#include <array>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief An array that remembers its past.
|
* @brief An array that remembers its past.
|
||||||
|
@ -24,7 +22,7 @@ template<
|
||||||
typename Type,
|
typename Type,
|
||||||
unsigned int AttentionSpan,
|
unsigned int AttentionSpan,
|
||||||
typename std::enable_if_t<(AttentionSpan > 0), bool> = true>
|
typename std::enable_if_t<(AttentionSpan > 0), bool> = true>
|
||||||
class RetentiveArray
|
class RetentiveArray : public RetentiveEntity<std::vector<Type>, AttentionSpan>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -104,77 +102,14 @@ public:
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private:
|
||||||
* @brief Get the array from `index` generations ago
|
void CycleGenerations() override
|
||||||
*
|
|
||||||
* @param index Amount of generations to go backwards in time
|
|
||||||
* @return The array from before `index` generations
|
|
||||||
*/
|
|
||||||
std::vector<Type>& operator[](size_t index)
|
|
||||||
{
|
|
||||||
return data[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the most up-to-date array
|
|
||||||
*
|
|
||||||
* @return The array with generation 0
|
|
||||||
*/
|
|
||||||
std::vector<Type>& Current()
|
|
||||||
{
|
|
||||||
return data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Evolve the data in the array
|
|
||||||
*
|
|
||||||
* Simply calls the member function pointer. The called function is then
|
|
||||||
* supposed to perform whatever is needed to compute the new array contents.
|
|
||||||
*
|
|
||||||
* The data is swapped BEFORE calling this function, so the evolution function should
|
|
||||||
* modify the data in the Current() vector (index 0)
|
|
||||||
*/
|
|
||||||
void Evolve()
|
|
||||||
{
|
|
||||||
// Evolve the array
|
|
||||||
Evolve(rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Evolve the data in the array
|
|
||||||
*
|
|
||||||
* Simply calls the provided function pointer. The called function is then
|
|
||||||
* supposed to perform whatever is needed to compute the new array contents.
|
|
||||||
*
|
|
||||||
* The data is swapped BEFORE calling this function, so the evolution function should
|
|
||||||
* modify the data in the Current() vector (index 0)
|
|
||||||
*
|
|
||||||
* @param rule A function that evolves the data in the array
|
|
||||||
*/
|
|
||||||
void Evolve(std::function<void(void)> rule)
|
|
||||||
{
|
{
|
||||||
// Cycle the array contents, so that the previous "current" array is now the 2nd.
|
// Cycle the array contents, so that the previous "current" array is now the 2nd.
|
||||||
// The 2nd becomes the 3rd etc, and the former last array becomes the new current
|
// The 2nd becomes the 3rd etc, and the former last array becomes the new current
|
||||||
for (int n = 1; n <= AttentionSpan; n++)
|
for (int n = 1; n <= AttentionSpan; n++)
|
||||||
{
|
{
|
||||||
data[0].swap(data[1]);
|
data[0].swap(data[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
rule();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set a general rule for evolving the data
|
|
||||||
*
|
|
||||||
* @param rule The new evolution rule
|
|
||||||
*/
|
|
||||||
void SetEvolutionRule(std::function<void(void)> rule)
|
|
||||||
{
|
|
||||||
this->rule = rule;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::array<std::vector<Type>, AttentionSpan + 1> data;
|
|
||||||
std::function<void(void)> rule = std::bind([]() {}); // Do nothing by default
|
|
||||||
};
|
};
|
||||||
|
|
99
lib/RetentiveEntity.hpp
Normal file
99
lib/RetentiveEntity.hpp
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Abstract base type for all retentive things
|
||||||
|
*
|
||||||
|
* @tparam Type The object to give a memory to
|
||||||
|
* @tparam AttentionSpan How many generations of the data will be remembered by the object
|
||||||
|
*/
|
||||||
|
template<
|
||||||
|
typename Type,
|
||||||
|
unsigned int AttentionSpan,
|
||||||
|
typename std::enable_if_t<(AttentionSpan > 0), bool> = true>
|
||||||
|
class RetentiveEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RetentiveEntity() {}
|
||||||
|
RetentiveEntity(const RetentiveEntity<Type, AttentionSpan>& other) = delete;
|
||||||
|
RetentiveEntity(RetentiveEntity<Type, AttentionSpan>&& other) = delete;
|
||||||
|
RetentiveEntity<Type, AttentionSpan>& operator=(const RetentiveEntity<Type, AttentionSpan>& other) = delete;
|
||||||
|
RetentiveEntity<Type, AttentionSpan>& operator=(RetentiveEntity<Type, AttentionSpan>&& other) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the entity from `index` generations ago
|
||||||
|
*
|
||||||
|
* @param index Amount of generations to go backwards in time
|
||||||
|
* @return The entity from before `index` generations
|
||||||
|
*/
|
||||||
|
virtual Type& operator[](size_t index)
|
||||||
|
{
|
||||||
|
return data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the most up-to-date entity
|
||||||
|
*
|
||||||
|
* @return The entity with generation 0
|
||||||
|
*/
|
||||||
|
virtual Type& Current()
|
||||||
|
{
|
||||||
|
return data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evolve the data in the entity
|
||||||
|
*
|
||||||
|
* Simply calls the member function pointer. The called function is then
|
||||||
|
* supposed to perform whatever is needed to compute the new object contents.
|
||||||
|
*
|
||||||
|
* The data is swapped BEFORE calling this function, so the evolution function should
|
||||||
|
* modify the data in the Current() vector (index 0)
|
||||||
|
*/
|
||||||
|
void Evolve()
|
||||||
|
{
|
||||||
|
// Evolve the object
|
||||||
|
CycleGenerations();
|
||||||
|
rule();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evolve the data in the object
|
||||||
|
*
|
||||||
|
* Simply calls the provided function pointer. The called function is then
|
||||||
|
* supposed to perform whatever is needed to compute the new object contents.
|
||||||
|
*
|
||||||
|
* The data is swapped BEFORE calling this function, so the evolution function should
|
||||||
|
* modify the data in the Current() vector (index 0)
|
||||||
|
*
|
||||||
|
* @param rule A function that evolves the data in the object
|
||||||
|
*/
|
||||||
|
void Evolve(std::function<void(void)> rule)
|
||||||
|
{
|
||||||
|
CycleGenerations();
|
||||||
|
rule();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set a general rule for evolving the data
|
||||||
|
*
|
||||||
|
* @param rule The new evolution rule
|
||||||
|
*/
|
||||||
|
void SetEvolutionRule(std::function<void(void)> rule)
|
||||||
|
{
|
||||||
|
this->rule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Swaps the objects in the array
|
||||||
|
*/
|
||||||
|
virtual void CycleGenerations() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::array<Type, AttentionSpan + 1> data;
|
||||||
|
std::function<void(void)> rule = std::bind([]() {}); // Do nothing by default
|
||||||
|
};
|
149
lib/RetentiveObject.hpp
Normal file
149
lib/RetentiveObject.hpp
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RetentiveEntity.hpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An object that remembers its past.
|
||||||
|
*
|
||||||
|
* You most likely want to use a RetentiveArray instead.
|
||||||
|
* This structure is only really useful if you have a custom container class
|
||||||
|
* that you need to evolve over time.
|
||||||
|
*
|
||||||
|
* A retentive object is a kind of buffered object that "remembers"
|
||||||
|
* the state of the object from the last n generations.
|
||||||
|
*
|
||||||
|
* This structure handles the evolution of these kinds of objects and takes
|
||||||
|
* care of the memory allocation/freeing as well as properly swapping the
|
||||||
|
* object pointers.
|
||||||
|
*
|
||||||
|
* @tparam Type The object to give a memory to
|
||||||
|
* @tparam AttentionSpan How many generations of the data will be remembered by the object
|
||||||
|
*/
|
||||||
|
template<
|
||||||
|
typename Type,
|
||||||
|
unsigned int AttentionSpan,
|
||||||
|
typename std::enable_if_t<(AttentionSpan > 0), bool> = true>
|
||||||
|
class RetentiveObject : public RetentiveEntity<Type*, AttentionSpan>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructs a new, empty retentive object
|
||||||
|
*/
|
||||||
|
RetentiveObject()
|
||||||
|
{
|
||||||
|
// Create new vectors for every generation that needs to be remembered
|
||||||
|
for (int n = 0; n <= AttentionSpan; n++)
|
||||||
|
{
|
||||||
|
data[n] = new Type();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructs a new, empty retentive object
|
||||||
|
*
|
||||||
|
* @param size The size of the data contained in the object
|
||||||
|
*/
|
||||||
|
RetentiveObject(const Type& initVal)
|
||||||
|
{
|
||||||
|
// Create new vectors for every generation that needs to be remembered
|
||||||
|
for (int n = 0; n <= AttentionSpan; n++)
|
||||||
|
{
|
||||||
|
data[n] = new Type(initVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructs a new retentive object with the data of another object
|
||||||
|
*
|
||||||
|
* @param other The retentive object to copy from
|
||||||
|
*/
|
||||||
|
RetentiveObject<Type, AttentionSpan>& operator=(const RetentiveObject<Type, AttentionSpan>& other)
|
||||||
|
{
|
||||||
|
for (int n = 0; n <= AttentionSpan; n++)
|
||||||
|
{
|
||||||
|
*data[n] = *other.data[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructs a new retentive object pointing to the data of an rvalue
|
||||||
|
*
|
||||||
|
* @param other The retentive object to set its data to
|
||||||
|
*/
|
||||||
|
RetentiveObject<Type, AttentionSpan>& operator=(RetentiveObject<Type, AttentionSpan>&& other)
|
||||||
|
{
|
||||||
|
for (int n = 0; n <= AttentionSpan; n++)
|
||||||
|
{
|
||||||
|
data[n] = other.data[n];
|
||||||
|
other.data[n] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructs a new retentive object with the data of another object
|
||||||
|
*
|
||||||
|
* @param other The retentive object to copy from
|
||||||
|
*/
|
||||||
|
RetentiveObject(const RetentiveObject<Type, AttentionSpan>& other)
|
||||||
|
{
|
||||||
|
*this = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructs a new retentive object pointing to the data of an rvalue
|
||||||
|
*
|
||||||
|
* @param other The retentive object to set its data to
|
||||||
|
*/
|
||||||
|
RetentiveObject(RetentiveObject<Type, AttentionSpan>&& other)
|
||||||
|
{
|
||||||
|
*this = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
~RetentiveObject()
|
||||||
|
{
|
||||||
|
for (int n = 0; n <= AttentionSpan; n++)
|
||||||
|
{
|
||||||
|
if (data[n] != nullptr)
|
||||||
|
delete data[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the object from `index` generations ago
|
||||||
|
*
|
||||||
|
* @param index Amount of generations to go backwards in time
|
||||||
|
* @return The object from before `index` generations
|
||||||
|
*/
|
||||||
|
Type& operator[](size_t index) override
|
||||||
|
{
|
||||||
|
return *(data[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the most up-to-date object
|
||||||
|
*
|
||||||
|
* @return The object with generation 0
|
||||||
|
*/
|
||||||
|
Type& Current() override
|
||||||
|
{
|
||||||
|
return *(data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Swaps the objects in the array
|
||||||
|
*/
|
||||||
|
void CycleGenerations() override
|
||||||
|
{
|
||||||
|
// Cycle the object contents, so that the previous "current" object is now the 2nd.
|
||||||
|
// The 2nd becomes the 3rd etc, and the former last object becomes the new current
|
||||||
|
for (int n = 1; n <= AttentionSpan; n++)
|
||||||
|
{
|
||||||
|
std::swap(data[0], data[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in a new issue