@@ -100,9 +100,7 @@ namespace nexo::ecs {
100100 *
101101 * @param entity The entity to add the component to
102102 * @param componentData Pointer to the raw component data
103- * @throws OutOfRange if entity ID exceeds MAX_ENTITIES
104- *
105- * @pre The entity must be a valid entity ID
103+ * @pre The entity must be a valid entity ID (validated by EntityManager)
106104 * @pre componentData must point to valid memory of component's size
107105 */
108106 virtual void insertRaw (Entity entity, const void * componentData) = 0;
@@ -112,9 +110,7 @@ namespace nexo::ecs {
112110 *
113111 * @param entity The entity to add the component to
114112 * @param constructor Pointer to the constructor function or functor
115- * @throws OutOfRange if entity ID exceeds MAX_ENTITIES
116- *
117- * @pre The entity must be a valid entity ID
113+ * @pre The entity must be a valid entity ID (validated by EntityManager)
118114 */
119115 virtual void insertRawWithConstructor (Entity entity, void (*constructor)(void * memoryDst)) = 0;
120116
@@ -154,8 +150,8 @@ namespace nexo::ecs {
154150 * @tparam T The component type stored in this array
155151 * @tparam capacity Initial capacity for the sparse array
156152 *
157- * @note This class is not thread-safe. Access should be synchronized externally when
158- * used in multithreaded contexts .
153+ * @warning Not thread-safe. The ECS assumes a single-threaded execution model.
154+ * All component array operations must be performed from the main ECS thread .
159155 */
160156 template <typename T, size_t capacity = 1024 >
161157 requires (capacity >= 1 )
@@ -211,14 +207,11 @@ namespace nexo::ecs {
211207 *
212208 * @param entity The entity to add the component to
213209 * @param component The component instance to add
214- * @throws OutOfRange if entity ID exceeds MAX_ENTITIES
215210 *
216- * @pre The entity must be a valid entity ID
211+ * @pre The entity must be a valid entity ID (validated by EntityManager)
217212 */
218213 void insert (Entity entity, T component)
219214 {
220- if (entity >= MAX_ENTITIES) THROW_EXCEPTION (OutOfRange, entity);
221-
222215 // Ensure m_sparse can hold this entity index.
223216 ensureSparseCapacity (entity);
224217
@@ -240,15 +233,11 @@ namespace nexo::ecs {
240233 *
241234 * @param entity The entity to add the component to
242235 * @param componentData Pointer to the raw component data
243- * @throws OutOfRange if entity ID exceeds MAX_ENTITIES
244- *
245- * @pre The entity must be a valid entity ID
236+ * @pre The entity must be a valid entity ID (validated by EntityManager)
246237 * @pre componentData must point to valid memory of component's size
247238 */
248239 void insertRaw (Entity entity, const void * componentData) override
249240 {
250- if (entity >= MAX_ENTITIES) THROW_EXCEPTION (OutOfRange, entity);
251-
252241 ensureSparseCapacity (entity);
253242
254243 if (hasComponent (entity)) {
@@ -278,14 +267,10 @@ namespace nexo::ecs {
278267 *
279268 * @param entity The entity to add the component to
280269 * @param constructor Pointer to the constructor function or functor
281- * @throws OutOfRange if entity ID exceeds MAX_ENTITIES
282- *
283- * @pre The entity must be a valid entity ID
270+ * @pre The entity must be a valid entity ID (validated by EntityManager)
284271 */
285272 void insertRawWithConstructor (Entity entity, void (*constructor)(void * memoryDst))
286273 {
287- if (entity >= MAX_ENTITIES) THROW_EXCEPTION (OutOfRange, entity);
288-
289274 ensureSparseCapacity (entity);
290275
291276 if (hasComponent (entity)) {
@@ -294,12 +279,18 @@ namespace nexo::ecs {
294279 }
295280
296281 const size_t newIndex = m_size;
297- m_sparse[entity] = newIndex;
298- m_dense.push_back (entity);
299282
300- // allocate new component in the array
283+ // Allocate first, then construct, then commit bookkeeping
301284 m_componentArray.emplace_back ();
302- constructor (&m_componentArray[newIndex]);
285+ try {
286+ constructor (&m_componentArray[newIndex]);
287+ } catch (...) {
288+ m_componentArray.pop_back ();
289+ throw ;
290+ }
291+
292+ m_sparse[entity] = newIndex;
293+ m_dense.push_back (entity);
303294 ++m_size;
304295 }
305296
@@ -668,6 +659,9 @@ namespace nexo::ecs {
668659 * This class allows you to create component arrays at runtime without knowing
669660 * the component type at compile time. You only need to specify the size of
670661 * each component.
662+ *
663+ * @warning Not thread-safe. The ECS assumes a single-threaded execution model.
664+ * All component array operations must be performed from the main ECS thread.
671665 */
672666 class alignas (64 ) TypeErasedComponentArray final : public IComponentArray {
673667 public:
@@ -690,9 +684,7 @@ namespace nexo::ecs {
690684 *
691685 * @param entity The entity to add the component to
692686 * @param componentData Pointer to the raw component data
693- * @throws OutOfRange if entity ID exceeds MAX_ENTITIES
694- *
695- * @pre The entity must be a valid entity ID
687+ * @pre The entity must be a valid entity ID (validated by EntityManager)
696688 * @pre componentData must point to valid memory of component's size
697689 */
698690 void insertRaw (Entity entity, const void * componentData) override ;
@@ -702,9 +694,7 @@ namespace nexo::ecs {
702694 *
703695 * @param entity The entity to add the component to
704696 * @param constructor Pointer to the constructor function or functor
705- * @throws OutOfRange if entity ID exceeds MAX_ENTITIES
706- *
707- * @pre The entity must be a valid entity ID
697+ * @pre The entity must be a valid entity ID (validated by EntityManager)
708698 */
709699 void insertRawWithConstructor (Entity entity, void (*constructor)(void * memoryDst)) override ;
710700
@@ -816,6 +806,8 @@ namespace nexo::ecs {
816806 std::vector<size_t > m_sparse;
817807 // Dense storage for entity IDs
818808 std::vector<Entity> m_dense;
809+ // Reusable buffer for swapComponents() to avoid per-call heap allocation
810+ std::vector<std::byte> m_swapBuffer;
819811 // Size of each component in bytes
820812 size_t m_componentSize;
821813 // Initial capacity
0 commit comments