diff --git a/src/src/utils/EngineConfig.cpp b/src/src/utils/EngineConfig.cpp index 4f53181..285b4a6 100644 --- a/src/src/utils/EngineConfig.cpp +++ b/src/src/utils/EngineConfig.cpp @@ -3,6 +3,7 @@ EngineConfig g_engineConfig { - .lighting_enabled = false, + .lighting_enabled = true, + .version = "0.1.0", }; diff --git a/src/src/utils/EngineConfig.h b/src/src/utils/EngineConfig.h index 9957b40..67a180c 100644 --- a/src/src/utils/EngineConfig.h +++ b/src/src/utils/EngineConfig.h @@ -1,7 +1,8 @@ #pragma once - +#include #include +#include #include #include -#include +#include #include -template -class CreateVector { - static_assert(std::is_trivially_destructible_v, "CreateVector only supports trivially destructible types for max performance."); +#ifndef FV_ASSERT +#define FV_ASSERT(cond) assert(cond) +#endif - T* data_ = nullptr; +template +class FastVector { + using StorageT = typename std::aligned_storage::type; + + StorageT sbo_[SBO_CAP]; + T* data_ = reinterpret_cast(sbo_); size_t size_ = 0; - size_t capacity_ = 0; + size_t capacity_ = SBO_CAP; + bool heapAllocated_ = false; - static constexpr size_t kMinCapacity = 8; + inline void reallocate(size_t newCap) { + T* newData = reinterpret_cast(std::malloc(newCap * sizeof(T))); + if (!newData) std::abort(); - inline void grow(size_t minCapacity) { - size_t newCap = capacity_ ? capacity_ * 2 : kMinCapacity; - if (newCap < minCapacity) newCap = minCapacity; - - T* newData = (T*)std::malloc(newCap * sizeof(T)); - if (data_) { + if constexpr (std::is_trivially_copyable_v) { std::memcpy(newData, data_, size_ * sizeof(T)); - std::free(data_); + } else { + std::uninitialized_copy(data_, data_ + size_, newData); + std::destroy(data_, data_ + size_); } + + if (heapAllocated_) std::free(data_); data_ = newData; capacity_ = newCap; + heapAllocated_ = true; } public: - inline CreateVector() = default; + inline FastVector() = default; - inline ~CreateVector() { - std::free(data_); + inline ~FastVector() { + std::destroy(data_, data_ + size_); + if (heapAllocated_) std::free(data_); } - inline CreateVector(const CreateVector&) = delete; - inline CreateVector& operator=(const CreateVector&) = delete; - - inline CreateVector(CreateVector&& other) noexcept - : data_(other.data_), size_(other.size_), capacity_(other.capacity_) { - other.data_ = nullptr; - other.size_ = 0; - other.capacity_ = 0; + // Copy constructor + FastVector(const FastVector& other) { + reserve(other.size_); + if constexpr (std::is_trivially_copyable_v) { + std::memcpy(data_, other.data_, other.size_ * sizeof(T)); + } else { + std::uninitialized_copy(other.data_, other.data_ + other.size_, data_); + } + size_ = other.size_; } - inline CreateVector& operator=(CreateVector&& other) noexcept { - if (this != &other) { - std::free(data_); + // Move constructor + FastVector(FastVector&& other) noexcept { + if (other.heapAllocated_) { data_ = other.data_; size_ = other.size_; capacity_ = other.capacity_; - other.data_ = nullptr; - other.size_ = 0; - other.capacity_ = 0; + heapAllocated_ = true; + } else { + std::uninitialized_move(other.data_, other.data_ + other.size_, data_); + } + other.data_ = reinterpret_cast(other.sbo_); + other.size_ = 0; + other.capacity_ = SBO_CAP; + other.heapAllocated_ = false; + } + + // Copy assignment + FastVector& operator=(const FastVector& other) { + if (this != &other) { + clear(); + reserve(other.size_); + if constexpr (std::is_trivially_copyable_v) { + std::memcpy(data_, other.data_, other.size_ * sizeof(T)); + } else { + std::uninitialized_copy(other.data_, other.data_ + other.size_, data_); + } + size_ = other.size_; } return *this; } - inline void push_back(const T& value) { - if (size_ == capacity_) grow(size_ + 1); - data_[size_++] = value; + // Move assignment + FastVector& operator=(FastVector&& other) noexcept { + if (this != &other) { + clear(); + if (heapAllocated_) std::free(data_); + + if (other.heapAllocated_) { + data_ = other.data_; + size_ = other.size_; + capacity_ = other.capacity_; + heapAllocated_ = true; + } else { + std::uninitialized_move(other.data_, other.data_ + other.size_, data_); + } + + other.data_ = reinterpret_cast(other.sbo_); + other.size_ = 0; + other.capacity_ = SBO_CAP; + other.heapAllocated_ = false; + } + return *this; } - inline void push_back(T&& value) { - if (size_ == capacity_) grow(size_ + 1); - data_[size_++] = std::move(value); + inline void push_back(const T& val) { + if (size_ == capacity_) reallocate(capacity_ * 2); + new (data_ + size_) T(val); + ++size_; + } + + inline void push_back(T&& val) { + if (size_ == capacity_) reallocate(capacity_ * 2); + new (data_ + size_) T(std::move(val)); + ++size_; } inline void pop_back() { - assert(size_ > 0); + FV_ASSERT(size_ > 0); --size_; + std::destroy_at(data_ + size_); } inline void clear() { + std::destroy(data_, data_ + size_); size_ = 0; } + inline void reserve(size_t newCap) { + if (newCap > capacity_) reallocate(newCap); + } + inline void resize(size_t newSize) { - if (newSize > capacity_) grow(newSize); + if (newSize > capacity_) reallocate(newSize); + if (newSize > size_) { + std::uninitialized_value_construct(data_ + size_, data_ + newSize); + } else { + std::destroy(data_ + newSize, data_ + size_); + } size_ = newSize; } - inline void reserve(size_t newCap) { - if (newCap > capacity_) grow(newCap); + inline T& operator[](size_t i) { + FV_ASSERT(i < size_); + return data_[i]; } - inline T& operator[](size_t index) { - assert(index < size_); - return data_[index]; - } - - inline const T& operator[](size_t index) const { - assert(index < size_); - return data_[index]; + inline const T& operator[](size_t i) const { + FV_ASSERT(i < size_); + return data_[i]; } inline T* data() { return data_; }