|
@@ -36,204 +36,192 @@ namespace crown
|
|
|
/// Packed array of objects with lookup table.
|
|
/// Packed array of objects with lookup table.
|
|
|
///
|
|
///
|
|
|
/// @ingroup Containers
|
|
/// @ingroup Containers
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-class IdArray
|
|
|
|
|
|
|
+template <uint32_t MAX, typename T>
|
|
|
|
|
+struct IdArray
|
|
|
{
|
|
{
|
|
|
-public:
|
|
|
|
|
-
|
|
|
|
|
- /// Creates the table for tracking exactly @a MAX_NUM_ID - 1 unique Ids.
|
|
|
|
|
- IdArray();
|
|
|
|
|
|
|
+ /// Creates the table for tracking exactly @a MAX - 1 unique Ids.
|
|
|
|
|
+ IdArray();
|
|
|
|
|
|
|
|
/// Random access by index.
|
|
/// Random access by index.
|
|
|
- T& operator[](uint32_t i);
|
|
|
|
|
|
|
+ T& operator[](uint32_t i);
|
|
|
/// Random access by index.
|
|
/// Random access by index.
|
|
|
- const T& operator[](uint32_t i) const;
|
|
|
|
|
-
|
|
|
|
|
- /// Returns a new Id.
|
|
|
|
|
- Id create(const T& object);
|
|
|
|
|
-
|
|
|
|
|
- /// Destroys the object with the given @a id.
|
|
|
|
|
- void destroy(Id id);
|
|
|
|
|
-
|
|
|
|
|
- /// Returns whether the table has the object with the given @a id
|
|
|
|
|
- bool has(Id id) const;
|
|
|
|
|
-
|
|
|
|
|
- /// Returns the number of objects in the array.
|
|
|
|
|
- uint32_t size() const;
|
|
|
|
|
-
|
|
|
|
|
- /// Returns the object with the given @a id.
|
|
|
|
|
- T& lookup(const Id& id);
|
|
|
|
|
-
|
|
|
|
|
- T* begin();
|
|
|
|
|
- const T* begin() const;
|
|
|
|
|
- T* end();
|
|
|
|
|
- const T* end() const;
|
|
|
|
|
-
|
|
|
|
|
-private:
|
|
|
|
|
-
|
|
|
|
|
- // Returns the next available unique id.
|
|
|
|
|
- uint16_t next_id();
|
|
|
|
|
-
|
|
|
|
|
-public:
|
|
|
|
|
|
|
+ const T& operator[](uint32_t i) const;
|
|
|
|
|
|
|
|
// The index of the first unused id
|
|
// The index of the first unused id
|
|
|
- uint16_t m_freelist;
|
|
|
|
|
-
|
|
|
|
|
- // The index of the last id in the id table
|
|
|
|
|
- uint16_t m_last_index;
|
|
|
|
|
|
|
+ uint16_t m_freelist;
|
|
|
|
|
|
|
|
// Next available unique id
|
|
// Next available unique id
|
|
|
- uint16_t m_next_id;
|
|
|
|
|
- uint16_t m_num_objects;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ uint16_t m_next_id;
|
|
|
|
|
+ uint16_t m_size;
|
|
|
|
|
|
|
|
// The last valid id is reserved and cannot be used to
|
|
// The last valid id is reserved and cannot be used to
|
|
|
// refer to Ids from the outside
|
|
// refer to Ids from the outside
|
|
|
- Id m_sparse[MAX_NUM_ID];
|
|
|
|
|
- uint16_t m_sparse_to_dense[MAX_NUM_ID];
|
|
|
|
|
- uint16_t m_dense_to_sparse[MAX_NUM_ID];
|
|
|
|
|
- T m_objects[MAX_NUM_ID];
|
|
|
|
|
|
|
+ Id m_sparse[MAX];
|
|
|
|
|
+ uint16_t m_sparse_to_dense[MAX];
|
|
|
|
|
+ uint16_t m_dense_to_sparse[MAX];
|
|
|
|
|
+ T m_objects[MAX];
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline IdArray<MAX_NUM_ID, T>::IdArray()
|
|
|
|
|
- : m_freelist(INVALID_ID)
|
|
|
|
|
- , m_last_index(0)
|
|
|
|
|
- , m_next_id(0)
|
|
|
|
|
- , m_num_objects(0)
|
|
|
|
|
|
|
+/// Functions to manipulate IdArray.
|
|
|
|
|
+///
|
|
|
|
|
+/// @ingroup Containers
|
|
|
|
|
+namespace id_array
|
|
|
{
|
|
{
|
|
|
- for (uint32_t i = 0; i < MAX_NUM_ID; i++)
|
|
|
|
|
- {
|
|
|
|
|
- m_sparse[i].id = INVALID_ID;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ /// Creates a new @a object in the array @a a and returns its id.
|
|
|
|
|
+ template <uint32_t MAX, typename T> Id create(IdArray<MAX, T>& a, const T& object);
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline T& IdArray<MAX_NUM_ID, T>::operator[](uint32_t i)
|
|
|
|
|
-{
|
|
|
|
|
- CE_ASSERT(i < m_num_objects, "Index out of bounds");
|
|
|
|
|
- return m_objects[i];
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ /// Destroys the object with the given @a id.
|
|
|
|
|
+ template <uint32_t MAX, typename T> void destroy(IdArray<MAX, T>& a, Id id);
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline const T& IdArray<MAX_NUM_ID, T>::operator[](uint32_t i) const
|
|
|
|
|
-{
|
|
|
|
|
- CE_ASSERT(i < m_num_objects, "Index out of bounds");
|
|
|
|
|
- return m_objects[i];
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ /// Returns whether the table has the object with the given @a id.
|
|
|
|
|
+ template <uint32_t MAX, typename T> bool has(const IdArray<MAX, T>& a, Id id);
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline Id IdArray<MAX_NUM_ID, T>::create(const T& object)
|
|
|
|
|
-{
|
|
|
|
|
- CE_ASSERT(m_num_objects < MAX_NUM_ID, "Object list full");
|
|
|
|
|
|
|
+ /// Returns the number of objects in the array.
|
|
|
|
|
+ template <uint32_t MAX, typename T> uint32_t size(const IdArray<MAX, T>& a);
|
|
|
|
|
|
|
|
- // Obtain a new id
|
|
|
|
|
- Id id;
|
|
|
|
|
- id.id = next_id();
|
|
|
|
|
|
|
+ /// Returns the object with the given @a id.
|
|
|
|
|
+ template <uint32_t MAX, typename T> T& get(const Id& id);
|
|
|
|
|
+
|
|
|
|
|
+ template <uint32_t MAX, typename T> T* begin(IdArray<MAX, T>& a);
|
|
|
|
|
+ template <uint32_t MAX, typename T> const T* begin(const IdArray<MAX, T>& a);
|
|
|
|
|
+ template <uint32_t MAX, typename T> T* end(IdArray<MAX, T>& a);
|
|
|
|
|
+ template <uint32_t MAX, typename T> const T* end(const IdArray<MAX, T>& a);
|
|
|
|
|
+} // namespace id_array
|
|
|
|
|
|
|
|
- // Recycle slot if there are any
|
|
|
|
|
- if (m_freelist != INVALID_ID)
|
|
|
|
|
|
|
+namespace id_array
|
|
|
|
|
+{
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ template <uint32_t MAX, typename T>
|
|
|
|
|
+ inline Id create(IdArray<MAX, T>& a, const T& object)
|
|
|
{
|
|
{
|
|
|
- id.index = m_freelist;
|
|
|
|
|
- m_freelist = m_sparse[m_freelist].index;
|
|
|
|
|
|
|
+ CE_ASSERT(a.m_size < MAX, "Object list full");
|
|
|
|
|
+
|
|
|
|
|
+ // Obtain a new id
|
|
|
|
|
+ Id id;
|
|
|
|
|
+ id.id = a.m_next_id++;
|
|
|
|
|
+
|
|
|
|
|
+ // Recycle slot if there are any
|
|
|
|
|
+ if (a.m_freelist != INVALID_ID)
|
|
|
|
|
+ {
|
|
|
|
|
+ id.index = a.m_freelist;
|
|
|
|
|
+ a.m_freelist = a.m_sparse[a.m_freelist].index;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ id.index = a.m_size;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ a.m_sparse[id.index] = id;
|
|
|
|
|
+ a.m_sparse_to_dense[id.index] = a.m_size;
|
|
|
|
|
+ a.m_dense_to_sparse[a.m_size] = id.index;
|
|
|
|
|
+ a.m_objects[a.m_size] = object;
|
|
|
|
|
+ a.m_size++;
|
|
|
|
|
+
|
|
|
|
|
+ return id;
|
|
|
}
|
|
}
|
|
|
- else
|
|
|
|
|
|
|
+
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ template <uint32_t MAX, typename T>
|
|
|
|
|
+ inline void destroy(IdArray<MAX, T>& a, Id id)
|
|
|
{
|
|
{
|
|
|
- id.index = m_last_index++;
|
|
|
|
|
|
|
+ CE_ASSERT(has(a, id), "IdArray does not have ID: %d,%d", id.id, id.index);
|
|
|
|
|
+
|
|
|
|
|
+ a.m_sparse[id.index].id = INVALID_ID;
|
|
|
|
|
+ a.m_sparse[id.index].index = a.m_freelist;
|
|
|
|
|
+ a.m_freelist = id.index;
|
|
|
|
|
+
|
|
|
|
|
+ // Swap with last element
|
|
|
|
|
+ const uint32_t last = a.m_size - 1;
|
|
|
|
|
+ CE_ASSERT(last >= a.m_sparse_to_dense[id.index], "Swapping with previous item");
|
|
|
|
|
+ a.m_objects[a.m_sparse_to_dense[id.index]] = a.m_objects[last];
|
|
|
|
|
+
|
|
|
|
|
+ // Update tables
|
|
|
|
|
+ uint16_t std = a.m_sparse_to_dense[id.index];
|
|
|
|
|
+ uint16_t dts = a.m_dense_to_sparse[last];
|
|
|
|
|
+ a.m_sparse_to_dense[dts] = std;
|
|
|
|
|
+ a.m_dense_to_sparse[std] = dts;
|
|
|
|
|
+ a.m_size--;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- m_sparse[id.index] = id;
|
|
|
|
|
- m_sparse_to_dense[id.index] = m_num_objects;
|
|
|
|
|
- m_dense_to_sparse[m_num_objects] = id.index;
|
|
|
|
|
- m_objects[m_num_objects] = object;
|
|
|
|
|
- m_num_objects++;
|
|
|
|
|
-
|
|
|
|
|
- return id;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ template <uint32_t MAX, typename T>
|
|
|
|
|
+ inline T& get(IdArray<MAX, T>& a, const Id& id)
|
|
|
|
|
+ {
|
|
|
|
|
+ CE_ASSERT(has(a, id), "IdArray does not have ID: %d,%d", id.id, id.index);
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline void IdArray<MAX_NUM_ID, T>::destroy(Id id)
|
|
|
|
|
-{
|
|
|
|
|
- CE_ASSERT(has(id), "IdArray does not have ID: %d,%d", id.id, id.index);
|
|
|
|
|
-
|
|
|
|
|
- m_sparse[id.index].id = INVALID_ID;
|
|
|
|
|
- m_sparse[id.index].index = m_freelist;
|
|
|
|
|
- m_freelist = id.index;
|
|
|
|
|
-
|
|
|
|
|
- // Swap with last element
|
|
|
|
|
- const uint32_t last = m_num_objects - 1;
|
|
|
|
|
- CE_ASSERT(last >= m_sparse_to_dense[id.index], "Swapping with previous item");
|
|
|
|
|
- m_objects[m_sparse_to_dense[id.index]] = m_objects[last];
|
|
|
|
|
-
|
|
|
|
|
- // Update tables
|
|
|
|
|
- uint16_t std = m_sparse_to_dense[id.index];
|
|
|
|
|
- uint16_t dts = m_dense_to_sparse[last];
|
|
|
|
|
- m_sparse_to_dense[dts] = std;
|
|
|
|
|
- m_dense_to_sparse[std] = dts;
|
|
|
|
|
- m_num_objects--;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ return a.m_objects[a.m_sparse_to_dense[id.index]];
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline T& IdArray<MAX_NUM_ID, T>::lookup(const Id& id)
|
|
|
|
|
-{
|
|
|
|
|
- CE_ASSERT(has(id), "IdArray does not have ID: %d,%d", id.id, id.index);
|
|
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ template <uint32_t MAX, typename T>
|
|
|
|
|
+ inline bool has(const IdArray<MAX, T>& a, Id id)
|
|
|
|
|
+ {
|
|
|
|
|
+ return id.index < MAX && a.m_sparse[id.index].id == id.id;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return m_objects[m_sparse_to_dense[id.index]];
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ template <uint32_t MAX, typename T>
|
|
|
|
|
+ inline uint32_t size(const IdArray<MAX, T>& a)
|
|
|
|
|
+ {
|
|
|
|
|
+ return a.m_size;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline bool IdArray<MAX_NUM_ID, T>::has(Id id) const
|
|
|
|
|
-{
|
|
|
|
|
- return id.index < MAX_NUM_ID && m_sparse[id.index].id == id.id;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ template <uint32_t MAX, typename T>
|
|
|
|
|
+ inline T* begin(IdArray<MAX, T>& a)
|
|
|
|
|
+ {
|
|
|
|
|
+ return a.m_objects;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline uint32_t IdArray<MAX_NUM_ID, T>::size() const
|
|
|
|
|
-{
|
|
|
|
|
- return m_num_objects;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ template <uint32_t MAX, typename T>
|
|
|
|
|
+ inline const T* begin(const IdArray<MAX, T>& a)
|
|
|
|
|
+ {
|
|
|
|
|
+ return a.m_objects;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline uint16_t IdArray<MAX_NUM_ID, T>::next_id()
|
|
|
|
|
-{
|
|
|
|
|
- return m_next_id++;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ template <uint32_t MAX, typename T>
|
|
|
|
|
+ inline T* end(IdArray<MAX, T>& a)
|
|
|
|
|
+ {
|
|
|
|
|
+ return a.m_objects + a.m_size;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-//-----------------------------------------------------------------------------
|
|
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline T* IdArray<MAX_NUM_ID, T>::begin()
|
|
|
|
|
-{
|
|
|
|
|
- return m_objects;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ //-----------------------------------------------------------------------------
|
|
|
|
|
+ template <uint32_t MAX, typename T>
|
|
|
|
|
+ inline const T* end(const IdArray<MAX, T>& a)
|
|
|
|
|
+ {
|
|
|
|
|
+ return a.m_objects + a.m_size;
|
|
|
|
|
+ }
|
|
|
|
|
+} // namespace id_array
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline const T* IdArray<MAX_NUM_ID, T>::begin() const
|
|
|
|
|
|
|
+template <uint32_t MAX, typename T>
|
|
|
|
|
+inline IdArray<MAX, T>::IdArray()
|
|
|
|
|
+ : m_freelist(INVALID_ID)
|
|
|
|
|
+ , m_next_id(0)
|
|
|
|
|
+ , m_size(0)
|
|
|
{
|
|
{
|
|
|
- return m_objects;
|
|
|
|
|
|
|
+ for (uint32_t i = 0; i < MAX; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ m_sparse[i].id = INVALID_ID;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline T* IdArray<MAX_NUM_ID, T>::end()
|
|
|
|
|
|
|
+template <uint32_t MAX, typename T>
|
|
|
|
|
+inline T& IdArray<MAX, T>::operator[](uint32_t i)
|
|
|
{
|
|
{
|
|
|
- return m_objects + m_num_objects;
|
|
|
|
|
|
|
+ CE_ASSERT(i < m_size, "Index out of bounds");
|
|
|
|
|
+ return m_objects[i];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
-template <uint32_t MAX_NUM_ID, typename T>
|
|
|
|
|
-inline const T* IdArray<MAX_NUM_ID, T>::end() const
|
|
|
|
|
|
|
+template <uint32_t MAX, typename T>
|
|
|
|
|
+inline const T& IdArray<MAX, T>::operator[](uint32_t i) const
|
|
|
{
|
|
{
|
|
|
- return m_objects + m_num_objects;
|
|
|
|
|
|
|
+ CE_ASSERT(i < m_size, "Index out of bounds");
|
|
|
|
|
+ return m_objects[i];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} // namespace crown
|
|
} // namespace crown
|