Files
Z3D/source/assets/data_stores/shader_source_store.ipp
2025-04-01 21:51:56 +02:00

348 lines
8.7 KiB
C++

#ifndef INCLUDE_SHADER_SOURCE_STORE_IMPLEMENTATION
# error Never include this file directly include 'shader_source_store.hpp'
#endif
#include <vector>
#include <span>
#include <tuple>
#include <cstddef>
#include <type_traits>
#include <algorithm>
#include "opengl/metadata/shader_source_metadata.hpp"
template<typename Char>
assets::shader_source_store_iterator<Char>::shader_source_store_iterator(
id_iterator_type ids,
string_iterator_type strings,
length_iterator_type lengths,
metadata_iterator_type metadata,
const size_type index,
const offset_type& offset
) :
m_ids{ ids },
m_strings{ strings },
m_lengths{ lengths },
m_metadata{ metadata },
m_index{ index },
m_offset{ offset } {}
template<typename Char>
typename assets::shader_source_store_iterator<Char>::reference assets::shader_source_store_iterator<Char>::operator*() const {
return dereference();
}
template<typename Char>
assets::shader_source_store_iterator<Char>& assets::shader_source_store_iterator<Char>::operator++() {
calc_offset(1);
++m_index;
return *this;
}
template<typename Char>
assets::shader_source_store_iterator<Char> assets::shader_source_store_iterator<Char>::operator++(int) {
shader_source_store_iterator tmp = *this;
++(*this);
return tmp;
}
template<typename Char>
assets::shader_source_store_iterator<Char>& assets::shader_source_store_iterator<Char>::operator--() {
calc_offset(-1);
--m_index;
return *this;
}
template<typename Char>
assets::shader_source_store_iterator<Char> assets::shader_source_store_iterator<Char>::operator--(int) {
auto tmp = *this;
--(*this);
return tmp;
}
template<typename Char>
assets::shader_source_store_iterator<Char>& assets::shader_source_store_iterator<Char>::operator+=(const difference_type n)
{
calc_offset(n);
m_index += n;
return *this;
}
template<typename Char>
assets::shader_source_store_iterator<Char>& assets::shader_source_store_iterator<Char>::operator-=(const difference_type n)
{
return (*this) += -n;
}
template<typename Char>
assets::shader_source_store_iterator<Char> assets::shader_source_store_iterator<Char>::operator+(const difference_type n) const
{
auto tmp = *this;
return tmp += n; // TODO clion says n is unused
}
template<typename Char>
assets::shader_source_store_iterator<Char> assets::shader_source_store_iterator<Char>::operator-(const difference_type n) const
{
auto tmp = *this;
return tmp -= n; // TODO clion says n is unused
}
template<typename Char>
typename assets::shader_source_store_iterator<Char>::difference_type
assets::shader_source_store_iterator<Char>::operator-(const shader_source_store_iterator& other) const
{
return static_cast<difference_type>(m_index) - static_cast<difference_type>(other.m_index);
}
template<typename Char>
typename assets::shader_source_store_iterator<Char>::reference assets::shader_source_store_iterator<Char>::operator[](
const difference_type n
) const {
return *(*this + n);
}
template<typename Char>
bool assets::shader_source_store_iterator<Char>::operator==(const shader_source_store_iterator& other) const
{
return m_ids == other.m_ids and m_index == other.m_index;
}
template<typename Char>
bool assets::shader_source_store_iterator<Char>::operator!=(const shader_source_store_iterator& other) const
{
return not (*this == other);
}
template<typename Char>
bool assets::shader_source_store_iterator<Char>::operator<(const shader_source_store_iterator& other) const
{
return m_index < other.m_index;
}
template<typename Char>
bool assets::shader_source_store_iterator<Char>::operator<=(const shader_source_store_iterator& other) const
{
return m_index <= other.m_index;
}
template<typename Char>
bool assets::shader_source_store_iterator<Char>::operator>(const shader_source_store_iterator& other) const
{
return m_index > other.m_index;
}
template<typename Char>
bool assets::shader_source_store_iterator<Char>::operator>=(const shader_source_store_iterator& other) const
{
return m_index >= other.m_index;
}
template<typename Char>
void assets::shader_source_store_iterator<Char>::calc_offset(
difference_type n
) {
const auto negative = n < difference_type{ 0 };
const auto positive = n > difference_type{ 0 };
const auto step = difference_type{ positive } - difference_type{ negative };
n = negative ? -n : n;
// TODO template optimize for single steps
while (n--)
{
const auto& count = m_lengths[m_index];
m_offset += step * count;
m_index += step;
}
}
template<typename Char>
typename assets::shader_source_store_iterator<Char>::reference
assets::shader_source_store_iterator<Char>::dereference() const
{
return std::make_pair(
m_ids[m_index],
shader_source_view{
.source = { m_strings[m_offset], m_lengths[m_index] },
.meta = m_metadata[m_index]
}
);
}
inline bool assets::shader_source_store::insert(const id_type id, const data_type& data)
{
auto lock = std::unique_lock{ m_mutex };
const auto result = find(id);
return insert(result.first, id, data);
}
inline std::pair<assets::shader_source_store::iterator, bool> assets::shader_source_store::find(id_type id)
{
auto lock = std::shared_lock{ m_mutex };
return unsafe_find(id);
}
inline std::pair<assets::shader_source_store::const_iterator, bool> assets::shader_source_store::find(id_type id) const
{
auto lock = std::shared_lock{ m_mutex };
return unsafe_find(id);
}
inline bool assets::shader_source_store::unsafe_insert(iterator it, const id_type id, const data_type& data)
{
auto lock = std::unique_lock{ m_mutex };
const auto index = it.m_index;
const auto new_entry = index == m_ids.size() or m_ids[index] != id;
auto dst_source_length = count_type{};
const auto src_source_length = data.source.size();
if (new_entry) {
m_ids.insert(m_ids.begin() + index, id);
m_lengths.insert(m_lengths.begin() + index, src_source_length);
m_metadata.insert(m_metadata.begin() + index, data.meta);
}
else
{
dst_source_length = m_lengths[index];
m_lengths[index] = src_source_length;
m_metadata[index] = data.meta;
}
const auto dst_string_it = m_strings.begin() + it.m_offset;
ztu::replace_range(
m_strings,
dst_string_it,
dst_string_it + dst_source_length,
data.source.begin(),
data.source.end()
);
if (new_entry)
{
m_strings.insert(m_strings.begin() + it.m_offset + src_source_length, '\0');
}
return new_entry;
}
inline std::pair<assets::shader_source_store::iterator, bool> assets::shader_source_store::unsafe_find(id_type id)
{
const auto it = std::ranges::lower_bound(m_ids, id);
const auto found = it != m_ids.end() and *it == id;
const auto index = std::distance(m_ids.begin(), it);
return { begin() + index, found };
}
inline std::pair<assets::shader_source_store::const_iterator, bool> assets::shader_source_store::unsafe_find(id_type id) const
{
const auto it = std::ranges::lower_bound(m_ids, id);
const auto found = it != m_ids.end() and *it == id;
const auto index = std::distance(m_ids.begin(), it);
return { begin() + index, found };
}
void assets::shader_source_store::remove(const iterator& it)
{
auto lock = std::unique_lock{ m_mutex };
const auto index = it.m_index;
m_ids.erase(m_ids.begin() + index);
const auto strings_begin = m_strings.begin() + it.m_offset;
const auto strings_end = strings_begin + it.m_lengths[it.m_index] + sizeof('\0');
m_strings.erase(strings_begin, strings_end);
m_lengths.erase(m_lengths.begin() + index);
m_metadata.erase(m_metadata.begin() + index);
}
void assets::shader_source_store::clear()
{
auto lock = std::unique_lock{ m_mutex };
m_ids.clear();
m_strings.clear();
m_lengths.clear();
m_metadata.clear();
}
std::shared_lock<std::shared_mutex> assets::shader_source_store::acquire_read_lock() const {
return std::shared_lock{ m_mutex };
}
std::unique_lock<std::shared_mutex> assets::shader_source_store::acquire_write_lock() {
return std::unique_lock{ m_mutex };
}
assets::shader_source_store::iterator assets::shader_source_store::begin()
{
return iterator{
m_ids.data(),
m_strings.data(),
m_lengths.data(),
m_metadata.data(),
0,
{}
};
}
assets::shader_source_store::iterator assets::shader_source_store::end()
{
return iterator{
m_ids.data(),
m_strings.data(),
m_lengths.data(),
m_metadata.data(),
m_lengths.size(),
m_strings.size()
};
}
assets::shader_source_store::const_iterator assets::shader_source_store::begin() const
{
return const_iterator{
m_ids.data(),
m_strings.data(),
m_lengths.data(),
m_metadata.data(),
0,
{}
};
}
assets::shader_source_store::const_iterator assets::shader_source_store::end() const
{
return const_iterator{
m_ids.data(),
m_strings.data(),
m_lengths.data(),
m_metadata.data(),
m_lengths.size(),
m_strings.size()
};
}
assets::shader_source_store::const_iterator assets::shader_source_store::cbegin() const
{
return this->begin();
}
assets::shader_source_store::const_iterator assets::shader_source_store::cend() const
{
return this->end();
}