Can you split this function up into smaller functions? template<class C, typename... Args>
C* ECS::AddComponent(const uint32_t entityId, Args&&... args) {
	auto newComponentID = Component<C>::GetTypeID();

	if (componentMasks[entityId].HasComponent(newComponentID)) {
		return nullptr; // Component already exists for the entity
	}

	componentMasks[entityId].AddComponent(newComponentID);
	Archetype* newArchetype = nullptr;
	C* newComponent = nullptr;

	Record& record = entityArchetypeMap[entityId];
	Archetype* oldArchetype = record.archetype;

	auto& newComponentMask = componentMasks[entityId];
	newArchetype = GetArchetype(componentMasks[entityId]);

	// if the entity already has components
	if (oldArchetype) {
		auto oldComponentMask = oldArchetype->componentMask;
		std::size_t entityIndex = std::find(
			oldArchetype->entityIds.begin(),
			oldArchetype->entityIds.end() - 1,
			entityId
		) - oldArchetype->entityIds.begin();

		std::size_t index = 0;
		std::size_t j = 0;

		for (std::size_t i = 0; i < newComponentMask.GetBitsetMask().size() - 1; ++i) {
			if (newComponentMask.GetBitsetMask().test(i)) {
				const ComponentBase* const componentBase = componentMap[i];
				const std::size_t newComponentDataSize = componentBase->GetSize();

				std::size_t currentSize = newArchetype->entityIds.size() * newComponentDataSize;
				std::size_t newSize = currentSize + newComponentDataSize;

				if (newSize > newArchetype->componentDataSize[index]) {
					Reallocate(componentBase, newComponentDataSize, newArchetype, index);
				}

				if (oldComponentMask.HasComponent(i)) {
					TransferComponentData(componentBase, oldArchetype, newArchetype, index, j, entityIndex);
					++j;
				}
				else {
					/*newComponent = */ new (&newArchetype->componentData[index][currentSize]) C(std::forward<Args>(args)...);
				}
				index++;
			}
		}

		auto lastEntity = oldArchetype->entityIds.size() - 1;

		// If the old archetype still has entities in
		if (!oldArchetype->entityIds.empty() && entityIndex < oldArchetype->entityIds.size()) {
			std::iter_swap(oldArchetype->entityIds.begin() + entityIndex, oldArchetype->entityIds.begin() + lastEntity);
			for (std::size_t i = 0, j = 0, index = 0; i < oldComponentMask.GetBitsetMask().size() - 1; ++i) {
				if (oldComponentMask.GetBitsetMask().test(i)) {
					const ComponentBase* const componentBase = componentMap[i];
					SwapComponentData(componentBase, oldArchetype, index, entityIndex);
					++index;
				}
			}

			// swap the entity leaving the archetype with the one at the end of the list before deleting the leaving entity by popping
			oldArchetype->entityIds.pop_back();
		}
	}
	// If this is the first time we're adding a component to this entity
	else
	{
		// Get size of the new component
		const ComponentBase* const newComponentBase = componentMap[newComponentID];
		const std::size_t& newComponentDataSize = newComponentBase->GetSize();

		std::size_t currentSize = newArchetype->entityIds.size() * newComponentDataSize;
		std::size_t newSize = currentSize + newComponentDataSize;

		//Reallocate(newComponentBase, newArchetype, 0);
		if (newSize > newArchetype->componentDataSize[0]) {
			Reallocate(newComponentBase, newComponentDataSize, newArchetype, 0);
		}

		newComponent = new (&newArchetype->componentData[0][currentSize]) C(std::forward<Args>(args)...);
	}

	newArchetype->entityIds.push_back(entityId);
	record.index = newArchetype->entityIds.size() - 1;
	record.archetype = newArchetype;

	return newComponent;
} This is the implementation for the reallocate and transferallocate functions void ECS::TransferComponentData(const ComponentBase* compbase, Archetype* fromArch, Archetype* toArch, size_t i, size_t j, size_t entityIndex) {
    const std::size_t compSize = compbase->GetSize();
    std::size_t currentSize = toArch->entityIds.size() * compSize;

    compbase->MoveData(&fromArch->componentData[j][entityIndex * compSize],
        &toArch->componentData[i][currentSize]);

    compbase->DestroyData(&fromArch->componentData[j][entityIndex * compSize]);
}

void ECS::RemoveAndAllocateComponentData(const ComponentBase* compbase, Archetype* fromArch, Archetype* toArch, size_t i, size_t j, size_t entityIndex) {
    const std::size_t compSize = compbase->GetSize();
    std::size_t currentSize = toArch->entityIds.size() * compSize;
    const auto lastEntity = fromArch->entityIds.size() - 1;

    compbase->MoveData(&fromArch->componentData[j][entityIndex * compSize],
        &toArch->componentData[i][currentSize]);

    if (entityIndex != lastEntity) {
        compbase->MoveData(&fromArch->componentData[j][lastEntity * compSize],
            &fromArch->componentData[j][entityIndex * compSize]);
    }

    compbase->DestroyData(&fromArch->componentData[j][lastEntity * compSize]);
}