Files
Gleb Mazovetskiy 0d19c1b773 Slightly optimize loading same-sprite monsters
For monsters with the same sprite, load the sprite from the file system only once.

Example:

```
VERBOSE: Loaded monster graphics: falspear\phall   452 KiB   x1
VERBOSE: Loaded monster graphics: skelbow\sklbw    618 KiB   x1
VERBOSE: Loaded monster graphics: skelsd\sklsr     610 KiB   x1
VERBOSE: Loaded monster graphics: goatbow\goatb    832 KiB   x1
VERBOSE: Loaded monster graphics: bat\bat          282 KiB   x2 <-- here we only load the sprite once
VERBOSE: Loaded monster graphics: rhino\rhino     1306 KiB   x1
VERBOSE: Loaded monster graphics: golem\golem      298 KiB   x1
VERBOSE:  Total monster graphics:                 4401 KiB 4684 KiB
```

Here, the bat sprite will be loaded from the MPQ only once.
For the second sprite, we simply clone the first sprite before applying TRNs.

This also reduces the size of `MonsterData` from 88 bytes to 80.

When we migrate monster data to a TSV, the sprite IDs can be generated automatically at load time.
2023-11-10 06:01:40 +00:00

104 lines
1.7 KiB
C++

#pragma once
#include <cstddef>
#include <initializer_list>
#include <memory>
#include <utility>
#include "appfat.h"
namespace devilution {
/**
* @brief A stack-allocated vector with a fixed capacity.
*
* @tparam T element type.
* @tparam N capacity.
*/
template <class T, size_t N>
class StaticVector {
public:
StaticVector() = default;
template <typename U>
StaticVector(std::initializer_list<U> elements)
{
for (auto &&element : elements) {
emplace_back(element);
}
}
[[nodiscard]] const T *begin() const
{
return &(*this)[0];
}
[[nodiscard]] const T *end() const
{
return begin() + size_;
}
[[nodiscard]] size_t size() const
{
return size_;
}
[[nodiscard]] bool empty() const
{
return size_ == 0;
}
[[nodiscard]] T &back()
{
return (*this)[size_ - 1];
}
[[nodiscard]] const T &back() const
{
return (*this)[size_ - 1];
}
template <typename... Args>
T &emplace_back(Args &&...args) // NOLINT(readability-identifier-naming)
{
assert(size_ < N);
return *::new (&data_[size_++]) T(std::forward<Args>(args)...);
}
T &operator[](std::size_t pos)
{
return *data_[pos].ptr();
}
const T &operator[](std::size_t pos) const
{
return *data_[pos].ptr();
}
~StaticVector()
{
for (std::size_t pos = 0; pos < size_; ++pos) {
std::destroy_at(data_[pos].ptr());
}
}
private:
struct AlignedStorage {
alignas(alignof(T)) std::byte data[sizeof(T)];
const T *ptr() const
{
return std::launder(reinterpret_cast<const T *>(data));
}
T *ptr()
{
return std::launder(reinterpret_cast<T *>(data));
}
};
AlignedStorage data_[N];
std::size_t size_ = 0;
};
} // namespace devilution