16#ifndef AEONGAMES_DEPENDENCY_MAP_H
17#define AEONGAMES_DEPENDENCY_MAP_H
19#include <unordered_map>
37 class Hash = std::hash<Key>,
38 class KeyEqual = std::equal_to<Key>,
39 class MapAllocator = std::allocator< std::pair<
const Key,
typename std::tuple <
42 std::vector<Key, std::allocator<Key >>,
45 class VectorAllocator = std::allocator<Key>
49 using GraphNode =
typename std::tuple <
52 std::vector<Key, VectorAllocator>,
58 using triple =
typename std::tuple<Key, std::vector<Key>, T>;
63 typename std::vector<Key, VectorAllocator>::iterator mIterator{};
64 typename std::unordered_map <
71 friend class DependencyMap<Key, T, Hash, KeyEqual, MapAllocator, VectorAllocator>;
73 const typename std::vector<Key, VectorAllocator>::iterator & aIterator,
81 mIterator ( aIterator ),
84 using difference_type =
typename std::vector<Key, VectorAllocator>::iterator::difference_type;
85 using value_type =
typename std::vector<Key, VectorAllocator>::iterator::value_type;
92 ~iterator() =
default;
98 return mIterator == i.mIterator;
103 return mIterator != i.mIterator;
120 return std::get<3> ( mGraph->at ( *mIterator ) );
125 return &std::get<3> ( mGraph->at ( *mIterator ) );
137 return std::get<2> ( mGraph->at ( *mIterator ) );
144 typename std::vector<Key, VectorAllocator>::const_iterator mIterator{};
145 const typename std::unordered_map <
152 friend class DependencyMap<Key, T, Hash, KeyEqual, MapAllocator, VectorAllocator>;
154 const typename std::vector<Key, VectorAllocator>::const_iterator & aIterator,
155 const std::unordered_map <
162 mIterator ( aIterator ),
165 using difference_type =
typename std::vector<Key, VectorAllocator>::const_iterator::difference_type;
166 using value_type =
typename std::vector<Key, VectorAllocator>::const_iterator::value_type;
170 const_iterator() =
default;
173 ~const_iterator() =
default;
175 const_iterator&
operator= (
const const_iterator& ) =
default;
179 return mIterator == i.mIterator;
184 return mIterator != i.mIterator;
201 return std::get<3> ( mGraph->at ( *mIterator ) );
206 return &std::get<3> ( mGraph->at ( *mIterator ) );
218 return std::get<2> ( mGraph->at ( *mIterator ) );
226 graph.reserve ( count );
227 sorted.reserve ( count );
240 for (
auto& i : aList )
242 graph[std::get<0> ( i )] = GraphNode{{}, 0, std::get<1> ( i ), std::get<2> ( i ) };
244 for (
auto& i : graph )
247 if ( std::find ( sorted.begin(), sorted.end(), i.first ) == sorted.end() )
252 std::get<0> ( graph[i.first] ) = i.first;
256 if ( std::get<1> ( graph[node] ) < std::get<2> ( graph[node] ).size() )
258 if ( std::get<2> ( graph[node] ) [std::get<1> ( graph[node] )] == i.first )
260 throw std::runtime_error (
"One of the provided nodes creates a circular dependency." );
263 auto next = graph.find ( std::get<2> ( graph[node] ) [std::get<1> ( graph[node] )] );
264 ++std::get<1> ( graph[node] );
266 if ( next != graph.end() && std::find ( sorted.begin(), sorted.end(), ( *next ).first ) == sorted.end() )
268 std::get<0> ( ( *next ).second ) = node;
269 node = ( *next ).first;
275 sorted.push_back ( node );
276 std::get<1> ( graph[node] ) = 0;
278 node = std::get<0> ( graph[node] );
281 while ( node != std::get<0> ( graph[node] ) );
282 sorted.push_back ( node );
294 if ( sorted.empty() && graph.empty() )
296 graph[std::get<0> ( item )] = GraphNode{{}, 0, std::get<1> ( item ), std::get<2> ( item ) };
297 sorted.emplace_back ( std::get<0> ( item ) );
301 auto insertion_cursor = sorted.begin();
302 bool circular_dependency =
false;
304 for (
auto& i : std::get<1> ( item ) )
307 if ( graph.find ( i ) != graph.end() && std::find ( sorted.begin(), insertion_cursor, i ) == insertion_cursor )
312 std::get<0> ( graph[i] ) = std::get<0> ( item );
314 while ( node != std::get<0> ( item ) )
316 if ( std::get<1> ( graph[node] ) < std::get<2> ( graph[node] ).size() )
318 if ( std::get<2> ( graph[node] ) [std::get<1> ( graph[node] )] == std::get<0> ( item ) )
327 circular_dependency =
true;
330 auto next = graph.find ( std::get<2> ( graph[node] ) [std::get<1> ( graph[node] )] );
331 ++std::get<1> ( graph[node] );
333 if ( next != graph.end() && std::find ( sorted.begin(), insertion_cursor, ( *next ).first ) == insertion_cursor )
335 std::get<0> ( ( *next ).second ) = node;
336 node = ( *next ).first;
341 auto node_iterator = std::find ( sorted.begin(), sorted.end(), node );
342 std::rotate ( insertion_cursor++, node_iterator, node_iterator + 1 );
343 std::get<1> ( graph[node] ) = 0;
345 node = std::get<0> ( graph[node] );
350 if ( !circular_dependency )
353 graph[std::get<0> ( item )] = GraphNode{{}, 0, std::get<1> ( item ), std::get<2> ( item ) };
354 return sorted.insert ( insertion_cursor, std::get<0> ( item ) ) - sorted.begin();
358 throw std::runtime_error (
"New node would create a circular dependency." );
367 sorted.erase ( std::remove ( sorted.begin(), sorted.end(), key ), sorted.end() );
376 if ( index >= sorted.size() )
378 throw std::out_of_range (
"Index out of range." );
380 return std::get<3> ( graph.at ( sorted[index] ) );
396 return sorted.size();
406 std::find ( sorted.begin(), sorted.end(), key ),
417 std::find ( sorted.begin(), sorted.end(), key ),
425 return iterator{sorted.begin(), &graph};
431 return iterator{sorted.end(), &graph};
456 std::vector<Key, VectorAllocator> sorted;
Const bidirectional iterator over topologically sorted entries.
typename std::vector< Key, VectorAllocator >::const_iterator::difference_type difference_type
Iterator difference type.
const_iterator & operator--()
Pre-decrement operator.
const_iterator & operator=(const const_iterator &)=default
Copy assignment operator.
bool operator!=(const const_iterator &i) const
Inequality comparison operator.
const T & reference
Const reference to the mapped value type.
std::bidirectional_iterator_tag iterator_category
Bidirectional iterator category.
const std::vector< Key, VectorAllocator > & GetDependencies() const
Get the dependency list of the element this iterator points to.
const_iterator(const const_iterator &)=default
Copy constructor.
const T * pointer
Const pointer to the mapped value type.
typename std::vector< Key, VectorAllocator >::const_iterator::value_type value_type
Iterator value type.
const Key & GetKey() const
Get the key of the element this iterator points to.
reference operator*() const
Dereference operator.
const_iterator & operator++()
Pre-increment operator.
bool operator==(const const_iterator &i) const
Equality comparison operator.
pointer operator->() const
Member access operator.
Mutable bidirectional iterator over topologically sorted entries.
const std::vector< Key, VectorAllocator > & GetDependencies() const
Get the dependency list of the element this iterator points to.
iterator(const iterator &)=default
Copy constructor.
typename std::vector< Key, VectorAllocator >::iterator::difference_type difference_type
Iterator difference type.
std::bidirectional_iterator_tag iterator_category
Bidirectional iterator category.
T * pointer
Pointer to the mapped value type.
iterator & operator++()
Pre-increment operator.
const Key & GetKey() const
Get the key of the element this iterator points to.
reference operator*() const
Dereference operator.
iterator & operator--()
Pre-decrement operator.
bool operator==(const iterator &i) const
Equality comparison operator.
typename std::vector< Key, VectorAllocator >::iterator::value_type value_type
Iterator value type.
pointer operator->() const
Member access operator.
bool operator!=(const iterator &i) const
Inequality comparison operator.
iterator & operator=(const iterator &)=default
Copy assignment operator.
T & reference
Reference to the mapped value type.
const_iterator begin() const
Get a const iterator to the first element in sorted order.
void Reserve(size_t count)
Reserve storage for a given number of elements.
DependencyMap()=default
Default constructor.
void Erase(const Key &key)
Remove an element by key.
iterator Find(const Key &key)
Find an element by key (mutable).
const_iterator Find(const Key &key) const
Find an element by key (const).
iterator begin()
Get a mutable iterator to the first element in sorted order.
const std::size_t Size() const
Get the number of elements.
size_t Insert(const triple &item)
Insert a new element, maintaining topological order.
DependencyMap(std::initializer_list< triple > aList)
Construct from an initializer list, performing topological sort.
~DependencyMap()=default
Default destructor.
const_iterator end() const
Get a const iterator past the last element in sorted order.
const T & operator[](const std::size_t index) const
Access element by sorted index (const).
iterator end()
Get a mutable iterator past the last element in sorted order.
typename std::tuple< Key, std::vector< Key >, T > triple
Convenience type alias for an insertion tuple: (key, dependencies, payload).
<- This is here just for the literals