diff --git a/Source/FeatureHelpers/PlayedSounds.h b/Source/FeatureHelpers/PlayedSounds.h index 7da4a9bc5db..9d13da509f1 100644 --- a/Source/FeatureHelpers/PlayedSounds.h +++ b/Source/FeatureHelpers/PlayedSounds.h @@ -11,12 +11,13 @@ #include #include #include "PlayedSound.h" +#include class PlayedSounds { public: void removeExpiredSounds(float curtime, float lifetime) noexcept { - for (std::size_t i = 0; i < numberOfSounds;) { + for (std::size_t i = 0; i < sounds.getSize();) { auto& sound = sounds[i]; if (!sound.isAlive(curtime, lifetime)) removeSound(sound); @@ -53,29 +54,27 @@ class PlayedSounds { if (!predicate(std::string_view{buffer.data()})) continue; - if (std::ranges::find(sounds.begin(), sounds.begin() + numberOfSounds, channel.guid, &PlayedSound::guid) != sounds.begin() + numberOfSounds) + if (std::ranges::find(sounds, channel.guid, &PlayedSound::guid) != sounds.end()) continue; - if (numberOfSounds < sounds.size()) - sounds[numberOfSounds++] = PlayedSound{ .guid = channel.guid, .spawnTime = curtime, .origin = channelInfo2.memory[i].origin }; + sounds.pushBack(PlayedSound{ .guid = channel.guid, .spawnTime = curtime, .origin = channelInfo2.memory[i].origin }); } } template void forEach(F&& f) const noexcept { - std::for_each_n(sounds.cbegin(), numberOfSounds, std::forward(f)); + std::ranges::for_each(sounds, std::forward(f)); } private: void removeSound(PlayedSound& sound) noexcept { - sound = sounds[numberOfSounds - 1]; - --numberOfSounds; + sound = sounds.back(); + sounds.popBack(); } cs2::SoundChannels** soundChannels{ SoundSystemPatterns::soundChannels() }; cs2::CBaseFileSystem** fileSystem{ FileSystemPatterns::fileSystem() }; - std::array sounds; // TODO: dynamically allocate - std::size_t numberOfSounds{0}; + DynamicArray sounds; }; diff --git a/Source/Osiris.vcxproj b/Source/Osiris.vcxproj index a0154c9a210..444a3bd00a4 100644 --- a/Source/Osiris.vcxproj +++ b/Source/Osiris.vcxproj @@ -169,6 +169,7 @@ + diff --git a/Source/Osiris.vcxproj.filters b/Source/Osiris.vcxproj.filters index 2e42f78c8b0..d5dc11d557b 100644 --- a/Source/Osiris.vcxproj.filters +++ b/Source/Osiris.vcxproj.filters @@ -621,6 +621,9 @@ FeatureHelpers + + Utils + diff --git a/Source/Utils/DynamicArray.h b/Source/Utils/DynamicArray.h new file mode 100644 index 00000000000..a4109f96777 --- /dev/null +++ b/Source/Utils/DynamicArray.h @@ -0,0 +1,126 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include + +template + requires std::is_trivially_copyable_v +class DynamicArray { +public: + DynamicArray() = default; + DynamicArray(DynamicArray&&) = delete; + DynamicArray(const DynamicArray&) = delete; + DynamicArray& operator=(DynamicArray&&) = delete; + DynamicArray& operator=(const DynamicArray&) = delete; + + [[nodiscard]] T* begin() noexcept + { + return memory.get(); + } + + [[nodiscard]] T* end() noexcept + { + return memory.get() + size; + } + + [[nodiscard]] const T* begin() const noexcept + { + return memory.get(); + } + + [[nodiscard]] const T* end() const noexcept + { + return memory.get() + size; + } + + [[nodiscard]] std::size_t getCapacity() const noexcept + { + return memory.get_deleter().getNumberOfElements(); + } + + [[nodiscard]] std::size_t getSize() const noexcept + { + return size; + } + + [[nodiscard]] T& operator[](std::size_t index) noexcept + { + assert(index < size); + return memory.get()[index]; + } + + bool pushBack(const T& value) noexcept + { + if (ensureCapacityForNewElement()) [[likely]] { + new (memory.get() + size) T{ value }; + ++size; + return true; + } + return false; + } + + [[nodiscard]] T& back() noexcept + { + assert(size > 0); + return memory.get()[size - 1]; + } + + void popBack() noexcept + { + assert(size > 0); + std::destroy_at(&back()); + --size; + } + +private: + [[nodiscard]] static std::size_t calculateNewCapacity(std::size_t currentCapacity) noexcept + { + return currentCapacity + currentCapacity / 2 + 1; + } + + [[nodiscard]] std::size_t calculateNewCapacity() const noexcept + { + return calculateNewCapacity(getCapacity()); + } + + [[nodiscard]] bool ensureCapacityForNewElement() noexcept + { + return size < getCapacity() || growMemory(calculateNewCapacity()); + } + + [[nodiscard]] bool growMemory(std::size_t newCapacity) noexcept + { + assert(newCapacity > getCapacity()); + if (const auto newMemory = createNewMemory(newCapacity)) { + memory.reset(newMemory); + memory.get_deleter() = MemoryDeleter(newCapacity); + return true; + } + return false; + } + + [[nodiscard]] T* createNewMemory(std::size_t newCapacity) const noexcept + { + if (const auto newMemory = MemoryAllocator::allocate(newCapacity)) { + copyMemoryTo(newMemory); + return reinterpret_cast(newMemory); + } + return nullptr; + } + + void copyMemoryTo(std::byte* newMemory) const noexcept + { + if (size > 0) + std::memcpy(newMemory, memory.get(), size * sizeof(T)); + } + + UniquePtr memory; + std::size_t size{0}; +};