Merge branch 'new-data-structures' into 'master'

New data structures

See merge request kart-krew-dev/ring-racers-internal!2498
This commit is contained in:
Eidolon 2025-03-16 19:36:05 -05:00
commit 4e13f61de5
87 changed files with 6082 additions and 538 deletions

View file

@ -76,7 +76,7 @@ Ogg::Ogg() noexcept : memory_data_(), instance_(nullptr)
{
}
Ogg::Ogg(std::vector<std::byte> data) : memory_data_(std::move(data)), instance_(nullptr)
Ogg::Ogg(Vector<std::byte> data) : memory_data_(std::move(data)), instance_(nullptr)
{
_init_with_data();
}
@ -153,8 +153,8 @@ OggComment Ogg::comment() const
stb_vorbis_comment c_comment = stb_vorbis_get_comment(instance_);
return OggComment {
std::string(c_comment.vendor),
std::vector<std::string>(c_comment.comment_list, c_comment.comment_list + c_comment.comment_list_length)};
String(c_comment.vendor),
Vector<String>(c_comment.comment_list, c_comment.comment_list + c_comment.comment_list_length)};
}
std::size_t Ogg::sample_rate() const

View file

@ -35,19 +35,19 @@ public:
struct OggComment
{
std::string vendor;
std::vector<std::string> comments;
String vendor;
Vector<String> comments;
};
class Ogg final
{
std::vector<std::byte> memory_data_;
Vector<std::byte> memory_data_;
stb_vorbis* instance_;
public:
Ogg() noexcept;
explicit Ogg(std::vector<std::byte> data);
explicit Ogg(Vector<std::byte> data);
explicit Ogg(tcb::span<std::byte> data);
Ogg(const Ogg&) = delete;
@ -77,7 +77,7 @@ private:
template <typename I, typename std::enable_if_t<srb2::io::IsInputStreamV<I>, int> = 0>
inline Ogg load_ogg(I& stream)
{
std::vector<std::byte> data = srb2::io::read_to_vec(stream);
srb2::Vector<std::byte> data = srb2::io::read_to_vec(stream);
return Ogg {std::move(data)};
}

View file

@ -126,9 +126,9 @@ void visit_tag(Visitor& visitor, io::SpanStream& stream, const TagHeader& header
stream.seek(io::SeekFrom::kStart, dest);
}
std::vector<uint8_t> read_uint8_samples_from_stream(io::SpanStream& stream, std::size_t count)
Vector<uint8_t> read_uint8_samples_from_stream(io::SpanStream& stream, std::size_t count)
{
std::vector<uint8_t> samples;
Vector<uint8_t> samples;
samples.reserve(count);
for (std::size_t i = 0; i < count; i++)
{
@ -137,9 +137,9 @@ std::vector<uint8_t> read_uint8_samples_from_stream(io::SpanStream& stream, std:
return samples;
}
std::vector<int16_t> read_int16_samples_from_stream(io::SpanStream& stream, std::size_t count)
Vector<int16_t> read_int16_samples_from_stream(io::SpanStream& stream, std::size_t count)
{
std::vector<int16_t> samples;
Vector<int16_t> samples;
samples.reserve(count);
for (std::size_t i = 0; i < count; i++)
{
@ -177,7 +177,7 @@ Wav::Wav(tcb::span<std::byte> data)
}
std::optional<FmtTag> read_fmt;
std::variant<std::vector<uint8_t>, std::vector<int16_t>> interleaved_samples;
std::variant<Vector<uint8_t>, Vector<int16_t>> interleaved_samples;
while (stream.seek(io::SeekFrom::kCurrent, 0) < riff_end)
{
@ -247,7 +247,7 @@ template <typename T>
std::size_t read_samples(
std::size_t channels,
std::size_t offset,
const std::vector<T>& samples,
const Vector<T>& samples,
tcb::span<audio::Sample<1>> buffer
) noexcept
{
@ -281,8 +281,8 @@ std::size_t read_samples(
std::size_t Wav::get_samples(std::size_t offset, tcb::span<audio::Sample<1>> buffer) const noexcept
{
auto samples_visitor = srb2::Overload {
[&](const std::vector<uint8_t>& samples) { return read_samples<uint8_t>(channels(), offset, samples, buffer); },
[&](const std::vector<int16_t>& samples)
[&](const Vector<uint8_t>& samples) { return read_samples<uint8_t>(channels(), offset, samples, buffer); },
[&](const Vector<int16_t>& samples)
{ return read_samples<int16_t>(channels(), offset, samples, buffer); }};
return std::visit(samples_visitor, interleaved_samples_);
@ -291,7 +291,7 @@ std::size_t Wav::get_samples(std::size_t offset, tcb::span<audio::Sample<1>> buf
std::size_t Wav::interleaved_length() const noexcept
{
auto samples_visitor = srb2::Overload {
[](const std::vector<uint8_t>& samples) { return samples.size(); },
[](const std::vector<int16_t>& samples) { return samples.size(); }};
[](const Vector<uint8_t>& samples) { return samples.size(); },
[](const Vector<int16_t>& samples) { return samples.size(); }};
return std::visit(samples_visitor, interleaved_samples_);
}

View file

@ -15,10 +15,10 @@
#include <cstdint>
#include <type_traits>
#include <variant>
#include <vector>
#include <tcb/span.hpp>
#include "../core/vector.hpp"
#include "../io/streams.hpp"
#include "sample.hpp"
@ -27,7 +27,7 @@ namespace srb2::audio
class Wav final
{
std::variant<std::vector<uint8_t>, std::vector<int16_t>> interleaved_samples_;
std::variant<Vector<uint8_t>, Vector<int16_t>> interleaved_samples_;
std::size_t channels_ = 1;
std::size_t sample_rate_ = 44100;
@ -46,7 +46,7 @@ public:
template <typename I, typename std::enable_if_t<srb2::io::IsInputStreamV<I>, int> = 0>
inline Wav load_wav(I& stream)
{
std::vector<std::byte> data = srb2::io::read_to_vec(stream);
Vector<std::byte> data = srb2::io::read_to_vec(stream);
return Wav {data};
}

View file

@ -50,7 +50,7 @@ Xmp<C>::Xmp() : data_(), instance_(nullptr), module_loaded_(false), looping_(fal
}
template <size_t C>
Xmp<C>::Xmp(std::vector<std::byte> data)
Xmp<C>::Xmp(Vector<std::byte> data)
: data_(std::move(data)), instance_(nullptr), module_loaded_(false), looping_(false)
{
_init();

View file

@ -15,11 +15,11 @@
#include <cstddef>
#include <exception>
#include <utility>
#include <vector>
#include <tcb/span.hpp>
#include <xmp.h>
#include "../core/vector.hpp"
#include "../io/streams.hpp"
namespace srb2::audio
@ -37,7 +37,7 @@ public:
template <size_t C>
class Xmp final
{
std::vector<std::byte> data_;
Vector<std::byte> data_;
xmp_context instance_;
bool module_loaded_;
bool looping_;
@ -45,7 +45,7 @@ class Xmp final
public:
Xmp();
explicit Xmp(std::vector<std::byte> data);
explicit Xmp(Vector<std::byte> data);
explicit Xmp(tcb::span<std::byte> data);
Xmp(const Xmp<C>&) = delete;
@ -74,7 +74,7 @@ extern template class Xmp<2>;
template <size_t C, typename I, typename std::enable_if_t<srb2::io::IsInputStreamV<I>, int> = 0>
inline Xmp<C> load_xmp(I& stream)
{
std::vector<std::byte> data = srb2::io::read_to_vec(stream);
Vector<std::byte> data = srb2::io::read_to_vec(stream);
return Xmp<C> {std::move(data)};
}

View file

@ -12,6 +12,8 @@
#include <cmath>
#include "../core/vector.hpp"
using namespace srb2;
using namespace srb2::audio;

View file

@ -14,6 +14,8 @@
#include "source.hpp"
#include "xmp.hpp"
#include "../core/vector.hpp"
namespace srb2::audio
{
@ -21,7 +23,7 @@ template <size_t C>
class XmpPlayer final : public Source<C>
{
Xmp<C> xmp_;
std::vector<std::array<int16_t, C>> buf_;
srb2::Vector<std::array<int16_t, C>> buf_;
public:
XmpPlayer(Xmp<C>&& xmp);

View file

@ -1,8 +1,17 @@
target_sources(SRB2SDL2 PRIVATE
hash_map.hpp
hash_set.cpp
hash_set.hpp
json.cpp
json.hpp
memory.cpp
memory.h
spmc_queue.hpp
static_vec.hpp
string.cpp
string.h
thread_pool.cpp
thread_pool.h
vector.cpp
vector.hpp
)

678
src/core/hash_map.hpp Normal file
View file

@ -0,0 +1,678 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Ronald "Eidolon" Kinard
// Copyright (C) 2025 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef SRB2_CORE_HASH_MAP_HPP
#define SRB2_CORE_HASH_MAP_HPP
#include <algorithm>
#include <cstdint>
#include <functional>
#include <initializer_list>
#include <memory>
#include <stdexcept>
#include <utility>
#include "../cxxutil.hpp"
namespace srb2
{
template <typename V>
class HashSet;
template <typename K, typename V>
class HashMap
{
struct Elem;
using Hasher = std::hash<K>;
using KeyEqual = std::equal_to<K>;
public:
using Entry = std::pair<K, V>;
class ConstIter;
class Iter
{
const HashMap* self_;
uint32_t bucket_;
Elem* cur_;
Iter(const HashMap* self, uint32_t bucket, Elem* cur)
: self_(self)
, bucket_(bucket)
, cur_(cur)
{}
Iter(const ConstIter& r)
: self_(r.iter_.self_)
, bucket_(r.iter_.bucket_)
, cur_(r.iter_.cur_)
{}
friend class HashMap;
friend class HashSet<K>;
friend class ConstIter;
public:
Iter() : Iter(nullptr, 0, nullptr) {}
Iter(const Iter&) = default;
Iter(Iter&&) noexcept = default;
~Iter() = default;
Iter& operator=(const Iter&) = default;
Iter& operator=(Iter&&) noexcept = default;
Entry& operator*() const noexcept { return cur_->entry; }
Entry* operator->() const noexcept { return &cur_->entry; }
bool operator==(const Iter& r) const noexcept
{
return self_ == r.self_ && bucket_ == r.bucket_ && cur_ == r.cur_;
}
bool operator!=(const Iter& r) const noexcept { return !(*this == r); }
Iter& operator++()
{
if (cur_ == nullptr)
{
return *this;
}
if (cur_->next == nullptr)
{
do
{
if (bucket_ < self_->buckets_ - 1)
{
bucket_++;
cur_ = self_->heads_[bucket_];
}
else
{
self_ = nullptr;
bucket_ = 0;
cur_ = nullptr;
return *this;
}
} while (cur_ == nullptr);
}
else
{
cur_ = cur_->next;
}
return *this;
}
Iter operator++(int)
{
Iter itr = *this;
++(*this);
return itr;
}
};
class ConstIter
{
mutable Iter iter_;
friend class HashMap;
public:
ConstIter() : iter_() {}
ConstIter(const ConstIter&) = default;
ConstIter(ConstIter&&) noexcept = default;
~ConstIter() = default;
ConstIter& operator=(const ConstIter&) = default;
ConstIter& operator=(ConstIter&&) noexcept = default;
ConstIter(const Iter& iter) : iter_(iter) {}
const Entry& operator*() const noexcept { return iter_.cur_->entry; }
const Entry* operator->() const noexcept { return &iter_.cur_->entry; }
bool operator==(const ConstIter& r) const noexcept { return iter_ == r.iter_; }
bool operator!=(const ConstIter& r) const noexcept { return !(*this == r); }
ConstIter& operator++() noexcept
{
++iter_;
return *this;
}
ConstIter operator++(int) noexcept
{
ConstIter itr = *this;
++*this;
return itr;
}
};
// iter traits
using key_type = K;
using mapped_type = V;
using value_type = Entry;
using size_type = uint32_t;
using difference_type = int64_t;
using hasher = Hasher;
using key_equal = KeyEqual;
using reference = Entry&;
using const_reference = const Entry&;
using pointer = Entry*;
using const_pointer = const Entry*;
using iterator = Iter;
using const_iterator = ConstIter;
private:
struct Elem
{
Elem* prev;
Elem* next;
Entry entry;
};
Elem** heads_ = nullptr;
size_t size_ = 0;
uint32_t buckets_;
Hasher hasher_;
KeyEqual key_equal_;
constexpr static uint32_t kDefaultBuckets = 16;
void init_buckets()
{
if (buckets_ == 0)
{
buckets_ = kDefaultBuckets;
}
std::allocator<Elem*> allocator;
heads_ = allocator.allocate(buckets_);
for (uint32_t i = 0; i < buckets_; i++)
{
heads_[i] = nullptr;
}
}
void init_if_needed()
{
if (heads_ == nullptr)
{
init_buckets();
}
}
void rehash_if_needed(size_t target_size)
{
if (target_size >= buckets_)
{
rehash(std::max<size_t>(target_size, buckets_ * 2));
}
}
friend class Iter;
friend class ConstIter;
public:
HashMap() : heads_(nullptr), size_(0), buckets_(0), hasher_(), key_equal_()
{
}
HashMap(uint32_t buckets)
: heads_(nullptr)
, size_(0)
, buckets_(buckets)
, hasher_()
, key_equal_()
{
init_buckets();
}
HashMap(const HashMap& r)
{
*this = r;
}
HashMap(HashMap&& r) noexcept
{
*this = std::move(r);
};
~HashMap()
{
clear();
}
HashMap(std::initializer_list<Entry> list) : HashMap(list.size())
{
for (auto v : list)
{
insert(v);
}
}
HashMap& operator=(const HashMap& r)
{
clear();
buckets_ = r.buckets_;
if (buckets_ == 0)
{
return *this;
}
init_buckets();
for (auto itr = r.begin(); itr != r.end(); itr++)
{
insert({itr->first, itr->second});
}
return *this;
}
HashMap& operator=(HashMap&& r) noexcept
{
std::swap(buckets_, r.buckets_);
std::swap(size_, r.size_);
std::swap(heads_, r.heads_);
std::swap(hasher_, r.hasher_);
std::swap(key_equal_, r.key_equal_);
return *this;
};
constexpr bool empty() const noexcept { return size_ == 0; }
constexpr size_t size() const noexcept { return size_; }
constexpr uint32_t buckets() const noexcept { return buckets_; }
Iter begin() noexcept
{
if (size_ == 0)
{
return end();
}
Iter ret = end();
for (uint32_t i = 0; i < buckets_; i++)
{
Elem* ptr = heads_[i];
if (ptr != nullptr)
{
ret = Iter { this, i, ptr };
break;
}
}
return ret;
}
ConstIter cbegin() const noexcept
{
ConstIter ret = end();
for (uint32_t i = 0; i < buckets_; i++)
{
Elem* ptr = heads_[i];
if (ptr != nullptr)
{
ret = ConstIter { Iter { this, i, ptr } };
break;
}
}
return ret;
}
ConstIter begin() const noexcept { return cbegin(); }
constexpr Iter end() noexcept { return Iter(); }
constexpr ConstIter cend() const noexcept { return ConstIter(); }
constexpr ConstIter end() const noexcept { return cend(); }
void clear()
{
if (heads_)
{
std::allocator<Elem> elem_allocator;
for (uint32_t i = 0; i < buckets_; i++)
{
auto itr = heads_[i];
while (itr != nullptr)
{
auto nextitr = itr->next;
itr->~Elem();
elem_allocator.deallocate(itr, 1);
itr = nextitr;
}
}
std::allocator<Elem*> buckets_allocator;
buckets_allocator.deallocate(heads_, buckets_);
}
heads_ = nullptr;
size_ = 0;
}
Iter find(const K& key)
{
if (buckets_ == 0 || heads_ == nullptr)
{
return end();
}
uint32_t bucket = (hasher_)(key) % buckets_;
for (Elem* p = heads_[bucket]; p != nullptr; p = p->next)
{
if ((key_equal_)(p->entry.first, key))
{
return Iter { this, bucket, p };
}
};
return end();
}
ConstIter find(const K& key) const
{
Iter iter = const_cast<HashMap*>(this)->find(key);
return ConstIter { iter };
}
std::pair<Iter, bool> insert(const Entry& value)
{
Entry copy = value;
return insert(std::move(copy));
}
void rehash(uint32_t count)
{
count = size_ > count ? size_ : count;
HashMap rehashed { count };
for (Iter itr = begin(); itr != end();)
{
Iter itrcopy = itr;
++itr;
uint32_t oldbucket = itrcopy.bucket_;
if (heads_[oldbucket] == itrcopy.cur_)
{
heads_[oldbucket] = nullptr;
}
itrcopy.self_ = &rehashed;
itrcopy.bucket_ = (rehashed.hasher_)(itrcopy.cur_->entry.first) % count;
Elem* p = rehashed.heads_[itrcopy.bucket_];
if (p == nullptr)
{
p = rehashed.heads_[itrcopy.bucket_] = itrcopy.cur_;
size_ -= 1;
rehashed.size_ += 1;
if (p->next)
{
p->next->prev = nullptr;
}
if (p->prev)
{
p->prev->next = nullptr;
}
p->next = nullptr;
p->prev = nullptr;
}
else
{
for (; p != nullptr; p = p->next)
{
if (p->next != nullptr)
{
continue;
}
p->next = itrcopy.cur_;
size_ -= 1;
rehashed.size_ += 1;
p->next->prev = p;
p->next->next = nullptr;
break;
}
}
}
if (heads_)
{
std::allocator<Elem*> buckets_allocator;
buckets_allocator.deallocate(heads_, buckets_);
heads_ = nullptr;
}
*this = std::move(rehashed);
}
std::pair<Iter, bool> insert(Entry&& value)
{
std::pair<Iter, bool> ret { end(), false };
std::allocator<Elem> allocator;
init_if_needed();
rehash_if_needed(size_ + 1);
uint32_t bucket = (hasher_)(value.first) % buckets_;
Elem* p = heads_[bucket];
if (p == nullptr)
{
// Make a new slot
ret.second = true;
Elem* newslot = allocator.allocate(1);
newslot->prev = nullptr;
newslot->next = nullptr;
heads_[bucket] = newslot;
new (&newslot->entry) Entry { std::move(value) };
size_++;
ret.first = Iter { this, bucket, newslot };
return ret;
}
for(; p != nullptr;)
{
if ((key_equal_)(p->entry.first, value.first))
{
ret.second = false;
ret.first = Iter { this, bucket, p };
return ret;
}
if (p->next == nullptr)
{
// Make a new slot
ret.second = true;
Elem* newslot = allocator.allocate(1);
newslot->prev = p;
newslot->next = nullptr;
p->next = newslot;
new (&newslot->entry) Entry { std::move(value) };
size_++;
ret.first = Iter { this, bucket, newslot };
return ret;
}
p = p->next;
}
return ret;
}
template <typename M>
std::pair<Iter, bool> insert_or_assign(const K& key, M&& value)
{
K kcopy = key;
return insert_or_assign(std::move(kcopy), std::forward<M>(value));
}
template <typename M>
std::pair<Iter, bool> insert_or_assign(K&& key, M&& value)
{
std::pair<Iter, bool> ret { find(key), false };
if (ret.first != end())
{
ret.first->second = std::forward<M>(value);
}
else
{
ret = insert({ std::move(key), std::forward<M>(value) });
}
return ret;
}
template <typename ...Args>
std::pair<Iter, bool> emplace(Args&&... args)
{
Entry entry { std::forward<Args>(args)... };
return insert(std::move(entry));
}
template <typename ...Args>
std::pair<Iter, bool> try_emplace(const K& key, Args&&... args)
{
Iter itr = find(key);
if (itr != end())
{
return { itr, false };
}
return insert({ key, V(std::forward<Args>(args)...) });
}
template <typename ...Args>
std::pair<Iter, bool> try_emplace(K&& key, Args... args)
{
std::pair<Iter, bool> ret { end(), false };
return insert({ std::move(key), V(std::forward<Args>(args)...)});
}
V& operator[](const K& key)
{
K copy { key };
return this->operator[](std::move(copy));
}
V& operator[](K&& key)
{
std::allocator<Elem> allocator;
init_if_needed();
rehash_if_needed(size_ + 1);
uint32_t bucket = (hasher_)(key) % buckets_;
Elem* p = heads_[bucket];
if (p == nullptr)
{
// Make a new slot
Elem* newslot = allocator.allocate(1);
newslot->prev = nullptr;
newslot->next = nullptr;
heads_[bucket] = newslot;
new (&newslot->entry) Entry { std::move(key), {} };
size_++;
return newslot->entry.second;
}
for (; p != nullptr;)
{
if ((key_equal_)(p->entry.first, key))
{
return p->entry.second;
}
if (p->next == nullptr)
{
// Make a new slot
Elem* newslot = allocator.allocate(1);
newslot->prev = p;
newslot->next = nullptr;
p->next = newslot;
new (&newslot->entry) Entry { std::move(key), {} };
size_++;
return newslot->entry.second;
}
p = p->next;
}
return end()->second;
}
V& at(const K& key)
{
auto itr = find(key);
if (itr == end())
{
throw std::out_of_range("key not found");
}
return itr->second;
}
const V& at(const K& key) const
{
auto itr = find(key);
if (itr == cend())
{
throw std::out_of_range("key not found");
}
return itr->second;
}
Iter erase(Iter pos)
{
Iter ret = pos;
if (pos == end())
{
return end();
}
std::allocator<Elem> allocator;
uint32_t bucket = (hasher_)(pos.cur_->entry.first) % buckets_;
Elem* p = heads_[bucket];
for (; p != nullptr;)
{
if ((key_equal_)(p->entry.first, pos.cur_->entry.first))
{
// found it; remove, return next iter
++ret;
if (p->next != nullptr)
{
p->next->prev = p->prev;
}
if (p->prev != nullptr)
{
p->prev->next = p->next;
}
if (p == heads_[bucket])
{
heads_[bucket] = p->next;
}
p->~Elem();
allocator.deallocate(p, 1);
size_ -= 1;
return ret;
}
p = p->next;
}
return ret;
}
Iter erase(ConstIter pos)
{
return erase(pos.iter_);
}
uint32_t erase(const K& key)
{
Iter pos = find(key);
if (pos != end())
{
erase(pos);
return 1;
}
return 0;
}
};
} // namespace srb2
#endif // SRB2_CORE_HASH_MAP_HPP

32
src/core/hash_set.cpp Normal file
View file

@ -0,0 +1,32 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Ronald "Eidolon" Kinard
// Copyright (C) 2025 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#include "hash_set.hpp"
#include <string>
#include "string.h"
namespace srb2
{
template class HashSet<bool>;
template class HashSet<uint8_t>;
template class HashSet<uint16_t>;
template class HashSet<uint32_t>;
template class HashSet<uint64_t>;
template class HashSet<int8_t>;
template class HashSet<int16_t>;
template class HashSet<int32_t>;
template class HashSet<int64_t>;
template class HashSet<String>;
template class HashSet<std::string>;
} // namespace srb2

214
src/core/hash_set.hpp Normal file
View file

@ -0,0 +1,214 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Ronald "Eidolon" Kinard
// Copyright (C) 2025 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef SRB2_CORE_HASH_SET_HPP
#define SRB2_CORE_HASH_SET_HPP
#include <cstdint>
#include <string>
#include "hash_map.hpp"
#include "string.h"
namespace srb2
{
template <typename V>
class HashSet
{
using Inner = HashMap<V, uint8_t>;
public:
class Iter
{
typename Inner::Iter iter_;
Iter(typename Inner::Iter iter) : iter_(iter) {}
friend class HashSet;
friend class ConstIter;
public:
Iter() = default;
Iter(const Iter&) = default;
Iter(Iter&&) noexcept = default;
~Iter() = default;
Iter& operator=(const Iter&) = default;
Iter& operator=(Iter&&) noexcept = default;
bool operator==(const Iter& r) const noexcept { return iter_ == r.iter_; }
bool operator!=(const Iter& r) const noexcept { return !(*this == r); }
V& operator*() const noexcept { return iter_->first; }
V* operator->() const noexcept { return &iter_->first; }
Iter& operator++() noexcept
{
++iter_;
return *this;
}
Iter operator++(int) noexcept
{
Iter self = *this;
++*this;
return self;
}
};
class ConstIter
{
typename Inner::ConstIter iter_;
friend class HashSet;
friend class Iter;
public:
ConstIter() = default;
ConstIter(const ConstIter&) = default;
ConstIter(ConstIter&&) noexcept = default;
~ConstIter() = default;
ConstIter(const Iter& iter) : iter_(iter.iter_) {}
ConstIter(const typename Inner::ConstIter& iter) : iter_(iter) {}
ConstIter& operator=(const ConstIter&) = default;
ConstIter& operator=(ConstIter&&) noexcept = default;
bool operator==(const ConstIter& r) const noexcept { return iter_ == r.iter_; }
bool operator!=(const ConstIter& r) const noexcept { return !(*this == r); }
const V& operator*() const noexcept { return iter_->first; }
const V* operator->() const noexcept { return &iter_->first; }
ConstIter& operator++() noexcept
{
++iter_;
return *this;
}
ConstIter operator++(int) noexcept
{
ConstIter self = *this;
++*this;
return self;
}
};
private:
Inner map_;
public:
using key_type = V;
using value_type = V;
using size_type = typename Inner::size_type;
using difference_type = typename Inner::difference_type;
using hasher = typename Inner::hasher;
using key_equal = typename Inner::key_equal;
using reference = V&;
using const_reference = const V&;
using pointer = V*;
using const_pointer = const V*;
using iterator = Iter;
using const_iterator = ConstIter;
HashSet() = default;
HashSet(const HashSet&) = default;
HashSet(HashSet&&) noexcept = default;
~HashSet() = default;
HashSet& operator=(const HashSet&) = default;
HashSet& operator=(HashSet&&) noexcept = default;
Iter begin() { return map_.begin(); }
Iter end() { return map_.end(); }
ConstIter cbegin() const { return map_.cbegin(); }
ConstIter cend() const { return map_.cend(); }
ConstIter begin() const { return cbegin(); }
ConstIter end() const { return cend(); }
bool empty() const noexcept { return map_.empty(); }
size_t size() const noexcept { return map_.size(); }
void clear() { map_.clear(); }
std::pair<Iter, bool> insert(const V& value)
{
V copy { value };
return insert(std::move(copy));
}
std::pair<Iter, bool> insert(V&& value)
{
return emplace(std::move(value));
}
template <typename ...Args>
std::pair<Iter, bool> emplace(Args&&... args)
{
std::pair<Iter, bool> res;
auto [map_iter, map_inserted] = map_.emplace(std::forward<Args&&>(args)..., 0);
res.first = map_iter;
res.second = map_inserted;
return res;
}
Iter erase(Iter pos)
{
auto map_ret = map_.erase(pos.iter_);
return map_ret;
}
Iter erase(ConstIter pos)
{
auto map_ret = map_.erase(pos.iter_);
return map_ret;
}
Iter erase(ConstIter first, ConstIter last)
{
ConstIter iter;
for (iter = first; iter != last;)
{
iter = erase(iter);
}
return typename Inner::Iter(iter.iter_);
}
Iter find(const V& value)
{
auto map_ret = map_.find(value);
return map_ret;
}
ConstIter find(const V& value) const
{
auto map_ret = map_.find(value);
return map_ret;
}
void rehash(size_t count)
{
map_.rehash(count);
}
};
extern template class HashSet<bool>;
extern template class HashSet<uint8_t>;
extern template class HashSet<uint16_t>;
extern template class HashSet<uint32_t>;
extern template class HashSet<uint64_t>;
extern template class HashSet<int8_t>;
extern template class HashSet<int16_t>;
extern template class HashSet<int32_t>;
extern template class HashSet<int64_t>;
extern template class HashSet<String>;
extern template class HashSet<std::string>;
} // namespace srb2
#endif // SRB2_CORE_HASH_SET_HPP

1809
src/core/json.cpp Normal file

File diff suppressed because it is too large Load diff

533
src/core/json.hpp Normal file
View file

@ -0,0 +1,533 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Ronald "Eidolon" Kinard
// Copyright (C) 2025 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef SRB2_CORE_JSON_HPP
#define SRB2_CORE_JSON_HPP
#include <array>
#include <cstdint>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <vector>
#include <tcb/span.hpp>
#include "hash_map.hpp"
#include "string.h"
#include "vector.hpp"
#include "json_macro.inl"
namespace srb2
{
class JsonValue;
using JsonArray = Vector<JsonValue>;
using JsonObject = HashMap<String, JsonValue>;
class JsonError : public std::runtime_error
{
public:
JsonError(const std::string& what);
JsonError(const char* what);
JsonError(const JsonError&) noexcept;
};
class JsonParseError : public JsonError
{
public:
JsonParseError(const std::string& what);
JsonParseError(const char* what);
JsonParseError(const JsonParseError&) noexcept;
};
class JsonValue
{
public:
enum class Type : int
{
kNull,
kBoolean,
kNumber,
kString,
kArray,
kObject
};
private:
Type type_;
union {
struct {} dummy;
bool boolean_;
double number_;
String string_;
JsonArray array_;
JsonObject object_;
};
static void value_to_ubjson(srb2::Vector<std::byte>& out);
static void value_to_ubjson(srb2::Vector<std::byte>& out, bool value);
static void value_to_ubjson(srb2::Vector<std::byte>& out, double value);
static void value_to_ubjson(srb2::Vector<std::byte>& out, uint64_t value);
static void value_to_ubjson(srb2::Vector<std::byte>& out, const String& value, bool include_type);
static void value_to_ubjson(srb2::Vector<std::byte>& out, const JsonArray& value);
static void value_to_ubjson(srb2::Vector<std::byte>& out, const JsonObject& value);
void do_to_ubjson(srb2::Vector<std::byte>& out) const;
public:
JsonValue();
JsonValue(const JsonValue&);
JsonValue(JsonValue&&) noexcept;
~JsonValue();
JsonValue& operator=(const JsonValue&);
JsonValue& operator=(JsonValue&&) noexcept;
JsonValue(const String& value);
JsonValue(String&& value);
JsonValue(const JsonArray& value);
JsonValue(JsonArray&& value);
JsonValue(const JsonObject& value);
JsonValue(JsonObject&& value);
JsonValue(float value);
JsonValue(double value);
JsonValue(int8_t value);
JsonValue(int16_t value);
JsonValue(int32_t value);
JsonValue(int64_t value);
JsonValue(uint8_t value);
JsonValue(uint16_t value);
JsonValue(uint32_t value);
JsonValue(uint64_t value);
JsonValue(bool value);
static JsonValue array() { return JsonValue(JsonArray()); }
static JsonValue object() { return JsonValue(JsonObject()); }
bool operator==(const JsonValue& rhs) const;
bool operator!=(const JsonValue& rhs) const { return !(*this == rhs); }
void to_json(JsonValue& to) const;
void from_json(const JsonValue& from);
String to_json_string() const;
static JsonValue from_json_string(const String& str);
srb2::Vector<std::byte> to_ubjson() const;
static JsonValue from_ubjson(tcb::span<const std::byte> ubjson);
constexpr Type type() const noexcept { return type_; }
template <typename V> V get() const;
constexpr bool is_null() const noexcept { return type_ == Type::kNull; }
constexpr bool is_boolean() const noexcept { return type_ == Type::kBoolean; }
constexpr bool is_number() const noexcept { return type_ == Type::kNumber; }
constexpr bool is_string() const noexcept { return type_ == Type::kString; }
constexpr bool is_array() const noexcept { return type_ == Type::kArray; }
constexpr bool is_object() const noexcept { return type_ == Type::kObject; }
JsonArray& as_array();
JsonObject& as_object();
const JsonArray& as_array() const;
const JsonObject& as_object() const;
JsonValue& at(uint32_t i);
const JsonValue& at(uint32_t i) const;
JsonValue& at(const char* key);
JsonValue& at(const String& key);
const JsonValue& at(const char* key) const;
const JsonValue& at(const String& key) const;
template <typename V>
V value(const char* key, const V& def) const;
template <typename V>
V value(const String& key, const V& def) const;
template <typename V>
V value(const char* key, V&& def) const;
template <typename V>
V value(const String& key, V&& def) const;
bool contains(const char* key) const;
bool contains(const String& key) const;
JsonValue& operator[](uint32_t i);
JsonValue& operator[](const char* key);
JsonValue& operator[](const String& key);
};
void to_json(JsonValue& to, bool value);
void to_json(JsonValue& to, int8_t value);
void to_json(JsonValue& to, int16_t value);
void to_json(JsonValue& to, int32_t value);
void to_json(JsonValue& to, int64_t value);
void to_json(JsonValue& to, uint8_t value);
void to_json(JsonValue& to, uint16_t value);
void to_json(JsonValue& to, uint32_t value);
void to_json(JsonValue& to, uint64_t value);
void to_json(JsonValue& to, float value);
void to_json(JsonValue& to, double value);
void to_json(JsonValue& to, const String& value);
void to_json(JsonValue& to, const JsonArray& value);
void to_json(JsonValue& to, const JsonObject& value);
void from_json(const JsonValue& to, bool& value);
void from_json(const JsonValue& to, int8_t& value);
void from_json(const JsonValue& to, int16_t& value);
void from_json(const JsonValue& to, int32_t& value);
void from_json(const JsonValue& to, int64_t& value);
void from_json(const JsonValue& to, uint8_t& value);
void from_json(const JsonValue& to, uint16_t& value);
void from_json(const JsonValue& to, uint32_t& value);
void from_json(const JsonValue& to, uint64_t& value);
void from_json(const JsonValue& to, float& value);
void from_json(const JsonValue& to, double& value);
void from_json(const JsonValue& to, String& value);
void from_json(const JsonValue& to, JsonArray& value);
void from_json(const JsonValue& to, JsonObject& value);
template <typename T, size_t S>
inline void to_json(JsonValue& to, const std::array<T, S>& v)
{
JsonArray arr;
for (auto itr = v.begin(); itr != v.end(); itr++)
{
JsonValue conv;
to_json(conv, *itr);
arr.push_back(conv);
}
to = JsonValue(std::move(arr));
}
template <typename T, size_t S>
inline void from_json(const JsonValue& to, std::array<T, S>& v)
{
if (!to.is_array())
{
throw JsonError("json value must be an array");
}
const JsonArray& arr = to.as_array();
size_t si = 0;
for (auto& i : arr)
{
if (si >= v.size())
{
break;
}
T conv;
from_json(i, conv);
v[si] = std::move(conv);
si++;
}
}
template <typename T, typename A>
inline void to_json(JsonValue& to, const std::vector<T, A>& v)
{
JsonArray arr;
for (auto itr = v.begin(); itr != v.end(); itr++)
{
JsonValue conv;
to_json(conv, *itr);
arr.push_back(conv);
}
to = JsonValue(std::move(arr));
}
template <typename T, typename A>
inline void from_json(const JsonValue& to, std::vector<T, A>& v)
{
if (!to.is_array())
{
throw JsonError("json value must be an array");
}
v.clear();
const JsonArray& arr = to.as_array();
for (auto& i : arr)
{
T conv;
from_json(i, conv);
v.push_back(std::move(conv));
}
}
template <typename T>
inline void to_json(JsonValue& to, const srb2::Vector<T>& v)
{
JsonArray arr;
for (auto itr = v.begin(); itr != v.end(); itr++)
{
JsonValue conv;
to_json(conv, *itr);
arr.push_back(conv);
}
to = JsonValue(std::move(arr));
}
template <typename T>
inline void from_json(const JsonValue& to, srb2::Vector<T>& v)
{
if (!to.is_array())
{
throw JsonError("json value must be an array");
}
v.clear();
const JsonArray& arr = to.as_array();
for (auto& i : arr)
{
T conv;
from_json(i, conv);
v.push_back(std::move(conv));
}
}
template <typename K, typename V, typename H, typename E, typename A>
inline void to_json(JsonValue& to, const std::unordered_map<K, V, H, E, A>& v)
{
JsonObject obj;
for (auto itr = v.begin(); itr != v.end(); itr++)
{
to_json(obj[itr->first], itr->second);
}
to = JsonValue(std::move(obj));
}
template <typename K, typename V, typename H, typename E, typename A>
inline void from_json(const JsonValue& to, std::unordered_map<K, V, H, E, A>& v)
{
if (!to.is_object())
{
throw JsonError("json value must be an object");
}
v.clear();
const JsonObject& obj = to.as_object();
for (auto itr = obj.begin(); itr != obj.end(); itr++)
{
V conv;
from_json(itr->second, conv);
v[itr->first] = std::move(conv);
}
}
template <typename K, typename V>
inline void to_json(JsonValue& to, const srb2::HashMap<K, V>& v)
{
JsonObject obj;
for (auto itr = v.begin(); itr != v.end(); itr++)
{
to_json(obj[itr->first], itr->second);
}
to = JsonValue(std::move(obj));
}
template <typename K, typename V>
inline void from_json(const JsonValue& to, srb2::HashMap<K, V>& v)
{
if (!to.is_object())
{
throw JsonError("json value must be an object");
}
v.clear();
const JsonObject& obj = to.as_object();
for (auto itr = obj.begin(); itr != obj.end(); itr++)
{
V conv;
from_json(itr->second, conv);
v[itr->first] = std::move(conv);
}
}
void from_json(const JsonValue& to, std::string& v);
void to_json(JsonValue& to, const std::string& v);
// template <typename K, typename V>
// inline void to_json(JsonValue& to, const srb2::OAHashMap<K, V>& v)
// {
// JsonObject obj;
// for (auto itr = v.begin(); itr != v.end(); itr++)
// {
// to_json(obj[itr->first], itr->second);
// }
// to = JsonValue(std::move(obj));
// }
// template <typename K, typename V>
// inline void from_json(const JsonValue& to, srb2::OAHashMap<K, V>& v)
// {
// if (!to.is_object())
// {
// throw JsonError("json value must be an object");
// }
// v.clear();
// const JsonObject& obj = to.as_object();
// for (auto itr = obj.begin(); itr != obj.end(); itr++)
// {
// V conv;
// from_json(itr->second, conv);
// v[itr->first] = std::move(conv);
// }
// }
//
template <typename V>
inline V JsonValue::get() const
{
V v;
from_json(*this, v);
return v;
}
template <typename V>
inline V JsonValue::value(const char* key, const V& def) const
{
V copy { def };
return value(key, std::move(copy));
}
template <typename V>
inline V JsonValue::value(const String& key, const V& def) const
{
return value(key.c_str(), def);
}
template <typename V>
inline V JsonValue::value(const char* key, V&& def) const
{
const JsonObject& obj = as_object();
auto itr = obj.find(key);
if (itr != obj.end())
{
return itr->second.get<V>();
}
return def;
}
template <> bool JsonValue::get() const;
template <> int8_t JsonValue::get() const;
template <> int16_t JsonValue::get() const;
template <> int32_t JsonValue::get() const;
template <> int64_t JsonValue::get() const;
template <> uint8_t JsonValue::get() const;
template <> uint16_t JsonValue::get() const;
template <> uint32_t JsonValue::get() const;
template <> uint64_t JsonValue::get() const;
template <> float JsonValue::get() const;
template <> double JsonValue::get() const;
template <> String JsonValue::get() const;
template <> std::string JsonValue::get() const;
template <> std::string_view JsonValue::get() const;
template <> JsonArray JsonValue::get() const;
template <> JsonObject JsonValue::get() const;
template <> JsonValue JsonValue::get() const;
inline bool operator==(const JsonValue& lhs, bool rhs)
{
if (!lhs.is_boolean())
{
return false;
}
return lhs.get<bool>() == rhs;
}
inline bool operator==(const JsonValue& lhs, int64_t rhs)
{
if (!lhs.is_number())
{
return false;
}
return lhs.get<int64_t>() == rhs;
}
inline bool operator==(const JsonValue& lhs, uint64_t rhs)
{
if (!lhs.is_number())
{
return false;
}
return lhs.get<uint64_t>() == rhs;
}
inline bool operator==(const JsonValue& lhs, double rhs)
{
if (!lhs.is_number())
{
return false;
}
return lhs.get<double>() == rhs;
}
inline bool operator==(const JsonValue& lhs, std::string_view rhs)
{
if (!lhs.is_string())
{
return false;
}
return lhs.get<std::string_view>() == rhs;
}
inline bool operator==(const JsonValue& lhs, const JsonArray& rhs)
{
if (!lhs.is_array())
{
return false;
}
return lhs.as_array() == rhs;
}
inline bool operator==(const JsonValue& lhs, const JsonObject& rhs)
{
if (!lhs.is_object())
{
return false;
}
return lhs.as_object() == rhs;
}
inline bool operator!=(const JsonValue& lhs, bool rhs)
{
return !(lhs == rhs);
}
inline bool operator!=(const JsonValue& lhs, int64_t rhs)
{
return !(lhs == rhs);
}
inline bool operator!=(const JsonValue& lhs, uint64_t rhs)
{
return !(lhs == rhs);
}
inline bool operator!=(const JsonValue& lhs, double rhs)
{
return !(lhs == rhs);
}
inline bool operator!=(const JsonValue& lhs, std::string_view rhs)
{
return !(lhs == rhs);
}
inline bool operator!=(const JsonValue& lhs, const JsonArray& rhs)
{
return !(lhs == rhs);
}
inline bool operator!=(const JsonValue& lhs, const JsonObject& rhs)
{
return !(lhs == rhs);
}
extern template class Vector<srb2::JsonValue>;
extern template class HashMap<String, srb2::JsonValue>;
} // namespace srb2
#endif // SRB2_CORE_JSON_HPP

185
src/core/json_macro.inl Normal file
View file

@ -0,0 +1,185 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson <evan@nemerson.com>
// SPDX-License-Identifier: MIT
// file: macro_scope.hpp
// This file is derived from nlohmman json's codegen macros and thus is provided under its license.
#define SRB2_JSON_EXPAND( x ) x
#define SRB2_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME
#define SRB2_JSON_PASTE(...) SRB2_JSON_EXPAND(SRB2_JSON_GET_MACRO(__VA_ARGS__, \
SRB2_JSON_PASTE64, \
SRB2_JSON_PASTE63, \
SRB2_JSON_PASTE62, \
SRB2_JSON_PASTE61, \
SRB2_JSON_PASTE60, \
SRB2_JSON_PASTE59, \
SRB2_JSON_PASTE58, \
SRB2_JSON_PASTE57, \
SRB2_JSON_PASTE56, \
SRB2_JSON_PASTE55, \
SRB2_JSON_PASTE54, \
SRB2_JSON_PASTE53, \
SRB2_JSON_PASTE52, \
SRB2_JSON_PASTE51, \
SRB2_JSON_PASTE50, \
SRB2_JSON_PASTE49, \
SRB2_JSON_PASTE48, \
SRB2_JSON_PASTE47, \
SRB2_JSON_PASTE46, \
SRB2_JSON_PASTE45, \
SRB2_JSON_PASTE44, \
SRB2_JSON_PASTE43, \
SRB2_JSON_PASTE42, \
SRB2_JSON_PASTE41, \
SRB2_JSON_PASTE40, \
SRB2_JSON_PASTE39, \
SRB2_JSON_PASTE38, \
SRB2_JSON_PASTE37, \
SRB2_JSON_PASTE36, \
SRB2_JSON_PASTE35, \
SRB2_JSON_PASTE34, \
SRB2_JSON_PASTE33, \
SRB2_JSON_PASTE32, \
SRB2_JSON_PASTE31, \
SRB2_JSON_PASTE30, \
SRB2_JSON_PASTE29, \
SRB2_JSON_PASTE28, \
SRB2_JSON_PASTE27, \
SRB2_JSON_PASTE26, \
SRB2_JSON_PASTE25, \
SRB2_JSON_PASTE24, \
SRB2_JSON_PASTE23, \
SRB2_JSON_PASTE22, \
SRB2_JSON_PASTE21, \
SRB2_JSON_PASTE20, \
SRB2_JSON_PASTE19, \
SRB2_JSON_PASTE18, \
SRB2_JSON_PASTE17, \
SRB2_JSON_PASTE16, \
SRB2_JSON_PASTE15, \
SRB2_JSON_PASTE14, \
SRB2_JSON_PASTE13, \
SRB2_JSON_PASTE12, \
SRB2_JSON_PASTE11, \
SRB2_JSON_PASTE10, \
SRB2_JSON_PASTE9, \
SRB2_JSON_PASTE8, \
SRB2_JSON_PASTE7, \
SRB2_JSON_PASTE6, \
SRB2_JSON_PASTE5, \
SRB2_JSON_PASTE4, \
SRB2_JSON_PASTE3, \
SRB2_JSON_PASTE2, \
SRB2_JSON_PASTE1)(__VA_ARGS__))
#define SRB2_JSON_PASTE2(func, v1) func(v1)
#define SRB2_JSON_PASTE3(func, v1, v2) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE2(func, v2)
#define SRB2_JSON_PASTE4(func, v1, v2, v3) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE3(func, v2, v3)
#define SRB2_JSON_PASTE5(func, v1, v2, v3, v4) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE4(func, v2, v3, v4)
#define SRB2_JSON_PASTE6(func, v1, v2, v3, v4, v5) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE5(func, v2, v3, v4, v5)
#define SRB2_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE6(func, v2, v3, v4, v5, v6)
#define SRB2_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)
#define SRB2_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)
#define SRB2_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9)
#define SRB2_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)
#define SRB2_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)
#define SRB2_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)
#define SRB2_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)
#define SRB2_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)
#define SRB2_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)
#define SRB2_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)
#define SRB2_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)
#define SRB2_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)
#define SRB2_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)
#define SRB2_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)
#define SRB2_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)
#define SRB2_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)
#define SRB2_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)
#define SRB2_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)
#define SRB2_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)
#define SRB2_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)
#define SRB2_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)
#define SRB2_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)
#define SRB2_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)
#define SRB2_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)
#define SRB2_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)
#define SRB2_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32)
#define SRB2_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33)
#define SRB2_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34)
#define SRB2_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35)
#define SRB2_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36)
#define SRB2_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37)
#define SRB2_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38)
#define SRB2_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39)
#define SRB2_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40)
#define SRB2_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41)
#define SRB2_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42)
#define SRB2_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43)
#define SRB2_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44)
#define SRB2_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45)
#define SRB2_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46)
#define SRB2_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47)
#define SRB2_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48)
#define SRB2_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49)
#define SRB2_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50)
#define SRB2_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51)
#define SRB2_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52)
#define SRB2_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53)
#define SRB2_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54)
#define SRB2_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55)
#define SRB2_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56)
#define SRB2_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57)
#define SRB2_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58)
#define SRB2_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59)
#define SRB2_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60)
#define SRB2_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61)
#define SRB2_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62)
#define SRB2_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) SRB2_JSON_PASTE2(func, v1) SRB2_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63)
#define SRB2_JSON_TO(v1) to_json(srb2_json_j.as_object()[#v1], srb2_json_t.v1);
#define SRB2_JSON_FROM(v1) srb2_json_t.v1 = srb2_json_j.as_object().at(#v1);
#define SRB2_JSON_FROM_WITH_DEFAULT(v1) if (srb2_json_j.as_object().find(#v1) != srb2_json_j.as_object().end()) \
{ \
from_json(srb2_json_j.as_object().find(#v1)->second, srb2_json_t.v1); \
} \
else \
{ \
srb2_json_t.v1 = srb2_json_default_obj.v1; \
}
/*!
@brief macro
@def SRB2_JSON_DEFINE_TYPE_INTRUSIVE
@since version 3.9.0
*/
#define SRB2_JSON_DEFINE_TYPE_INTRUSIVE(Type, ...) \
friend void to_json(srb2::JsonValue& srb2_json_j, const Type& srb2_json_t) { srb2_json_j = srb2::JsonObject(); SRB2_JSON_EXPAND(SRB2_JSON_PASTE(SRB2_JSON_TO, __VA_ARGS__)) } \
friend void from_json(const srb2::JsonValue& srb2_json_j, Type& srb2_json_t) { SRB2_JSON_EXPAND(SRB2_JSON_PASTE(SRB2_JSON_FROM, __VA_ARGS__)) }
#define SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \
friend void to_json(srb2::JsonValue& srb2_json_j, const Type& srb2_json_t) { srb2_json_j = srb2::JsonObject(); SRB2_JSON_EXPAND(SRB2_JSON_PASTE(SRB2_JSON_TO, __VA_ARGS__)) } \
friend void from_json(const srb2::JsonValue& srb2_json_j, Type& srb2_json_t) { const Type srb2_json_default_obj{}; SRB2_JSON_EXPAND(SRB2_JSON_PASTE(SRB2_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
/*!
@brief macro
@def SRB2_JSON_DEFINE_TYPE_NON_INTRUSIVE
@since version 3.9.0
*/
#define SRB2_JSON_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \
inline void to_json(srb2::JsonValue& srb2_json_j, const Type& srb2_json_t) { SRB2_JSON_EXPAND(SRB2_JSON_PASTE(SRB2_JSON_TO, __VA_ARGS__)) } \
inline void from_json(const srb2::JsonValue& srb2_json_j, Type& srb2_json_t) { SRB2_JSON_EXPAND(SRB2_JSON_PASTE(SRB2_JSON_FROM, __VA_ARGS__)) }
/*!
@brief macro
@def SRB2_JSON_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT
@since version 3.11.0
*/
#define SRB2_JSON_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \
inline void to_json(srb2::JsonValue& srb2_json_j, const Type& srb2_json_t) { SRB2_JSON_EXPAND(SRB2_JSON_PASTE(SRB2_JSON_TO, __VA_ARGS__)) } \
inline void from_json(const srb2::JsonValue& srb2_json_j, Type& srb2_json_t) { const Type srb2_json_default_obj{}; SRB2_JSON_EXPAND(SRB2_JSON_PASTE(SRB2_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }

1125
src/core/string.cpp Normal file

File diff suppressed because it is too large Load diff

453
src/core/string.h Normal file
View file

@ -0,0 +1,453 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Ronald "Eidolon" Kinard
// Copyright (C) 2025 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef SRB2_CORE_STRING_HPP
#define SRB2_CORE_STRING_HPP
#ifdef __cplusplus
#include <cstdint>
#include <initializer_list>
#include <string>
#include <string_view>
#include <type_traits>
#include "fmt/core.h"
#include "static_vec.hpp"
#include "vector.hpp"
namespace srb2
{
class Utf8Iter
{
public:
using difference_type = size_t;
using value_type = uint32_t;
using pointer = void;
using reference = void;
using iterator_category = std::input_iterator_tag;
private:
size_t i_;
std::string_view s_;
Utf8Iter(std::string_view s, size_t i) : i_(i), s_(s) {}
friend class String;
uint32_t do_codepoint() const;
public:
Utf8Iter() = default;
Utf8Iter(const Utf8Iter&) = default;
Utf8Iter(Utf8Iter&&) noexcept = default;
~Utf8Iter() = default;
Utf8Iter& operator=(const Utf8Iter&) = default;
Utf8Iter& operator=(Utf8Iter&&) noexcept = default;
static Utf8Iter begin(std::string_view s) { return Utf8Iter(s, 0); }
static Utf8Iter end(std::string_view s) { return Utf8Iter(s, s.size()); }
bool operator==(const Utf8Iter& r) const noexcept
{
return s_ == r.s_ && i_ == r.i_;
}
bool operator!=(const Utf8Iter& r) const noexcept { return !(*this == r); }
uint32_t operator*() const { return codepoint(); }
Utf8Iter& operator++()
{
i_ += size();
return *this;
}
Utf8Iter operator++(int)
{
Utf8Iter copy = *this;
++*this;
return copy;
}
uint32_t codepoint() const;
bool valid() const;
uint8_t size() const;
};
class Utf16Iter
{
public:
using difference_type = size_t;
using value_type = uint32_t;
using pointer = void;
using reference = void;
using iterator_category = std::input_iterator_tag;
private:
size_t i_;
std::u16string_view s_;
Utf16Iter(std::u16string_view s, size_t i) : i_(i), s_(s) {}
uint32_t do_codepoint() const;
public:
Utf16Iter() = default;
Utf16Iter(const Utf16Iter&) = default;
Utf16Iter(Utf16Iter&&) noexcept = default;
~Utf16Iter() = default;
Utf16Iter& operator=(const Utf16Iter&) = default;
Utf16Iter& operator=(Utf16Iter&&) = default;
static Utf16Iter begin(std::u16string_view s) { return Utf16Iter(s, 0); }
static Utf16Iter end(std::u16string_view s) { return Utf16Iter(s, s.size()); }
bool operator==(const Utf16Iter& r) const noexcept
{
return s_ == r.s_ && i_ == r.i_;
}
bool operator!=(const Utf16Iter& r) const noexcept { return !(*this == r); }
uint32_t operator*() const { return codepoint(); }
Utf16Iter& operator++()
{
i_ += size();
return *this;
}
Utf16Iter operator++(int)
{
Utf16Iter copy = *this;
++*this;
return copy;
}
uint32_t codepoint() const;
bool valid() const { return true; } // we allow unpaired surrogates in general
uint8_t size() const;
};
class String
{
public:
using size_type = uint32_t;
using difference_type = int64_t;
using value_type = uint8_t;
using reference = uint8_t&;
using const_reference = const uint8_t&;
using pointer = uint8_t*;
using const_pointer = const uint8_t*;
using iterator = uint8_t*;
using const_iterator = const uint8_t*;
private:
srb2::Vector<uint8_t> data_;
public:
friend struct std::hash<String>;
static constexpr const size_type npos = -1;
String() = default;
String(const String&);
String(String&&) noexcept;
~String();
String& operator=(const String&);
String& operator=(String&&) noexcept;
String(const char* s);
String(const char* s, size_t len);
String(const std::string&);
explicit String(std::string_view view);
operator std::string() const;
operator std::string_view() const;
size_type size() const noexcept;
bool empty() const noexcept { return data_.empty(); }
const char* c_str() const;
uint8_t* data() noexcept { return data_.data(); }
const uint8_t* data() const noexcept { return data_.data(); }
void reserve(size_type capacity);
uint8_t* begin() noexcept;
uint8_t* end() noexcept;
const uint8_t* cbegin() const noexcept;
const uint8_t* cend() const noexcept;
const uint8_t* begin() const noexcept { return cbegin(); }
const uint8_t* end() const noexcept { return cend(); }
uint8_t& at(size_type i);
const uint8_t& at(size_type i) const;
uint8_t& operator[](size_type i) { return data_[i]; }
const uint8_t& operator[](size_type i) const { return data_[i]; }
uint8_t& front() { return data_[0]; }
const uint8_t& front() const { return data_[0]; }
uint8_t& back() { return data_[size() - 1]; }
const uint8_t& back() const { return data_[size() - 1]; }
void clear() { data_.clear(); }
String& insert(size_type index, size_type count, uint8_t ch);
String& insert(size_type index, const char* s);
String& insert(size_type index, const char* s, size_type count);
String& insert(size_type index, std::string_view str);
String& insert(size_type index, std::string_view str, size_t s_index, size_t count = npos);
iterator insert(const_iterator pos, uint8_t ch);
iterator insert(const_iterator pos, size_type count, uint8_t ch);
template <
typename InputIt,
typename std::enable_if_t<
std::is_constructible<
uint8_t,
typename std::iterator_traits<InputIt>::reference
>::value,
int
> = 0
>
iterator insert(const_iterator pos, InputIt first, InputIt last)
{
size_type offset = pos - data();
if (!empty())
{
// remove null byte
data_.pop_back();
}
auto ret = data_.insert(pos, first, last);
if (data_.size() > 0)
{
data_.push_back(0);
}
return data() + offset;
}
iterator insert(const_iterator pos, std::initializer_list<uint8_t> list);
String& erase(size_type index = 0, size_type count = npos);
iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
void push_back(uint8_t v);
void pop_back();
String& append(size_type count, uint8_t ch);
String& append(const char* s, size_type count);
String& append(const char* s);
String& append(std::string_view str);
String& append(std::string_view str, size_type pos, size_type count = npos);
template <
typename InputIt,
typename std::enable_if_t<
std::is_constructible<
uint8_t,
typename std::iterator_traits<InputIt>::reference
>::value,
int
> = 0
>
String& append(InputIt first, InputIt last)
{
if (!empty())
{
// remove null byte
data_.pop_back();
}
for (; first != last; first++)
{
data_.push_back(*first);
}
if (data_.size() > 0)
{
data_.push_back(0);
}
return *this;
}
String& append(std::initializer_list<uint8_t> ilist);
String& operator+=(std::string_view r);
String& operator+=(const char* r);
String& operator+=(uint8_t r);
String& operator+=(std::initializer_list<uint8_t> r);
String& replace(size_type pos, size_type count, std::string_view str);
String& replace(const_iterator first, const_iterator last, std::string_view str);
String& replace(size_type pos, size_type count, std::string_view str, size_t pos2, size_t count2 = -1);
String& replace(size_type pos, size_type count, const char* cstr, size_type count2);
String& replace(const_iterator first, const_iterator last, const char* cstr, size_type count2);
String& replace(size_type pos, size_type count, const char* cstr);
String& replace(const_iterator first, const_iterator last, const char* cstr);
// String& replace(size_type pos, size_type count, size_type count2, uint8_t ch);
String& replace(const_iterator first, const_iterator last, uint8_t ch);
template <
typename InputIt,
typename std::enable_if_t<
std::is_constructible<
uint8_t,
typename std::iterator_traits<InputIt>::reference
>::value,
int
> = 0
>
String& replace(const_iterator first, const_iterator last, InputIt first2, InputIt last2)
{
for (; first != last && first2 != last2; first++, first2++)
{
*const_cast<iterator>(first) = *first2;
}
return *this;
}
String& replace(const_iterator first, const_iterator last, std::initializer_list<uint8_t> ilist);
size_type copy(uint8_t* dest, size_type count, size_type pos = 0) const;
size_type copy(char* dest, size_type count, size_type pos = 0) const;
void resize(size_type count);
void resize(size_type count, uint8_t ch);
void swap(String& other) noexcept;
size_type find(const String& str, size_type pos = 0) const;
size_type find(std::string_view str, size_type pos = 0) const;
size_type find(const char* s, size_type pos, size_t count) const;
size_type find(const char* s, size_type pos = 0) const;
size_type find(uint8_t ch, size_type pos = 0) const;
size_type rfind(const String& str, size_type pos = npos) const;
size_type rfind(std::string_view str, size_type pos = npos) const;
size_type rfind(const char* s, size_type pos, size_type count) const;
size_type rfind(const char* s, size_type pos = npos) const;
size_type rfind(uint8_t ch, size_type pos = npos) const;
// size_type find_first_of(std::string_view str, size_type pos = 0) const;
// size_type find_first_of(const char* s, size_type pos, size_type count) const;
// size_type find_first_of(const char* s, size_type pos = 0) const;
// size_type find_first_of(uint8_t ch, size_type pos = 0) const;
// size_type find_first_not_of(std::string_view str, size_type pos = 0) const;
// size_type find_first_not_of(const char* s, size_type pos, size_type count) const;
// size_type find_first_not_of(const char* s, size_type pos = 0) const;
// size_type find_first_not_of(uint8_t ch, size_type pos = 0) const;
// size_type find_last_of(std::string_view str, size_type pos = npos) const;
// size_type find_last_of(const char* s, size_type pos, size_type count) const;
// size_type find_last_of(const char* s, size_type pos = npos) const;
// size_type find_last_of(uint8_t ch, size_type pos = npos) const;
// size_type find_last_not_of(std::string_view str, size_type pos = npos) const;
// size_type find_last_not_of(const char* s, size_type pos, size_type count) const;
// size_type find_last_not_of(const char* s, size_type pos = npos) const;
// size_type find_last_not_of(uint8_t ch, size_type pos = npos) const;
int compare(std::string_view str) const noexcept;
// int compare(size_type pos1, size_type count1, std::string_view str) const;
// int compare(size_type pos1, size_type count1, std::string_view str, size_type pos2, size_type count2 = npos) const;
int compare(const char* s) const;
// int compare(size_type pos1, size_type count1, const char* s) const;
// int compare(size_type pos1, size_type count1, const char* s, size_type count2) const;
String substr(size_type pos = 0, size_type count = npos) const;
// Non-STL String functions
bool valid_utf8() const noexcept;
srb2::Vector<uint16_t> to_utf16() const;
srb2::Vector<uint32_t> to_utf32() const;
size_t length_decoded() const;
Utf8Iter decode_begin() const { return Utf8Iter(*this, 0); }
Utf8Iter decode_end() const { return Utf8Iter(*this, size()); };
};
String operator+(const String& lhs, const String& rhs);
String operator+(const String& lhs, const char* rhs);
String operator+(const String& lhs, uint8_t rhs);
String operator+(const String& lhs, std::string_view view);
bool operator==(const String& lhs, const String& rhs);
bool operator==(const String& lhs, const char* rhs);
// bool operator==(const String& lhs, std::string_view rhs);
bool operator!=(const String& lhs, const String& rhs);
bool operator!=(const String& lhs, const char* rhs);
// bool operator!=(const String& lhs, std::string_view rhs);
bool operator<(const String& lhs, const String& rhs);
bool operator<(const String& lhs, const char* rhs);
// bool operator<(const String& lhs, std::string_view rhs);
bool operator<=(const String& lhs, const String& rhs);
bool operator<=(const String& lhs, const char* rhs);
// bool operator<=(const String& lhs, std::string_view rhs);
bool operator>(const String& lhs, const String& rhs);
bool operator>(const String& lhs, const char* rhs);
// bool operator>(const String& lhs, std::string_view rhs);
bool operator>=(const String& lhs, const String& rhs);
bool operator>=(const String& lhs, const char* rhs);
// bool operator>=(const String& lhs, std::string_view rhs);
Vector<uint16_t> to_utf16(std::string_view utf8);
Vector<uint32_t> to_utf32(std::string_view utf8);
srb2::StaticVec<uint8_t, 4> to_utf8(uint32_t codepoint);
template <
typename ItUTF32,
typename std::enable_if_t<
std::is_constructible<
uint32_t,
typename std::iterator_traits<ItUTF32>::reference
>::value,
int
> = 0
>
srb2::String to_utf8(ItUTF32 begin, ItUTF32 end)
{
srb2::String ret;
for (auto itr = begin; itr != end; ++itr)
{
srb2::StaticVec<uint8_t, 4> utf8 = to_utf8(*itr);
ret.append(utf8.begin(), utf8.end());
}
return ret;
}
srb2::String to_utf8(std::u32string_view utf32view);
// fmtlib
inline auto format_as(const String& str) { return fmt::string_view(static_cast<std::string_view>(str)); }
srb2::String vformat(fmt::string_view fmt, fmt::format_args args);
template <typename... T>
inline auto format(fmt::format_string<T...> fmt, T&&... args)
{
return ::srb2::vformat(fmt, fmt::vargs<T...>{{args...}});
}
} // namespace srb2
namespace std
{
template <> struct hash<srb2::String>
{
size_t operator()(const srb2::String& v);
};
} // namespace std
#endif // __cplusplus
#ifndef __cplusplus
#include <stdint.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
int Str_IsValidUTF8(const char* str);
// int Str_ToUTF16(uint16_t* dst, size_t dstlen, const char* src);
// int Str_ToUTF32(uint32_t* dst, size_t dstlen, const char* src);
uint32_t Str_NextCodepointFromUTF8(const char** itr);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // SRB2_CORE_STRING_HPP

View file

@ -14,12 +14,13 @@
#include <condition_variable>
#include <exception>
#include <mutex>
#include <string>
#include <system_error>
#include <fmt/format.h>
#include <tracy/tracy/Tracy.hpp>
#include "../core/string.h"
#include "../core/vector.hpp"
#include "../cxxutil.hpp"
#include "../m_argv.h"
@ -50,11 +51,11 @@ static void pool_executor(
std::shared_ptr<std::mutex> worker_ready_mutex,
std::shared_ptr<std::condition_variable> worker_ready_condvar,
std::shared_ptr<ThreadPool::Queue> my_wq,
std::vector<std::shared_ptr<ThreadPool::Queue>> other_wqs
srb2::Vector<std::shared_ptr<ThreadPool::Queue>> other_wqs
)
{
{
std::string thread_name = fmt::format("Thread Pool Thread {}", thread_index);
srb2::String thread_name = srb2::format("Thread Pool Thread {}", thread_index);
tracy::SetThreadName(thread_name.c_str());
}
@ -133,7 +134,7 @@ ThreadPool::ThreadPool(size_t threads)
for (size_t i = 0; i < threads; i++)
{
std::shared_ptr<Queue> my_queue = work_queues_[i];
std::vector<std::shared_ptr<Queue>> other_queues;
srb2::Vector<std::shared_ptr<Queue>> other_queues;
for (size_t j = 0; j < threads; j++)
{
// Order the other queues starting from the next adjacent worker

61
src/core/vector.cpp Normal file
View file

@ -0,0 +1,61 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Ronald "Eidolon" Kinard
// Copyright (C) 2025 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#include "vector.hpp"
#include <algorithm>
#include <cstddef>
#include <memory>
#include "string.h"
namespace srb2
{
AbstractVector::GrowResult AbstractVector::_realloc_mem(void* data, size_t size, size_t old_cap, size_t elem_size, Move move, size_t cap) noexcept
{
GrowResult ret;
std::allocator<uint8_t> allocator;
if (old_cap == 0)
{
cap = std::max<size_t>(cap, 1);
ret.data = allocator.allocate(cap * elem_size + sizeof(std::max_align_t));
ret.cap = cap;
return ret;
}
cap = std::max<size_t>(cap, old_cap * 2);
ret.data = allocator.allocate(cap * elem_size + sizeof(std::max_align_t));
(move)(ret.data, data, size);
allocator.deallocate(reinterpret_cast<uint8_t*>(data), old_cap * elem_size + sizeof(std::max_align_t));
ret.cap = cap;
return ret;
}
void AbstractVector::_free_mem(void* data, size_t cap, size_t elem_size) noexcept
{
std::allocator<uint8_t> allocator;
allocator.deallocate(reinterpret_cast<uint8_t*>(data), cap * elem_size + sizeof(std::max_align_t));
}
template class Vector<bool>;
template class Vector<std::byte>;
template class Vector<uint8_t>;
template class Vector<uint16_t>;
template class Vector<uint32_t>;
template class Vector<uint64_t>;
template class Vector<int8_t>;
template class Vector<int16_t>;
template class Vector<int32_t>;
template class Vector<int64_t>;
template class Vector<String>;
} // namespace srb2

366
src/core/vector.hpp Normal file
View file

@ -0,0 +1,366 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Ronald "Eidolon" Kinard
// Copyright (C) 2025 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef SRB2_CORE_VEC_HPP
#define SRB2_CORE_VEC_HPP
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <initializer_list>
#include <iterator>
#include <type_traits>
#include <utility>
namespace srb2
{
class AbstractVector
{
protected:
size_t size_;
size_t capacity_;
size_t elem_size_;
void* data_;
using Move = void(*)(void* dst, void* src, size_t size);
template <typename T>
static void _move(void* dst, void* src, size_t size) noexcept
{
T* d = (T*)dst;
T* s = (T*)src;
for (size_t i = 0; i < size; i++)
{
new (&d[i]) T(std::move(s[i]));
}
}
struct GrowResult
{
void* data;
size_t cap;
};
static GrowResult _realloc_mem(void* data, size_t size, size_t old_cap, size_t elem_size, Move move, size_t cap) noexcept;
static void _free_mem(void* data, size_t cap, size_t elem_size) noexcept;
template <typename T>
void _reserve_mem(size_t c) noexcept
{
if (c > capacity_)
{
GrowResult r = _realloc_mem(data_, size_, capacity_, elem_size_, _move<T>, c);
data_ = r.data;
capacity_ = r.cap;
}
}
constexpr AbstractVector() : size_(0), capacity_(0), elem_size_(0), data_(nullptr) {}
};
template <typename T>
class Vector : AbstractVector
{
public:
// iter traits
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using reference = T&;
using const_reference = const T&;
using pointer = T*;
using const_pointer = const T*;
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
Vector() : AbstractVector()
{
elem_size_ = sizeof(T);
}
Vector(const Vector& rhs) : Vector()
{
*this = rhs;
}
Vector(Vector&& rhs) noexcept : AbstractVector()
{
elem_size_ = sizeof(T);
*this = std::move(rhs);
}
~Vector()
{
if (data_)
{
for (size_type i = 0; i < size_; i++)
{
((T*)(data_))[(size_ - i - 1)].~T();
}
_free_mem(data_, capacity_, elem_size_);
}
data_ = nullptr;
}
explicit Vector(size_type capacity) : AbstractVector()
{
elem_size_ = sizeof(T);
_reserve_mem<T>(capacity);
}
Vector(std::initializer_list<T> l) : AbstractVector()
{
elem_size_ = sizeof(T);
if (l.size() == 0)
{
return;
}
_reserve_mem<T>(l.size());
for (auto itr = l.begin(); itr != l.end(); itr++)
{
emplace_back(*itr);
}
}
template <
typename It,
typename std::enable_if_t<
std::is_constructible_v<
T,
typename std::iterator_traits<It>::reference
>,
int
> = 0
>
Vector(It begin, It end) : AbstractVector()
{
elem_size_ = sizeof(T);
for (auto itr = begin; itr != end; ++itr)
{
push_back(*itr);
}
}
Vector& operator=(const Vector& rhs)
{
for (auto itr = rhs.begin(); itr != rhs.end(); itr++)
{
push_back(*itr);
}
return *this;
}
Vector& operator=(Vector&& rhs) noexcept
{
std::swap(size_, rhs.size_);
std::swap(capacity_, rhs.capacity_);
std::swap(data_, rhs.data_);
return *this;
}
constexpr size_type size() const noexcept { return size_; }
constexpr size_type capacity() const noexcept { return capacity_; }
constexpr bool empty() const noexcept { return size_ == 0; }
constexpr T* data() noexcept { return (T*) data_; }
constexpr const T* data() const noexcept { return (const T*) data_; }
constexpr T* begin() noexcept { return data(); }
constexpr const T* begin() const noexcept { return data(); }
constexpr T* end() noexcept { return data() + size(); }
constexpr const T* end() const noexcept { return data() + size(); }
constexpr const T* cbegin() const noexcept { return data(); }
constexpr const T* cend() const noexcept { return end(); }
constexpr auto rbegin() noexcept { return std::reverse_iterator(end()); }
constexpr auto rbegin() const noexcept { return std::reverse_iterator(end()); }
constexpr auto rend() noexcept { return std::reverse_iterator(begin()); }
constexpr auto rend() const noexcept { return std::reverse_iterator(begin()); }
constexpr auto crbegin() const noexcept { return rbegin(); }
constexpr auto crend() const noexcept { return rend(); }
T& front() noexcept { return data()[0]; }
const T& front() const noexcept { return data()[0]; }
T& back() noexcept { return data()[size() - 1]; }
const T& back() const noexcept { return data()[size() - 1]; }
void push_back(const T& t)
{
reserve(size() + 1);
new (&data()[size()]) T(t);
size_++;
}
void push_back(T&& t)
{
reserve(size() + 1);
new (&data()[size()]) T(std::move(t));
size_++;
}
void pop_back()
{
T* end = &data()[size() - 1];
end->~T();
size_--;
}
void clear() { for (auto& x : *this) x.~T(); size_ = 0; }
void reserve(size_type c)
{
_reserve_mem<T>(c);
}
void resize(size_type s)
{
resize(s, T());
}
void resize(size_type s, const T& value)
{
if (s <= size())
{
auto itr_begin = rbegin();
auto itr_end = std::prev(rend(), s);
size_t count_destroyed = 0;
for (auto itr = itr_begin; itr != itr_end; itr++)
{
itr->~T();
count_destroyed++;
}
size_ = s;
}
else
{
reserve(s);
size_type oldsize = size();
size_ = s;
for (auto itr = std::next(begin(), oldsize); itr != end(); itr++)
{
try
{
new (itr) T(value);
}
catch (...)
{
size_ = oldsize;
std::rethrow_exception(std::current_exception());
}
}
}
}
const T& at(size_type i) const { if (i >= size()) throw std::out_of_range("index out of range"); return data()[i]; }
T& at(size_type i) { if (i >= size()) throw std::out_of_range("index out of range"); return data()[i]; }
T& operator[](size_type i) { return data()[i]; }
const T& operator[](size_type i) const { return data()[i]; }
iterator erase(const_iterator first) { return erase(first, first + 1); }
iterator erase(const_iterator first, const_iterator last)
{
iterator firstm = const_cast<iterator>(first);
iterator lastm = const_cast<iterator>(last);
if (first == last) return firstm;
auto diff = last - first;
if (last != end()) std::move(lastm, end(), firstm);
resize(size_ - diff);
return firstm;
}
iterator insert(const_iterator pos, const T& value)
{
return insert(pos, (size_type)1, std::forward<const T&>(value));
}
iterator insert(const_iterator pos, T&& value)
{
size_type oldsize = size();
difference_type offs = pos - data();
push_back(std::move(value));
std::rotate(data() + offs, data() + oldsize, data() + size());
return data() + offs;
}
iterator insert(const_iterator pos, size_type count, const T& value)
{
size_type oldsize = size();
difference_type offs = pos - data();
reserve(oldsize + count);
T* d = data();
for (uint32_t i = 0; i < count; i++)
{
// must be copy-initialized;
// value is currently uninitialized
new ((T*)(&d[oldsize + i])) T(value);
}
size_ = oldsize + count;
std::rotate(d + offs, d + oldsize, d + (oldsize + count));
return data() + offs;
}
template <
class InputIt,
typename std::enable_if_t<
std::is_constructible<
T,
typename std::iterator_traits<InputIt>::reference
>::value,
int
> = 0
>
iterator insert(const_iterator pos, InputIt first, InputIt last)
{
size_type oldsize = size();
difference_type offs = pos - data();
size_type count = 0;
while (first != last)
{
push_back(*first);
++first;
++count;
}
std::rotate(data() + offs, data() + oldsize, data() + (oldsize + count));
return data() + offs;
}
template <typename... A>
iterator emplace(const_iterator position, A&&... args)
{
return insert(position, T(std::forward<A>(args)...));
}
template <typename... A>
T& emplace_back(A&&... args)
{
reserve(size() + 1);
new (&data()[size()]) T(std::forward<A>(args)...);
size_++;
return (*this)[size_ - 1];
}
};
class String;
extern template class Vector<bool>;
extern template class Vector<std::byte>;
extern template class Vector<uint8_t>;
extern template class Vector<uint16_t>;
extern template class Vector<uint32_t>;
extern template class Vector<uint64_t>;
extern template class Vector<int8_t>;
extern template class Vector<int16_t>;
extern template class Vector<int32_t>;
extern template class Vector<int64_t>;
extern template class Vector<String>;
} // namespace srb2
#endif // SRB2_CORE_VEC_HPP

View file

@ -16,7 +16,6 @@
#include <cstddef>
#include <tcb/span.hpp>
#include <nlohmann/json.hpp>
#include "doomdef.h"
#include "doomtype.h"
@ -50,6 +49,7 @@
#include "md5.h" // demo checksums
#include "p_saveg.h" // savebuffer_t
#include "g_party.h"
#include "core/json.hpp"
// SRB2Kart
#include "d_netfil.h" // nameonly
@ -2437,17 +2437,18 @@ void G_BeginRecording(void)
void srb2::write_current_demo_standings(const srb2::StandingsJson& standings)
{
using namespace srb2;
using json = nlohmann::json;
// TODO populate standings data
std::vector<uint8_t> ubjson = json::to_ubjson(standings);
JsonValue value { JsonObject() };
to_json(value, standings);
Vector<std::byte> ubjson = value.to_ubjson();
uint32_t bytes = ubjson.size();
WRITEUINT8(demobuf.p, DW_STANDING2);
WRITEUINT32(demobuf.p, bytes);
WRITEMEM(demobuf.p, ubjson.data(), bytes);
WRITEMEM(demobuf.p, (UINT8*)ubjson.data(), bytes);
}
void srb2::write_current_demo_end_marker()
@ -2615,12 +2616,12 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
static bool load_ubjson_standing(menudemo_t* pdemo, tcb::span<std::byte> slice, tcb::span<democharlist_t> demoskins)
{
using namespace srb2;
using json = nlohmann::json;
StandingsJson js;
try
{
js = json::from_ubjson(slice).template get<StandingsJson>();
JsonValue value { JsonValue::from_ubjson(tcb::as_bytes(slice)) };
from_json(value, js);
}
catch (...)
{

View file

@ -21,10 +21,9 @@
#ifdef __cplusplus
#include <string>
#include <vector>
#include <nlohmann/json.hpp>
#include "core/json.hpp"
#include "core/string.h"
#include "core/vector.hpp"
// Modern json formats
namespace srb2
@ -32,12 +31,12 @@ namespace srb2
struct StandingJson
{
uint8_t ranking;
std::string name;
String name;
uint8_t demoskin;
std::string skincolor;
String skincolor;
uint32_t timeorscore;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
StandingJson,
ranking,
name,
@ -48,9 +47,9 @@ struct StandingJson
};
struct StandingsJson
{
std::vector<StandingJson> standings;
Vector<StandingJson> standings;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(StandingsJson, standings)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(StandingsJson, standings)
};
void write_current_demo_standings(const StandingsJson& standings);

View file

@ -27,7 +27,6 @@
#include "z_zone.h"
namespace fs = std::filesystem;
using json = nlohmann::json;
#define GD_VERSION_MAJOR (0xBA5ED321)
#define GD_VERSION_MINOR (1)
@ -137,13 +136,13 @@ void srb2::save_ng_gamedata()
skin_t& memskin = skins[i];
auto skin = skintojson(&memskin.records);
std::string name = std::string(memskin.name);
srb2::String name { memskin.name };
ng.skins[name] = std::move(skin);
}
for (auto unloadedskin = unloadedskins; unloadedskin; unloadedskin = unloadedskin->next)
{
auto skin = skintojson(&unloadedskin->records);
std::string name = std::string(unloadedskin->name);
srb2::String name { unloadedskin->name };
ng.skins[name] = std::move(skin);
}
@ -175,13 +174,13 @@ void srb2::save_ng_gamedata()
for (int i = 0; i < nummapheaders; i++)
{
auto map = maptojson(&mapheaderinfo[i]->records);
std::string lumpname = std::string(mapheaderinfo[i]->lumpname);
srb2::String lumpname { mapheaderinfo[i]->lumpname };
ng.maps[lumpname] = std::move(map);
}
for (auto unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next)
{
auto map = maptojson(&unloadedmap->records);
std::string lumpname = std::string(unloadedmap->lumpname);
srb2::String lumpname { unloadedmap->lumpname };
ng.maps[lumpname] = std::move(map);
}
for (int i = 0; i < gamedata->numspraycans; i++)
@ -194,7 +193,7 @@ void srb2::save_ng_gamedata()
{
continue;
}
spraycan.color = std::string(skincolors[can->col].name);
spraycan.color = String(skincolors[can->col].name);
if (can->map == NEXTMAP_INVALID)
{
@ -213,7 +212,7 @@ void srb2::save_ng_gamedata()
{
continue;
}
spraycan.map = std::string(mapheader->lumpname);
spraycan.map = String(mapheader->lumpname);
ng.spraycans.emplace_back(std::move(spraycan));
}
@ -230,11 +229,11 @@ void srb2::save_ng_gamedata()
skinreference_t& skinref = windata[i].best_skin;
if (skinref.unloaded)
{
newrecords.bestskin = std::string(skinref.unloaded->name);
newrecords.bestskin = String(skinref.unloaded->name);
}
else
{
newrecords.bestskin = std::string(skins[skinref.id].name);
newrecords.bestskin = String(skins[skinref.id].name);
}
newrecords.gotemerald = windata[i].got_emerald;
@ -252,7 +251,7 @@ void srb2::save_ng_gamedata()
}
auto cupdata = cuptojson(cup->windata);
cupdata.name = std::string(cup->name);
cupdata.name = String(cup->name);
ng.cups[cupdata.name] = std::move(cupdata);
}
for (auto unloadedcup = unloadedcupheaders; unloadedcup; unloadedcup = unloadedcup->next)
@ -263,7 +262,7 @@ void srb2::save_ng_gamedata()
}
auto cupdata = cuptojson(unloadedcup->windata);
cupdata.name = std::string(unloadedcup->name);
cupdata.name = String(unloadedcup->name);
ng.cups[cupdata.name] = std::move(cupdata);
}
@ -273,17 +272,19 @@ void srb2::save_ng_gamedata()
cupheader_t* cup = gamedata->sealedswaps[i];
sealedswap.name = std::string(cup->name);
sealedswap.name = String(cup->name);
ng.sealedswaps.emplace_back(std::move(sealedswap));
}
std::string gamedataname_s {gamedatafilename};
fs::path savepath {fmt::format("{}/{}", srb2home, gamedataname_s)};
fs::path baksavepath {fmt::format("{}/{}.bak", srb2home, gamedataname_s)};
json ngdata_json = ng;
String gamedataname_s {gamedatafilename};
String savepath_string = srb2::format("{}/{}", srb2home, gamedataname_s);
String baksavepath_string = srb2::format("{}/{}.bak", srb2home, gamedataname_s);
fs::path savepath { static_cast<std::string_view>(savepath_string) };
fs::path baksavepath { static_cast<std::string_view>(srb2::format("{}/{}.bak", srb2home, gamedataname_s)) };
JsonValue ngdata_json { JsonObject() };
to_json(ngdata_json, ng);
if (fs::exists(savepath))
{
@ -300,7 +301,7 @@ void srb2::save_ng_gamedata()
try
{
std::string savepathstring = savepath.string();
String savepathstring = savepath.string();
srb2::io::FileStream file {savepathstring, srb2::io::FileStreamMode::kWrite};
// The header is necessary to validate during loading.
@ -308,7 +309,7 @@ void srb2::save_ng_gamedata()
srb2::io::write(static_cast<uint8_t>(GD_VERSION_MINOR), file); // minor/flags
srb2::io::write(static_cast<uint8_t>(gamedata->evercrashed), file); // dirty (crash recovery)
std::vector<uint8_t> ubjson = json::to_ubjson(ng);
srb2::Vector<std::byte> ubjson = ngdata_json.to_ubjson();
srb2::io::write_exact(file, tcb::as_bytes(tcb::make_span(ubjson)));
file.close();
}
@ -382,7 +383,7 @@ void srb2::load_ng_gamedata()
return;
}
std::string datapath {fmt::format("{}/{}", srb2home, gamedatafilename)};
String datapath {srb2::format("{}/{}", srb2home, gamedatafilename)};
srb2::io::BufferedInputStream<srb2::io::FileStream> bis;
try
@ -419,15 +420,13 @@ void srb2::load_ng_gamedata()
return;
}
std::vector<std::byte> remainder = srb2::io::read_to_vec(bis);
srb2::Vector<std::byte> remainder = srb2::io::read_to_vec(bis);
GamedataJson js;
try
{
// safety: std::byte repr is always uint8_t 1-byte aligned
tcb::span<uint8_t> remainder_as_u8 = tcb::span((uint8_t*)remainder.data(), remainder.size());
json parsed = json::from_ubjson(remainder_as_u8);
js = parsed.template get<GamedataJson>();
JsonValue parsed = JsonValue::from_ubjson(remainder);
from_json(parsed, js);
}
catch (const std::exception& ex)
{
@ -542,7 +541,7 @@ void srb2::load_ng_gamedata()
gamedata->challengegrid = static_cast<uint16_t*>(Z_Malloc(
(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(UINT16)),
PU_STATIC, NULL));
for (size_t i = 0; i < std::min((size_t)(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT), js.challengegrid.grid.size()); i++)
for (size_t i = 0; i < std::min<size_t>((size_t)(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT), js.challengegrid.grid.size()); i++)
{
uint16_t gridvalue = js.challengegrid.grid[i];
gamedata->challengegrid[i] = gridvalue;
@ -745,7 +744,7 @@ void srb2::load_ng_gamedata()
// Find the loaded cup
for (cup = kartcupheaders; cup; cup = cup->next)
{
std::string cupname = std::string(cup->name);
String cupname { cup->name };
if (cupname == cuppair.first)
{
break;
@ -770,7 +769,7 @@ void srb2::load_ng_gamedata()
}
for (auto unloadedskin = unloadedskins; unloadedskin; unloadedskin = unloadedskin->next)
{
std::string skinname = std::string(unloadedskin->name);
String skinname { unloadedskin->name };
if (skinname == cuppair.second.records[j].bestskin)
{
skinreference_t ref {};
@ -826,7 +825,7 @@ void srb2::load_ng_gamedata()
break;
}
std::string cupname = std::string(cup->name);
String cupname { cup->name };
if (cupname == js.sealedswaps[i].name)
{
break;

View file

@ -13,13 +13,12 @@
#ifdef __cplusplus
#include <array>
#include <cstdint>
#include <string>
#include <unordered_map>
#include <vector>
#include <nlohmann/json.hpp>
#include "core/json.hpp"
#include "core/hash_map.hpp"
#include "core/string.h"
#include "core/vector.hpp"
namespace srb2
{
@ -39,7 +38,7 @@ struct GamedataPlaytimeJson final
uint32_t statistics;
uint32_t tumble;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
GamedataPlaytimeJson,
total,
netgame,
@ -60,7 +59,7 @@ struct GamedataRingsJson final
{
uint32_t total;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataRingsJson, total)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataRingsJson, total)
};
struct GamedataRoundsJson final
@ -71,7 +70,7 @@ struct GamedataRoundsJson final
uint32_t special;
uint32_t custom;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataRoundsJson, race, battle, prisons, special, custom)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataRoundsJson, race, battle, prisons, special, custom)
};
struct GamedataChallengeKeysJson final
@ -81,7 +80,7 @@ struct GamedataChallengeKeysJson final
uint16_t keyspending;
uint16_t chaokeys;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataChallengeKeysJson, pendingkeyrounds, pendingkeyroundoffset, keyspending, chaokeys)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataChallengeKeysJson, pendingkeyrounds, pendingkeyroundoffset, keyspending, chaokeys)
};
struct GamedataMilestonesJson final
@ -98,7 +97,7 @@ struct GamedataMilestonesJson final
bool sealedswapalerted;
bool tutorialdone;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
GamedataMilestonesJson,
gonerlevel,
everloadedaddon,
@ -119,15 +118,15 @@ struct GamedataPrisonEggPickupsJson final
uint16_t thisprisoneggpickup;
uint16_t prisoneggstothispickup;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataPrisonEggPickupsJson, thisprisoneggpickup, prisoneggstothispickup)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataPrisonEggPickupsJson, thisprisoneggpickup, prisoneggstothispickup)
};
struct GamedataChallengeGridJson final
{
uint32_t width;
std::vector<uint16_t> grid;
Vector<uint16_t> grid;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataChallengeGridJson, width, grid)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataChallengeGridJson, width, grid)
};
struct GamedataSkinRecordsPlaytimeJson final
@ -140,7 +139,7 @@ struct GamedataSkinRecordsPlaytimeJson final
uint32_t custom;
uint32_t tumble;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
GamedataSkinRecordsPlaytimeJson,
total,
race,
@ -158,7 +157,7 @@ struct GamedataSkinRecordsJson final
uint32_t rounds;
GamedataSkinRecordsPlaytimeJson time;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
GamedataSkinRecordsJson,
wins,
rounds,
@ -170,7 +169,7 @@ struct GamedataSkinJson final
{
GamedataSkinRecordsJson records;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSkinJson, records)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSkinJson, records)
};
struct GamedataMapVisitedJson final
@ -181,7 +180,7 @@ struct GamedataMapVisitedJson final
bool spbattack;
bool mysticmelody;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapVisitedJson, visited, beaten, encore, spbattack, mysticmelody)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapVisitedJson, visited, beaten, encore, spbattack, mysticmelody)
};
struct GamedataMapStatsTimeAttackJson final
@ -189,7 +188,7 @@ struct GamedataMapStatsTimeAttackJson final
uint32_t besttime;
uint32_t bestlap;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapStatsTimeAttackJson, besttime, bestlap)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapStatsTimeAttackJson, besttime, bestlap)
};
struct GamedataMapStatsSpbAttackJson final
@ -197,7 +196,7 @@ struct GamedataMapStatsSpbAttackJson final
uint32_t besttime;
uint32_t bestlap;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapStatsSpbAttackJson, besttime, bestlap)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapStatsSpbAttackJson, besttime, bestlap)
};
struct GamedataMapStatsPlaytimeJson final
@ -212,7 +211,7 @@ struct GamedataMapStatsPlaytimeJson final
uint32_t timeattack;
uint32_t spbattack;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
GamedataMapStatsPlaytimeJson,
total,
netgame,
@ -232,7 +231,7 @@ struct GamedataMapStatsJson final
GamedataMapStatsSpbAttackJson spbattack;
GamedataMapStatsPlaytimeJson time;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
GamedataMapStatsJson,
timeattack,
spbattack,
@ -245,15 +244,15 @@ struct GamedataMapJson final
GamedataMapVisitedJson visited;
GamedataMapStatsJson stats;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapJson, visited, stats)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapJson, visited, stats)
};
struct GamedataSprayCanJson final
{
std::string map;
std::string color;
String map;
String color;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSprayCanJson, map, color)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSprayCanJson, map, color)
};
struct GamedataCupRecordsJson final
@ -261,24 +260,24 @@ struct GamedataCupRecordsJson final
uint8_t bestplacement;
uint8_t bestgrade;
bool gotemerald;
std::string bestskin;
String bestskin;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupRecordsJson, bestplacement, bestgrade, gotemerald, bestskin)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupRecordsJson, bestplacement, bestgrade, gotemerald, bestskin)
};
struct GamedataCupJson final
{
std::string name;
std::vector<GamedataCupRecordsJson> records;
String name;
Vector<GamedataCupRecordsJson> records;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupJson, name, records)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupJson, name, records)
};
struct GamedataSealedSwapJson final
{
std::string name;
String name;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSealedSwapJson, name)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSealedSwapJson, name)
};
struct GamedataJson final
@ -290,19 +289,19 @@ struct GamedataJson final
GamedataMilestonesJson milestones;
GamedataPrisonEggPickupsJson prisons;
uint32_t tafolderhash;
std::vector<bool> emblems;
std::vector<bool> unlockables;
std::vector<bool> unlockpending;
std::vector<bool> conditionsets;
Vector<bool> emblems;
Vector<bool> unlockables;
Vector<bool> unlockpending;
Vector<bool> conditionsets;
GamedataChallengeGridJson challengegrid;
uint32_t timesBeaten;
std::unordered_map<std::string, GamedataSkinJson> skins;
std::unordered_map<std::string, GamedataMapJson> maps;
std::vector<GamedataSprayCanJson> spraycans;
std::unordered_map<std::string, GamedataCupJson> cups;
std::vector<GamedataSealedSwapJson> sealedswaps;
HashMap<String, GamedataSkinJson> skins;
HashMap<String, GamedataMapJson> maps;
Vector<GamedataSprayCanJson> spraycans;
HashMap<String, GamedataCupJson> cups;
Vector<GamedataSealedSwapJson> sealedswaps;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
GamedataJson,
playtime,
rings,

View file

@ -85,8 +85,8 @@ void K_DrawInputDisplay(float x, float y, INT32 flags, char mode, UINT8 pid, boo
const ticcmd_t& cmd = players[displayplayers[pid]].cmd;
const boolean analog = (mode == '4' || mode == '5') ? players[displayplayers[pid]].analoginput : false;
const std::string prefix = fmt::format("PR{}", mode);
auto gfx = [&](auto format, auto&&... args) { return prefix + fmt::format(format, args...); };
srb2::String prefix = srb2::format("PR{}", mode);
auto gfx = [&](auto format, auto&&... args) { return prefix + srb2::format(format, args...); };
auto but = [&](char key, INT32 gc, UINT32 bt)
{
bool press = local ? G_PlayerInputAnalog(pid, gc, guessinput) : ((cmd.buttons & bt) == bt);

View file

@ -165,7 +165,7 @@ void K_drawSpectatorHUD(boolean director)
if (player)
{
std::string label = [player]
srb2::String label = [player]
{
if (player->flashing)
{
@ -183,7 +183,7 @@ void K_drawSpectatorHUD(boolean director)
if (cv_maxplayers.value)
{
label += fmt::format(" [{}/{}]", numingame, cv_maxplayers.value);
label += srb2::format(" [{}/{}]", numingame, cv_maxplayers.value);
}
list.insert({{label.c_str(), "<l_animated>"}});

View file

@ -13,9 +13,9 @@
#include <array>
#include <cstddef>
#include <unordered_map>
#include <vector>
#include "../core/hash_map.hpp"
#include "../core/vector.hpp"
#include "../rhi/rhi.hpp"
namespace srb2::hwr2
@ -77,10 +77,10 @@ class MainPaletteManager final
rhi::Handle<rhi::Texture> encore_lighttable_;
rhi::Handle<rhi::Texture> default_colormap_;
std::unordered_map<const uint8_t*, rhi::Handle<rhi::Texture>> colormaps_;
std::unordered_map<const uint8_t*, rhi::Handle<rhi::Texture>> lighttables_;
std::vector<const uint8_t*> colormaps_to_upload_;
std::vector<const uint8_t*> lighttables_to_upload_;
srb2::HashMap<const uint8_t*, rhi::Handle<rhi::Texture>> colormaps_;
srb2::HashMap<const uint8_t*, rhi::Handle<rhi::Texture>> lighttables_;
srb2::Vector<const uint8_t*> colormaps_to_upload_;
srb2::Vector<const uint8_t*> lighttables_to_upload_;
void upload_palette(rhi::Rhi& rhi);
void upload_lighttables(rhi::Rhi& rhi);

View file

@ -72,7 +72,7 @@ rhi::Rect srb2::hwr2::trimmed_patch_dimensions(const patch_t* patch)
return {minx, miny, static_cast<uint32_t>(maxx - minx), static_cast<uint32_t>(maxy - miny)};
}
void srb2::hwr2::convert_patch_to_trimmed_rg8_pixels(const patch_t* patch, std::vector<uint8_t>& out)
void srb2::hwr2::convert_patch_to_trimmed_rg8_pixels(const patch_t* patch, srb2::Vector<uint8_t>& out)
{
Rect trimmed_rect = srb2::hwr2::trimmed_patch_dimensions(patch);
if (trimmed_rect.w % 2 > 0)
@ -299,7 +299,7 @@ void PatchAtlasCache::pack(Rhi& rhi)
SRB2_ASSERT(ready_for_lookup());
// Upload atlased patches
std::vector<uint8_t> patch_data;
srb2::Vector<uint8_t> patch_data;
for (const patch_t* patch_to_upload : patches_to_upload_)
{
srb2::NotNull<PatchAtlas*> atlas = find_patch(patch_to_upload);

View file

@ -14,12 +14,12 @@
#include <cstdint>
#include <memory>
#include <optional>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <tcb/span.hpp>
#include "../core/hash_map.hpp"
#include "../core/hash_set.hpp"
#include "../core/vector.hpp"
#include "../r_defs.h"
#include "../rhi/rhi.hpp"
@ -55,7 +55,7 @@ private:
rhi::Handle<rhi::Texture> tex_;
uint32_t size_;
std::unordered_map<const patch_t*, Entry> entries_;
srb2::HashMap<const patch_t*, Entry> entries_;
std::unique_ptr<stbrp_context> rp_ctx {nullptr};
std::unique_ptr<stbrp_node[]> rp_nodes {nullptr};
@ -84,11 +84,11 @@ public:
/// drawing things like sprites and 2D elements.
class PatchAtlasCache
{
std::vector<PatchAtlas> atlases_;
std::unordered_map<const patch_t*, size_t> patch_lookup_;
srb2::Vector<PatchAtlas> atlases_;
srb2::HashMap<const patch_t*, size_t> patch_lookup_;
std::unordered_set<const patch_t*> patches_to_pack_;
std::unordered_set<const patch_t*> patches_to_upload_;
srb2::HashSet<const patch_t*> patches_to_pack_;
srb2::HashSet<const patch_t*> patches_to_upload_;
uint32_t tex_size_ = 2048;
size_t max_textures_ = 2;
@ -135,7 +135,7 @@ rhi::Rect trimmed_patch_dimensions(const patch_t* patch);
/// during upload, but required for the RHI device's Unpack Alignment of 4 bytes.
/// @param patch the patch to convert
/// @param out the output vector, cleared before writing.
void convert_patch_to_trimmed_rg8_pixels(const patch_t* patch, std::vector<uint8_t>& out);
void convert_patch_to_trimmed_rg8_pixels(const patch_t* patch, srb2::Vector<uint8_t>& out);
} // namespace srb2::hwr2

View file

@ -10,12 +10,11 @@
#include "postprocess_wipe.hpp"
#include <string>
#include <fmt/format.h>
#include <glm/gtc/matrix_transform.hpp>
#include <tcb/span.hpp>
#include "../core/string.h"
#include "../f_finale.h"
#include "../w_wad.h"
@ -106,7 +105,7 @@ void PostprocessWipePass::prepass(Rhi& rhi)
return;
}
std::string lumpname = fmt::format(FMT_STRING("FADE{:02d}{:02d}"), wipe_type, wipe_frame);
String lumpname = format(FMT_STRING("FADE{:02d}{:02d}"), wipe_type, wipe_frame);
lumpnum_t mask_lump = W_CheckNumForName(lumpname.c_str());
if (mask_lump == LUMPERROR)
{

View file

@ -181,7 +181,7 @@ Handle<Texture> FlatTextureManager::find_or_create_indexed(Rhi& rhi, lumpnum_t l
});
flats_.insert({lump, new_tex});
std::vector<std::array<uint8_t, 2>> flat_data;
srb2::Vector<std::array<uint8_t, 2>> flat_data;
std::size_t lump_length = W_LumpLength(lump);
flat_data.reserve(flat_size * flat_size);

View file

@ -11,10 +11,10 @@
#ifndef __SRB2_HWR2_RESOURCE_MANAGEMENT_HPP__
#define __SRB2_HWR2_RESOURCE_MANAGEMENT_HPP__
#include "../core/hash_map.hpp"
#include "../core/vector.hpp"
#include "../rhi/rhi.hpp"
#include <unordered_map>
namespace srb2::hwr2
{
@ -27,8 +27,8 @@ class PaletteManager
#endif
rhi::Handle<rhi::Texture> default_colormap_;
std::unordered_map<const uint8_t*, rhi::Handle<rhi::Texture>> colormaps_;
std::unordered_map<const uint8_t*, rhi::Handle<rhi::Texture>> lighttables_;
srb2::HashMap<const uint8_t*, rhi::Handle<rhi::Texture>> colormaps_;
srb2::HashMap<const uint8_t*, rhi::Handle<rhi::Texture>> lighttables_;
public:
PaletteManager();
@ -67,9 +67,9 @@ from patch_t.
/// @brief Manages textures corresponding to specific flats indexed by lump number.
class FlatTextureManager
{
std::unordered_map<lumpnum_t, rhi::Handle<rhi::Texture>> flats_;
std::vector<lumpnum_t> to_upload_;
std::vector<rhi::Handle<rhi::Texture>> disposed_textures_;
srb2::HashMap<lumpnum_t, rhi::Handle<rhi::Texture>> flats_;
srb2::Vector<lumpnum_t> to_upload_;
srb2::Vector<rhi::Handle<rhi::Texture>> disposed_textures_;
public:
FlatTextureManager();

View file

@ -11,11 +11,11 @@
#include "twodee_renderer.hpp"
#include <algorithm>
#include <unordered_set>
#include <stb_rect_pack.h>
#include <glm/gtc/matrix_transform.hpp>
#include "../core/hash_set.hpp"
#include "blendmode.hpp"
#include "../r_patch.h"
#include "../v_video.h"
@ -248,7 +248,7 @@ void TwodeeRenderer::flush(Rhi& rhi, Twodee& twodee)
}
// Stage 1 - command list patch detection
std::unordered_set<const patch_t*> found_patches;
srb2::HashSet<const patch_t*> found_patches;
for (const auto& list : twodee)
{
for (const auto& cmd : list.cmds)

View file

@ -12,16 +12,16 @@
#define __SRB2_IO_STREAMS_HPP__
#include <cstddef>
#include <optional>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include <tcb/span.hpp>
#include <zlib.h>
#include "../core/string.h"
#include "../core/vector.hpp"
namespace srb2::io
{
@ -484,13 +484,13 @@ inline void read_exact(SpanStream& stream, tcb::span<std::byte> buffer)
}
class VecStream {
std::vector<std::byte> vec_;
srb2::Vector<std::byte> vec_;
std::size_t head_ {0};
public:
VecStream() = default;
VecStream(const std::vector<std::byte>& vec) : vec_(vec) {}
VecStream(std::vector<std::byte>&& vec) : vec_(std::move(vec)) {}
VecStream(const srb2::Vector<std::byte>& vec) : vec_(vec) {}
VecStream(srb2::Vector<std::byte>&& vec) : vec_(std::move(vec)) {}
VecStream(const VecStream& rhs) = default;
VecStream(VecStream&& rhs) = default;
@ -549,7 +549,7 @@ public:
return head_;
}
std::vector<std::byte>& vector() { return vec_; }
srb2::Vector<std::byte>& vector() { return vec_; }
friend void read_exact(VecStream& stream, tcb::span<std::byte> buffer);
};
@ -674,7 +674,7 @@ template <typename I,
class ZlibInputStream {
I inner_;
z_stream stream_;
std::vector<std::byte> buf_;
srb2::Vector<std::byte> buf_;
std::size_t buf_head_;
bool zstream_initialized_;
bool zstream_ended_;
@ -820,7 +820,7 @@ template <typename O,
class BufferedOutputStream final
{
O inner_;
std::vector<std::byte> buf_;
srb2::Vector<std::byte> buf_;
tcb::span<const std::byte>::size_type cap_;
public:
@ -872,7 +872,7 @@ template <typename I,
class BufferedInputStream final
{
I inner_;
std::vector<std::byte> buf_;
srb2::Vector<std::byte> buf_;
tcb::span<std::byte>::size_type cap_;
public:
@ -933,7 +933,7 @@ extern template class BufferedInputStream<FileStream>;
template <typename I, typename O>
StreamSize pipe_all(I& input, O& output) {
std::vector<std::byte> buf;
srb2::Vector<std::byte> buf;
StreamSize total_written = 0;
StreamSize read_this_time = 0;
@ -951,7 +951,7 @@ StreamSize pipe_all(I& input, O& output) {
}
template <typename I>
std::vector<std::byte> read_to_vec(I& input) {
srb2::Vector<std::byte> read_to_vec(I& input) {
VecStream out;
pipe_all(input, out);
return std::move(out.vector());

View file

@ -12,13 +12,14 @@
/// \file k_bans.c
/// \brief replacement for DooM Legacy ban system
#include <fstream>
#include <stdexcept>
#include <vector>
#include <fmt/format.h>
#include <nlohmann/json.hpp>
#include <tcb/span.hpp>
#include "core/json.hpp"
#include "core/string.h"
#include "io/streams.hpp"
#include "i_tcp_detail.h" // clientaddress
#include "k_bans.h"
#include "byteptr.h" // READ/WRITE macros
@ -34,7 +35,9 @@
#include "z_zone.h"
#include "i_addrinfo.h" // I_getaddrinfo
using nlohmann::json;
using srb2::JsonArray;
using srb2::JsonObject;
using srb2::JsonValue;
static mysockaddr_t *DuplicateSockAddr(const mysockaddr_t *source)
{
@ -43,22 +46,22 @@ static mysockaddr_t *DuplicateSockAddr(const mysockaddr_t *source)
return dup;
}
static std::vector<banrecord_t> bans;
static srb2::Vector<banrecord_t> bans;
static uint8_t allZero[PUBKEYLENGTH];
static void load_bans_array_v1(json& array)
static void load_bans_array_v1(const JsonArray& array)
{
for (json& object : array)
for (const JsonValue& object : array)
{
uint8_t public_key_bin[PUBKEYLENGTH];
std::string public_key = object.at("public_key");
std::string ip_address = object.at("ip_address");
time_t expires = object.at("expires");
UINT8 subnet_mask = object.at("subnet_mask");
std::string username = object.at("username");
std::string reason = object.at("reason");
srb2::String public_key = object.at("public_key").get<srb2::String>();
srb2::String ip_address = object.at("ip_address").get<srb2::String>();
time_t expires = object.at("expires").get<int64_t>();
UINT8 subnet_mask = object.at("subnet_mask").get<UINT8>();
srb2::String username = object.at("username").get<srb2::String>();
srb2::String reason = object.at("reason").get<srb2::String>();
if (!FromPrettyRRID(public_key_bin, public_key.c_str()))
{
@ -86,16 +89,31 @@ void SV_LoadBans(void)
if (!server)
return;
json object;
JsonValue object;
srb2::String banspath { srb2::format("{}/{}", srb2home, BANFILE) };
srb2::io::BufferedInputStream<srb2::io::FileStream> bis;
try
{
srb2::io::FileStream fs { banspath, srb2::io::FileStreamMode::kRead };
bis = srb2::io::BufferedInputStream(std::move(fs));
}
catch (const srb2::io::FileStreamException& ex)
{
// file didn't open, likely doesn't exist
return;
}
try
{
std::ifstream f(va(pandf, srb2home, BANFILE));
if (f.is_open())
srb2::Vector<tcb::byte> data = srb2::io::read_to_vec(bis);
srb2::String data_s;
data_s.reserve(data.size());
for (auto b : data)
{
f >> object;
data_s.push_back(std::to_integer<char>(b));
}
object = JsonValue::from_json_string(data_s);
}
catch (const std::exception& ex)
{
@ -115,11 +133,11 @@ void SV_LoadBans(void)
{
if (object.value("version", 1) == 1)
{
json& array = object.at("bans");
JsonValue& array = object.at("bans");
if (array.is_array())
{
load_bans_array_v1(array);
load_bans_array_v1(array.as_array());
}
}
}
@ -131,31 +149,36 @@ void SV_LoadBans(void)
void SV_SaveBans(void)
{
json object = json::object();
JsonValue object = JsonValue(JsonObject());
object["version"] = 1;
json& array = object["bans"];
JsonValue& array_value = object["bans"];
array = json::array();
array_value = JsonValue(JsonArray());
JsonArray& array = array_value.as_array();
for (banrecord_t& ban : bans)
{
if (ban.deleted)
continue;
array.push_back({
array.push_back(JsonObject {
{"public_key", GetPrettyRRID(ban.public_key, false)},
{"ip_address", SOCK_AddrToStr(ban.address)},
{"subnet_mask", ban.mask},
{"expires", ban.expires},
{"expires", static_cast<int64_t>(ban.expires)},
{"username", ban.username},
{"reason", ban.reason},
});
}
srb2::String json_string = object.to_json_string();
srb2::String banfile_path = srb2::format("{}/{}", srb2home, BANFILE);
try
{
std::ofstream(va(pandf, srb2home, BANFILE)) << object;
srb2::io::FileStream fs { banfile_path, srb2::io::FileStreamMode::kWrite };
srb2::io::write_exact(fs, tcb::as_bytes(tcb::span(json_string)));
}
catch (const std::exception& ex)
{
@ -345,10 +368,10 @@ static void SV_BanSearch(boolean remove)
const char* stringaddress = SOCK_AddrToStr(ban.address);
const char* stringkey = GetPrettyRRID(ban.public_key, true);
std::string recordprint = fmt::format(
srb2::String recordprint = srb2::format(
"{}{} - {} [{}] - {}",
stringaddress,
ban.mask && ban.mask != 32 ? fmt::format("/{}", ban.mask) : "",
ban.mask && ban.mask != 32 ? srb2::format("/{}", ban.mask) : "",
ban.username,
stringkey,
ban.reason
@ -359,7 +382,7 @@ static void SV_BanSearch(boolean remove)
if (ban.expires < now)
recordprint += " - EXPIRED";
else
recordprint += fmt::format(" - expires {}m", (ban.expires - now)/60);
recordprint += srb2::format(" - expires {}m", (ban.expires - now)/60);
}
CONS_Printf("%s\n", recordprint.c_str());

View file

@ -12,11 +12,8 @@
#include "k_credits.h"
#include <string>
#include <vector>
#include <algorithm>
#include <fmt/format.h>
#include <nlohmann/json.hpp>
#include "doomdef.h"
#include "doomstat.h"
@ -59,7 +56,9 @@
#include "r_main.h"
#include "m_easing.h"
using nlohmann::json;
using srb2::JsonArray;
using srb2::JsonObject;
using srb2::JsonValue;
enum credits_slide_types_e
{
@ -75,14 +74,14 @@ enum credits_slide_types_e
struct credits_slide_s
{
credits_slide_types_e type;
std::string label;
std::vector<std::string> strings;
srb2::String label;
srb2::Vector<srb2::String> strings;
size_t strings_height;
boolean play_demo_afterwards;
int fade_out_music;
};
static std::vector<struct credits_slide_s> g_credits_slides;
static srb2::Vector<struct credits_slide_s> g_credits_slides;
struct credits_star_s
{
@ -94,10 +93,10 @@ struct credits_star_s
static struct credits_s
{
size_t current_slide;
std::vector<UINT16> demo_maps;
srb2::Vector<UINT16> demo_maps;
boolean skip;
std::vector<struct credits_star_s> stars;
srb2::Vector<struct credits_star_s> stars;
fixed_t transition;
fixed_t transition_prev;
@ -105,7 +104,7 @@ static struct credits_s
tic_t animation_timer;
std::vector<std::vector<std::string>> split_slide_strings;
srb2::Vector<srb2::Vector<srb2::String>> split_slide_strings;
size_t split_slide_id;
tic_t split_slide_delay;
@ -142,12 +141,14 @@ void F_LoadCreditsDefinitions(void)
size_t credits_lump_len = W_LumpLength(credits_lump_id);
const char *credits_lump = static_cast<const char *>( W_CacheLumpNum(credits_lump_id, PU_CACHE) );
json credits_array = json::parse(credits_lump, credits_lump + credits_lump_len);
if (credits_array.is_array() == false)
srb2::String json_string { credits_lump, credits_lump_len };
JsonValue credits_parsed = JsonValue::from_json_string(json_string);
if (credits_parsed.is_array() == false)
{
I_Error("credits_def parse error: Not a JSON array");
return;
}
JsonArray credits_array = credits_parsed.as_array();
if (credits_array.size() == 0)
{
@ -156,11 +157,11 @@ void F_LoadCreditsDefinitions(void)
try
{
for (json& slide_obj : credits_array)
for (JsonValue& slide_obj : credits_array)
{
struct credits_slide_s slide;
std::string type_str = slide_obj.value("type", "scroll");
srb2::String type_str = slide_obj.value("type", srb2::String("scroll"));
if (type_str == "scroll")
{
@ -196,18 +197,19 @@ void F_LoadCreditsDefinitions(void)
throw std::runtime_error("unexpected type name '" + type_str + "'");
}
slide.label = slide_obj.value("label", "");
slide.label = slide_obj.value("label", srb2::String(""));
slide.strings_height = 0;
if (slide_obj.contains("strings"))
{
json strings_array = slide_obj.at("strings");
if (strings_array.is_array() == true)
JsonValue strings_value = slide_obj.at("strings");
if (strings_value.is_array() == true)
{
JsonArray& strings_array = strings_value.as_array();
for (size_t i = 0; i < strings_array.size(); i++)
{
slide.strings.push_back( strings_array.at(i) );
slide.strings.push_back( strings_array.at(i).get<srb2::String>() );
if (slide.type == CRED_TYPE_SCROLL)
{
@ -289,7 +291,7 @@ static void F_InitCreditsSlide(void)
size_t max_strings_per_screen = (num_strings - 1) / num_sub_screens + 1;
size_t str_id = 0;
std::vector<std::string> screen_strings;
srb2::Vector<srb2::String> screen_strings;
if (max_strings_per_screen == kMaxSlideStrings
&& num_strings % kMaxSlideStrings == 1)
@ -342,24 +344,24 @@ static void F_InitCreditsSlide(void)
#endif
)
{
slide->strings.push_back("#" + std::string(def->title));
slide->strings.push_back("#" + srb2::String(def->title));
slide->strings_height += 12;
if (def->author)
{
slide->strings.push_back("by " + std::string(def->author));
slide->strings.push_back("by " + srb2::String(def->author));
slide->strings_height += 12;
}
if (def->source)
{
slide->strings.push_back("from " + std::string(def->source));
slide->strings.push_back("from " + srb2::String(def->source));
slide->strings_height += 12;
}
if (def->composers)
{
slide->strings.push_back("originally by " + std::string(def->composers));
slide->strings.push_back("originally by " + srb2::String(def->composers));
slide->strings_height += 12;
}
@ -478,7 +480,7 @@ void F_ContinueCredits(void)
static UINT16 F_PickRandomCreditsDemoMap(void)
{
std::vector<UINT16> allowedMaps;
srb2::Vector<UINT16> allowedMaps;
for (INT32 i = 0; i < basenummapheaders; i++) // Only take from the base game.
{
@ -911,7 +913,7 @@ static void F_DrawCreditsScroll(void)
}
else
{
std::string new_str = str;
srb2::String new_str = str;
if (new_str.at(0) == '*')
{
@ -1017,7 +1019,7 @@ static void F_DrawCreditsSlide(void)
return;
}
const std::vector<std::string> *slide_strings = &g_credits.split_slide_strings[ g_credits.split_slide_id ];
const srb2::Vector<srb2::String> *slide_strings = &g_credits.split_slide_strings[ g_credits.split_slide_id ];
const fixed_t strings_height = slide_strings->size() * 30 * FRACUNIT;
fixed_t y = 0;
@ -1113,7 +1115,7 @@ static void F_DrawCreditsTyler52(void)
V_DrawFadeScreen(0xFF00, 31 - (g_credits.tyler_fade * 4));
}
std::string memory_str = "In memory of";
srb2::String memory_str = "In memory of";
const fixed_t memory_width = V_StringScaledWidth(
FRACUNIT, FRACUNIT, FRACUNIT,
0, LSLOW_FONT,
@ -1126,7 +1128,7 @@ static void F_DrawCreditsTyler52(void)
memory_str.c_str()
);
std::string tyler_str = "Tyler52";
srb2::String tyler_str = "Tyler52";
const fixed_t tyler_width = V_StringScaledWidth(
FRACUNIT, FRACUNIT, FRACUNIT,
0, LSHI_FONT,

View file

@ -14,9 +14,10 @@
#include "k_dialogue.hpp"
#include "k_dialogue.h"
#include <string>
#include <algorithm>
#include <string_view>
#include "core/string.h"
#include "info.h"
#include "sounds.h"
#include "g_game.h"
@ -43,7 +44,7 @@ void Dialogue::Typewriter::ClearText(void)
textDest.clear();
}
void Dialogue::Typewriter::NewText(std::string newText)
void Dialogue::Typewriter::NewText(const srb2::String& newText)
{
text.clear();
@ -174,7 +175,7 @@ void Dialogue::SetSpeaker(void)
typewriter.voiceSfx = sfx_ktalk;
}
void Dialogue::SetSpeaker(std::string skinName, int portraitID)
void Dialogue::SetSpeaker(srb2::String skinName, int portraitID)
{
Init();
@ -215,7 +216,7 @@ void Dialogue::SetSpeaker(std::string skinName, int portraitID)
}
}
void Dialogue::SetSpeaker(std::string name, patch_t *patch, UINT8 *colormap, sfxenum_t voice)
void Dialogue::SetSpeaker(srb2::String name, patch_t *patch, UINT8 *colormap, sfxenum_t voice)
{
Init();
@ -472,7 +473,7 @@ void Dialogue::Draw(void)
.flags(V_VFLIP|V_FLIP)
.patch(patchCache["TUTDIAGE"]);
std::string intertext = "<large>";
srb2::String intertext = "<large>";
drawer
.xy(10 - BASEVIDWIDTH, -3-32)
@ -486,7 +487,7 @@ void Dialogue::Draw(void)
.patch(patchCache["TUTDIAG2"]);
if (Held())
intertext += "<z_pressed>";
intertext += "<z_pressed>";
else
intertext += "<z_animated>";

View file

@ -14,10 +14,10 @@
#ifndef __K_DIALOGUE_HPP__
#define __K_DIALOGUE_HPP__
#include <string>
#include <string_view>
#include <unordered_map>
#include "core/hash_map.hpp"
#include "core/string.h"
#include "doomdef.h"
#include "doomtype.h"
#include "typedef.h"
@ -33,8 +33,8 @@ public:
static constexpr fixed_t kSlideSpeed = FRACUNIT / (TICRATE / 5);
void SetSpeaker(void);
void SetSpeaker(std::string skinName, int portraitID);
void SetSpeaker(std::string name, patch_t *patch, UINT8 *colormap, sfxenum_t voice);
void SetSpeaker(srb2::String skinName, int portraitID);
void SetSpeaker(srb2::String name, patch_t *patch, UINT8 *colormap, sfxenum_t voice);
void NewText(std::string_view newText);
@ -60,8 +60,8 @@ public:
static constexpr fixed_t kTextSpeedDefault = FRACUNIT;
static constexpr fixed_t kTextPunctPause = (FRACUNIT * TICRATE * 2) / 5;
std::string text;
std::string textDest;
srb2::String text;
srb2::String textDest;
fixed_t textTimer;
fixed_t textSpeed;
@ -71,7 +71,7 @@ public:
sfxenum_t voiceSfx;
bool syllable;
void NewText(std::string newText);
void NewText(const srb2::String& newText);
void ClearText(void);
void WriteText(void);
@ -86,11 +86,11 @@ private:
patch_t *bgPatch;
patch_t *confirmPatch;
std::string speaker;
srb2::String speaker;
patch_t *portrait;
UINT8 *portraitColormap;
std::unordered_map<std::string_view, patch_t*> patchCache;
srb2::HashMap<std::string_view, patch_t*> patchCache;
bool active;
fixed_t slide;

View file

@ -11,11 +11,12 @@
#include <algorithm>
#include <array>
#include <vector>
#include <deque>
#include <fmt/format.h>
#include "core/string.h"
#include "core/vector.hpp"
#include "k_hud.h"
#include "k_kart.h"
#include "k_battle.h"
@ -6332,21 +6333,21 @@ typedef enum
typedef struct
{
std::string text;
srb2::String text;
sfxenum_t sound;
} message_t;
struct messagestate_t
{
std::deque<std::string> messages;
std::string objective = "";
std::deque<srb2::String> messages;
srb2::String objective = "";
tic_t timer = 0;
boolean persist = false;
messagemode_t mode = MM_IN;
const tic_t speedyswitch = 2*TICRATE;
const tic_t lazyswitch = 4*TICRATE;
void add(std::string msg)
void add(srb2::String msg)
{
messages.push_back(msg);
}
@ -6384,7 +6385,7 @@ struct messagestate_t
switch (mode)
{
case MM_IN:
if (timer > messages[0].length())
if (timer > messages[0].size())
switch_mode(MM_HOLD);
break;
case MM_HOLD:
@ -6394,7 +6395,7 @@ struct messagestate_t
switch_mode(MM_OUT);
break;
case MM_OUT:
if (timer > messages[0].length())
if (timer > messages[0].size())
next();
break;
}

View file

@ -12,6 +12,7 @@
#include "k_podium.h"
#include "core/string.h"
#include "doomdef.h"
#include "d_main.h"
#include "d_netcmd.h"
@ -51,8 +52,6 @@
#include "k_hud.h"
#include <string>
typedef enum
{
PODIUM_ST_CONGRATS_SLIDEIN,
@ -652,7 +651,7 @@ void podiumData_s::Draw(void)
}
{
std::string emeraldName;
srb2::String emeraldName;
if (emeraldNum > 7)
{
emeraldName = (useWhiteFrame ? "K_SUPER2" : "K_SUPER1");

View file

@ -12,10 +12,13 @@
/// \brief implements methods for profiles etc.
#include <algorithm>
#include <filesystem>
#include <exception>
#include <fmt/format.h>
#include "core/string.h"
#include "core/vector.hpp"
#include "io/streams.hpp"
#include "doomtype.h"
#include "d_main.h" // pandf
@ -253,7 +256,6 @@ void PR_InitNewProfile(void)
void PR_SaveProfiles(void)
{
namespace fs = std::filesystem;
using json = nlohmann::json;
using namespace srb2;
namespace io = srb2::io;
@ -271,13 +273,13 @@ void PR_SaveProfiles(void)
profile_t* cprof = profilesList[i];
jsonprof.version = PROFILEVER;
jsonprof.profilename = std::string(cprof->profilename);
jsonprof.profilename = String(cprof->profilename);
std::copy(std::begin(cprof->public_key), std::end(cprof->public_key), std::begin(jsonprof.publickey));
std::copy(std::begin(cprof->secret_key), std::end(cprof->secret_key), std::begin(jsonprof.secretkey));
jsonprof.playername = std::string(cprof->playername);
jsonprof.skinname = std::string(cprof->skinname);
jsonprof.colorname = std::string(skincolors[cprof->color].name);
jsonprof.followername = std::string(cprof->follower);
jsonprof.playername = String(cprof->playername);
jsonprof.skinname = String(cprof->skinname);
jsonprof.colorname = String(skincolors[cprof->color].name);
jsonprof.followername = String(cprof->follower);
if (cprof->followercolor == FOLLOWERCOLOR_MATCH)
{
jsonprof.followercolorname = "Match";
@ -292,11 +294,11 @@ void PR_SaveProfiles(void)
}
else if (cprof->followercolor >= numskincolors)
{
jsonprof.followercolorname = std::string();
jsonprof.followercolorname = String();
}
else
{
jsonprof.followercolorname = std::string(skincolors[cprof->followercolor].name);
jsonprof.followercolorname = String(skincolors[cprof->followercolor].name);
}
jsonprof.records.wins = cprof->wins;
jsonprof.records.rounds = cprof->rounds;
@ -310,7 +312,7 @@ void PR_SaveProfiles(void)
for (size_t j = 0; j < num_gamecontrols; j++)
{
std::vector<int32_t> mappings;
srb2::Vector<int32_t> mappings;
for (size_t k = 0; k < MAXINPUTMAPPING; k++)
{
mappings.push_back(cprof->controls[j][k]);
@ -321,16 +323,18 @@ void PR_SaveProfiles(void)
ng.profiles.emplace_back(std::move(jsonprof));
}
std::vector<uint8_t> ubjson = json::to_ubjson(ng);
JsonValue ngv;
to_json(ngv, ng);
Vector<std::byte> ubjson = ngv.to_ubjson();
std::string realpath = fmt::format("{}/{}", srb2home, PROFILESFILE);
std::string bakpath = fmt::format("{}.bak", realpath);
String realpath = srb2::format("{}/{}", srb2home, PROFILESFILE);
String bakpath = srb2::format("{}.bak", realpath);
if (fs::exists(realpath))
if (fs::exists(fs::path(static_cast<std::string_view>(realpath))))
{
try
{
fs::rename(realpath, bakpath);
fs::rename(fs::path(static_cast<std::string_view>(realpath)), fs::path(static_cast<std::string_view>(bakpath)));
}
catch (const fs::filesystem_error& ex)
{
@ -349,7 +353,7 @@ void PR_SaveProfiles(void)
io::write(static_cast<uint8_t>(0), file); // reserved2
io::write(static_cast<uint8_t>(0), file); // reserved3
io::write(static_cast<uint8_t>(0), file); // reserved4
io::write_exact(file, tcb::as_bytes(tcb::make_span(ubjson)));
io::write_exact(file, ubjson);
file.close();
}
catch (const std::exception& ex)
@ -367,7 +371,6 @@ void PR_LoadProfiles(void)
namespace fs = std::filesystem;
using namespace srb2;
namespace io = srb2::io;
using json = nlohmann::json;
profile_t *dprofile = PR_MakeProfile(
PROFILEDEFAULTNAME,
@ -378,7 +381,7 @@ void PR_LoadProfiles(void)
true
);
std::string datapath {fmt::format("{}/{}", srb2home, PROFILESFILE)};
String datapath { srb2::format("{}/{}", srb2home, PROFILESFILE) };
io::BufferedInputStream<io::FileStream> bis;
try
@ -413,11 +416,10 @@ void PR_LoadProfiles(void)
throw std::domain_error("Header is incompatible");
}
std::vector<std::byte> remainder = io::read_to_vec(bis);
Vector<std::byte> remainder = io::read_to_vec(bis);
// safety: std::byte repr is always uint8_t 1-byte aligned
tcb::span<uint8_t> remainder_as_u8 = tcb::span((uint8_t*)remainder.data(), remainder.size());
json parsed = json::from_ubjson(remainder_as_u8);
js = parsed.template get<ProfilesJson>();
JsonValue parsed = JsonValue::from_ubjson(remainder);
from_json(parsed, js);
}
catch (const std::exception& ex)
{

View file

@ -25,10 +25,10 @@
#include <array>
#include <cstdint>
#include <string>
#include <vector>
#include <nlohmann/json.hpp>
#include "core/json.hpp"
#include "core/string.h"
#include "core/vector.hpp"
namespace srb2
{
@ -38,7 +38,7 @@ struct ProfileRecordsJson
uint32_t wins;
uint32_t rounds;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ProfileRecordsJson, wins, rounds)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ProfileRecordsJson, wins, rounds)
};
struct ProfilePreferencesJson
@ -50,9 +50,8 @@ struct ProfilePreferencesJson
bool autoring;
bool rumble;
uint8_t fov;
tm test;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
ProfilePreferencesJson,
kickstartaccel,
autoroulette,
@ -67,19 +66,19 @@ struct ProfilePreferencesJson
struct ProfileJson
{
uint32_t version;
std::string profilename;
std::string playername;
String profilename;
String playername;
std::array<uint8_t, 32> publickey = {{}};
std::array<uint8_t, 64> secretkey = {{}};
std::string skinname;
std::string colorname;
std::string followername;
std::string followercolorname;
String skinname;
String colorname;
String followername;
String followercolorname;
ProfileRecordsJson records;
ProfilePreferencesJson preferences;
std::vector<std::vector<int32_t>> controls = {};
Vector<Vector<int32_t>> controls = {};
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
ProfileJson,
version,
profilename,
@ -98,9 +97,9 @@ struct ProfileJson
struct ProfilesJson
{
std::vector<ProfileJson> profiles;
Vector<ProfileJson> profiles;
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ProfilesJson, profiles)
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ProfilesJson, profiles)
};
} // namespace srb2

View file

@ -24,10 +24,12 @@
#include "cxxutil.hpp"
#include <algorithm>
#include <vector>
#include <fmt/format.h>
#include "core/string.h"
#include "core/vector.hpp"
// The number of sparkles per waypoint connection in the waypoint visualisation
static const UINT32 SPARKLES_PER_CONNECTION = 16U;
@ -2377,8 +2379,8 @@ static BlockItReturn_t K_TrackWaypointNearOffroad(line_t *line)
struct complexity_sneaker_s
{
fixed_t bbox[4];
//std::vector<sector_t *> sectors;
//std::vector<mapthing_t *> things;
//srb2::Vector<sector_t *> sectors;
//srb2::Vector<mapthing_t *> things;
complexity_sneaker_s(sector_t *sec)
{
@ -2631,7 +2633,7 @@ static INT32 K_CalculateTrackComplexity(void)
delta = FixedMul(delta, FixedMul(FixedMul(dist_factor, radius_factor), wall_factor));
std::string msg = fmt::format(
srb2::String msg = srb2::format(
"TURN [{}]: r: {:.2f}, d: {:.2f}, w: {:.2f}, r*d*w: {:.2f}, DELTA: {}\n",
turn_id,
FixedToFloat(radius_factor),
@ -2644,7 +2646,7 @@ static INT32 K_CalculateTrackComplexity(void)
trackcomplexity += (delta / FRACUNIT);
}
std::vector<complexity_sneaker_s> sneaker_panels;
srb2::Vector<complexity_sneaker_s> sneaker_panels;
for (size_t i = 0; i < numsectors; i++)
{

View file

@ -10,10 +10,8 @@
#include <algorithm>
#include <cstddef>
#include <unordered_map>
#include <string>
#include <string_view>
#include <vector>
#include <fmt/format.h>
@ -21,6 +19,9 @@ extern "C" {
#include "blua/lua.h"
};
#include "core/hash_map.hpp"
#include "core/string.h"
#include "core/vector.hpp"
#include "v_draw.hpp"
#include "command.h"
@ -58,7 +59,7 @@ struct lua_timer_t
namespace
{
std::unordered_map<std::string, lua_timer_t> g_tic_timers;
srb2::HashMap<srb2::String, lua_timer_t> g_tic_timers;
}; // namespace
@ -156,7 +157,7 @@ void LUA_RenderTimers(void)
return;
}
std::vector<decltype(g_tic_timers)::iterator> view;
srb2::Vector<decltype(g_tic_timers)::Iter> view;
view.reserve(g_tic_timers.size());
auto color_flag = [](double t)

View file

@ -14,13 +14,13 @@
#include <cctype>
#include <fstream>
#include <stdexcept>
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include "modp_b64/modp_b64.h"
#include "core/string.h"
#include "core/vector.hpp"
#include "cxxutil.hpp"
#include "command.h"
@ -43,12 +43,13 @@ namespace
constexpr const UINT8 kRRSalt[17] = "0L4rlK}{9ay6'VJS";
std::array<UINT8, M_PW_BUF_SIZE> decode_hash(std::string encoded)
std::array<UINT8, M_PW_BUF_SIZE> decode_hash(srb2::String encoded)
{
std::array<UINT8, M_PW_BUF_SIZE> decoded;
if (modp::b64_decode(encoded).size() != decoded.size())
std::string encoded_stl { static_cast<std::string_view>(encoded) };
if (modp::b64_decode(encoded_stl).size() != decoded.size())
throw std::invalid_argument("hash is incorrectly sized");
std::copy(encoded.begin(), encoded.end(), decoded.begin());
std::copy(encoded_stl.begin(), encoded_stl.end(), decoded.begin());
return decoded;
}
@ -60,7 +61,7 @@ struct Pw
const std::array<UINT8, M_PW_BUF_SIZE> hash_;
};
std::vector<Pw> passwords;
srb2::Vector<Pw> passwords;
// m_cond.c
template <typename F>
@ -629,8 +630,8 @@ try_password_e M_TryPassword(const char *password, boolean conditions)
using var = std::variant<std::monostate, condition_t*, Pw*>;
// Normalize input casing
std::string key = password;
strlwr(key.data());
srb2::String key = password;
strlwr((char*)key.data());
UINT8 key_hash[M_PW_HASH_SIZE];
M_HashPassword(key_hash, key.c_str(), kRRSalt);
@ -684,8 +685,8 @@ try_password_e M_TryPassword(const char *password, boolean conditions)
boolean M_TryExactPassword(const char *password, const char *encodedhash)
{
// Normalize input casing
std::string key = password;
strlwr(key.data());
srb2::String key = password;
strlwr((char*)key.data());
UINT8 key_hash[M_PW_HASH_SIZE];
M_HashPassword(key_hash, key.c_str(), kRRSalt);

View file

@ -17,11 +17,11 @@
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <tcb/span.hpp>
#include "../core/string.h"
#include "../core/vector.hpp"
#include "../audio/sample.hpp"
namespace srb2::media
@ -49,7 +49,7 @@ public:
int frame_rate;
};
std::string file_name;
srb2::String file_name;
std::optional<std::size_t> max_size; // file size limit
std::optional<std::chrono::duration<float>> max_duration;
@ -63,7 +63,7 @@ public:
{
using instance_t = std::unique_ptr<StagingVideoFrame>;
std::vector<uint8_t> screen;
srb2::Vector<uint8_t> screen;
uint32_t width, height;
int pts;

View file

@ -10,10 +10,10 @@
#include <filesystem>
#include <sstream>
#include <string>
#include <fmt/format.h>
#include "../core/string.h"
#include "../cxxutil.hpp"
#include "avrecorder_impl.hpp"
@ -39,7 +39,7 @@ void Impl::container_dtor_handler(const MediaContainer& container) const
if (max_size_ && container.size() > *max_size_)
{
const std::string line = fmt::format(
const srb2::String line = srb2::format(
"Video size has exceeded limit {} > {} ({}%)."
" This should not happen, please report this bug.\n",
container.size(),
@ -100,7 +100,7 @@ void AVRecorder::draw_statistics() const
{
SRB2_ASSERT(impl_->video_encoder_ != nullptr);
auto draw = [](int x, std::string text, int32_t flags = 0)
auto draw = [](int x, const srb2::String text, int32_t flags = 0)
{
V_DrawThinString(
x,
@ -144,7 +144,7 @@ void AVRecorder::draw_statistics() const
return 0;
}();
draw(200, fmt::format("{:.0f}", fps), fps_color);
draw(230, fmt::format("{:.1f}s", impl_->container_->duration().count()));
draw(260, fmt::format("{:.1f} MB", size / kMb), mb_color);
draw(200, srb2::format("{:.0f}", fps), fps_color);
draw(230, srb2::format("{:.1f}s", impl_->container_->duration().count()));
draw(260, srb2::format("{:.1f} MB", size / kMb), mb_color);
}

View file

@ -19,8 +19,8 @@
#include <mutex>
#include <optional>
#include <thread>
#include <vector>
#include "../core/string.h"
#include "../i_time.h"
#include "avrecorder.hpp"
#include "container.hpp"
@ -57,7 +57,7 @@ public:
using frame_type = StagingVideoFrame::instance_t;
};
std::vector<typename Traits<T>::frame_type> vec_;
srb2::Vector<typename Traits<T>::frame_type> vec_;
// This number only decrements once a frame has
// actually been written to container.

View file

@ -19,7 +19,7 @@
using namespace srb2::media;
CFile::CFile(const std::string file_name) : name_(file_name)
CFile::CFile(const srb2::String& file_name) : name_(file_name)
{
file_ = std::fopen(name(), "wb");

View file

@ -12,7 +12,8 @@
#define __SRB2_MEDIA_CFILE_HPP__
#include <cstdio>
#include <string>
#include "../core/string.h"
namespace srb2::media
{
@ -20,7 +21,7 @@ namespace srb2::media
class CFile
{
public:
CFile(const std::string file_name);
CFile(const srb2::String& file_name);
~CFile();
operator std::FILE*() const { return file_; }
@ -28,7 +29,7 @@ public:
const char* name() const { return name_.c_str(); }
private:
std::string name_;
srb2::String name_;
std::FILE* file_;
};

View file

@ -14,8 +14,8 @@
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "../core/string.h"
#include "audio_encoder.hpp"
#include "video_encoder.hpp"
@ -30,7 +30,7 @@ public:
struct Config
{
std::string file_name;
srb2::String file_name;
dtor_cb_t destructor_callback;
};

View file

@ -13,11 +13,11 @@
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
#include "../core/hash_map.hpp"
#include "../core/string.h"
#include "../core/vector.hpp"
#include "../command.h"
namespace srb2::media
@ -26,7 +26,7 @@ namespace srb2::media
class Options
{
public:
using map_t = std::unordered_map<std::string, consvar_t>;
using map_t = srb2::HashMap<srb2::String, consvar_t>;
template <typename T>
struct Range
@ -46,7 +46,7 @@ public:
static consvar_t values(const char* default_value, const Range<T> range, std::map<std::string_view, T> list = {});
private:
static std::vector<consvar_t*> cvars_;
static srb2::Vector<consvar_t*> cvars_;
const char* prefix_;
map_t map_;
@ -54,6 +54,11 @@ private:
const consvar_t& cvar(const char* option) const;
};
// clang-format off
extern template consvar_t Options::values(const char* default_value, const Range<int> range, std::map<std::string_view, int> list);
extern template consvar_t Options::values(const char* default_value, const Range<float> range, std::map<std::string_view, float> list);
// clang-format on
}; // namespace srb2::media
#endif // __SRB2_MEDIA_OPTIONS_HPP__

View file

@ -12,6 +12,7 @@
#include <vpx/vpx_encoder.h>
#include "../core/vector.hpp"
#include "options.hpp"
#include "vorbis.hpp"
#include "vp8.hpp"
@ -23,7 +24,7 @@ using namespace srb2::media;
// to be defined in the same translation unit as
// Options::cvars_ to guarantee initialization order.
std::vector<consvar_t*> Options::cvars_;
srb2::Vector<consvar_t*> Options::cvars_;
// clang-format off
const Options VorbisEncoder::options_("vorbis", {

View file

@ -11,11 +11,11 @@
#ifndef __SRB2_MEDIA_VORBIS_ERROR_HPP__
#define __SRB2_MEDIA_VORBIS_ERROR_HPP__
#include <string>
#include <fmt/format.h>
#include <vorbis/codec.h>
#include "../core/string.h"
class VorbisError
{
public:
@ -23,7 +23,7 @@ public:
operator int() const { return error_; }
std::string name() const
srb2::String name() const
{
switch (error_)
{
@ -43,12 +43,12 @@ private:
};
template <>
struct fmt::formatter<VorbisError> : formatter<std::string>
struct fmt::formatter<VorbisError> : formatter<srb2::String>
{
template <typename FormatContext>
auto format(const VorbisError& error, FormatContext& ctx) const
{
return formatter<std::string>::format(error.name(), ctx);
return formatter<srb2::String>::format(error.name(), ctx);
}
};

View file

@ -11,22 +11,22 @@
#ifndef __SRB2_MEDIA_VPX_ERROR_HPP__
#define __SRB2_MEDIA_VPX_ERROR_HPP__
#include <string>
#include <fmt/format.h>
#include <vpx/vpx_codec.h>
#include "../core/string.h"
class VpxError
{
public:
VpxError(vpx_codec_ctx_t& ctx) : ctx_(&ctx) {}
std::string description() const
srb2::String description() const
{
const char* error = vpx_codec_error(ctx_);
const char* detail = vpx_codec_error_detail(ctx_);
return detail ? fmt::format("{}: {}", error, detail) : error;
return detail ? srb2::format("{}: {}", error, detail) : error;
}
private:
@ -34,12 +34,12 @@ private:
};
template <>
struct fmt::formatter<VpxError> : formatter<std::string>
struct fmt::formatter<VpxError> : formatter<srb2::String>
{
template <typename FormatContext>
auto format(const VpxError& error, FormatContext& ctx) const
{
return formatter<std::string>::format(error.description(), ctx);
return formatter<srb2::String>::format(error.description(), ctx);
}
};

View file

@ -13,11 +13,11 @@
#include <cstddef>
#include <mutex>
#include <unordered_map>
#include <vector>
#include <mkvmuxer/mkvmuxer.h>
#include "../core/hash_map.hpp"
#include "container.hpp"
#include "webm.hpp"
#include "webm_writer.hpp"
@ -88,7 +88,7 @@ private:
mutable std::recursive_mutex queue_mutex_;
std::unordered_map<webm::track, FrameQueue> queue_;
srb2::HashMap<webm::track, FrameQueue> queue_;
webm::timestamp latest_timestamp_ = 0;
std::size_t queue_size_ = 0;

View file

@ -12,10 +12,10 @@
#define __SRB2_MEDIA_WEBM_WRITER_HPP__
#include <cstdio>
#include <string>
#include <mkvmuxer/mkvwriter.h>
#include "../core/string.h"
#include "cfile.hpp"
namespace srb2::media
@ -24,7 +24,7 @@ namespace srb2::media
class WebmWriter : public CFile, public mkvmuxer::MkvWriter
{
public:
WebmWriter(const std::string file_name) : CFile(file_name), MkvWriter(static_cast<std::FILE*>(*this)) {}
WebmWriter(const srb2::String& file_name) : CFile(file_name), MkvWriter(static_cast<std::FILE*>(*this)) {}
~WebmWriter() { MkvWriter::Close(); }
};

View file

@ -12,8 +12,8 @@
#define __SRB2_MEDIA_YUV420P_HPP__
#include <cstdint>
#include <vector>
#include "../core/vector.hpp"
#include "video_frame.hpp"
namespace srb2::media
@ -40,7 +40,7 @@ public:
int width_ = 0;
int height_ = 0;
std::vector<uint8_t> vec_;
srb2::Vector<uint8_t> vec_;
};
YUV420pFrame(int pts, Buffer y, Buffer u, Buffer v, const BufferRGBA& rgba);

View file

@ -11,11 +11,11 @@
#include <algorithm>
#include <cstddef>
#include <memory>
#include <string>
#include <fmt/chrono.h>
#include <fmt/format.h>
#include "../../core/string.h"
#include "../../cxxutil.hpp"
#include "../../v_draw.hpp"
#include "EggTV.hpp"
@ -85,11 +85,11 @@ void draw_face(const Draw& draw, const EggTVData::Replay::Standing& player, face
}
}
std::string player_time_string(const EggTVData::Replay::Standing& player)
srb2::String player_time_string(const EggTVData::Replay::Standing& player)
{
if (player.time)
{
return fmt::format(
return srb2::format(
R"({}'{}"{})",
G_TicsToMinutes(*player.time, true),
G_TicsToSeconds(*player.time),
@ -102,7 +102,7 @@ std::string player_time_string(const EggTVData::Replay::Standing& player)
}
}
std::string player_points_string(const EggTVData::Replay::Standing& player)
srb2::String player_points_string(const EggTVData::Replay::Standing& player)
{
return player.score ? fmt::format("{} PTS", *player.score) : "NO CONTEST";
}

View file

@ -19,6 +19,7 @@
#include "EggTVData.hpp"
#include "EggTVGraphics.hpp"
#include "../../core/vector.hpp"
#include "../../doomdef.h" // TICRATE
#include "../../i_time.h"
#include "../../k_menu.h"
@ -197,7 +198,7 @@ private:
{
public:
using limiter_t = std::function<int()>;
using anims_t = std::vector<Animation*>;
using anims_t = srb2::Vector<Animation*>;
explicit Cursor(anims_t anims, limiter_t limiter) : limiter_(limiter), anims_(anims) {}

View file

@ -14,13 +14,14 @@
#include <fstream>
#include <iterator>
#include <memory>
#include <string>
#include <string_view>
#include <fmt/format.h>
#include <fmt/std.h> // std::filesystem::path formatter
#include <nlohmann/json.hpp>
#include "../../core/string.h"
#include "../../core/json.hpp"
#include "../../io/streams.hpp"
#include "../../cxxutil.hpp"
#include "EggTVData.hpp"
@ -34,15 +35,15 @@ using namespace srb2::menus::egg_tv;
namespace fs = std::filesystem;
using nlohmann::json;
using srb2::JsonValue;
template <>
struct fmt::formatter<fs::filesystem_error> : formatter<std::string>
struct fmt::formatter<fs::filesystem_error> : formatter<srb2::String>
{
template <typename FormatContext>
auto format(const fs::filesystem_error& ex, FormatContext& ctx) const
{
return formatter<std::string>::format(
return formatter<srb2::String>::format(
fmt::format("{}, path1={}, path2={}", ex.what(), ex.path1(), ex.path2()),
ctx
);
@ -65,13 +66,13 @@ To time_point_conv(From time)
return std::chrono::time_point_cast<typename To::duration>(To::clock::now() + (time - From::clock::now()));
}
json& ensure_array(json& object, const char* key)
JsonValue& ensure_array(JsonValue& object, const char* key)
{
json& array = object[key];
JsonValue& array = object[key];
if (!array.is_array())
{
array = json::array();
array = JsonValue::array();
}
return array;
@ -91,18 +92,16 @@ EggTVData::EggTVData() : favorites_(ensure_array(favoritesFile_, "favorites"))
}
}
json EggTVData::cache_favorites() const
JsonValue EggTVData::cache_favorites() const
{
json object;
JsonValue object;
try
{
std::ifstream f(favoritesPath_);
if (f.is_open())
{
f >> object;
}
srb2::io::FileStream stream { favoritesPath_.generic_string() };
srb2::Vector<std::byte> f = srb2::io::read_to_vec(stream);
srb2::String json_string { (const char*)f.data(), f.size() };
object = JsonValue::from_json_string(json_string);
}
catch (const std::exception& ex)
{
@ -199,9 +198,9 @@ EggTVData::Folder::Folder(EggTVData& tv, const fs::directory_entry& entry) :
}
}
EggTVData::Replay::Title::operator const std::string() const
EggTVData::Replay::Title::operator const srb2::String() const
{
return second().empty() ? first() : fmt::format("{} - {}", first(), second());
return second().empty() ? first() : srb2::format("{} - {}", first(), second());
}
EggTVData::Replay::Replay(Folder::Cache::ReplayRef& ref) : ref_(&ref)
@ -230,7 +229,7 @@ EggTVData::Replay::Replay(Folder::Cache::ReplayRef& ref) : ref_(&ref)
const std::string_view str = info.title;
const std::size_t mid = str.find(kDelimiter);
title_ = Title(str.substr(0, mid), mid == std::string::npos ? "" : str.substr(mid + kDelimiter.size()));
title_ = Title(str.substr(0, mid), mid == srb2::String::npos ? "" : str.substr(mid + kDelimiter.size()));
//title_ = Title("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW", "WWWWWWWWWWWWWWWWWWWWWWWWWWW");
}
@ -316,13 +315,13 @@ void EggTVData::Replay::toggle_favorite() const
{
const auto& it = ref_->iterator_to_favorite();
if (it != ref_->favorites().end())
if (it != ref_->favorites().as_array().end())
{
ref_->favorites().erase(it);
ref_->favorites().as_array().erase(it);
}
else
{
ref_->favorites().emplace_back(ref_->favorites_path());
ref_->favorites().as_array().emplace_back(ref_->favorites_path());
}
ref_->cache().folder().tv().save_favorites();
@ -382,7 +381,9 @@ void EggTVData::save_favorites() const
{
try
{
std::ofstream(favoritesPath_) << favoritesFile_;
srb2::String json_string = favoritesFile_.to_json_string();
srb2::io::FileStream fs { favoritesPath_.generic_string(), srb2::io::FileStreamMode::kWrite };
srb2::io::write_exact(fs, tcb::as_bytes(tcb::span(json_string.data(), json_string.size())));
}
catch (const std::exception& ex)
{

View file

@ -17,14 +17,13 @@
#include <filesystem>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <variant>
#include <vector>
#include <nlohmann/json.hpp>
#include "../../core/string.h"
#include "../../core/json.hpp"
#include "../../cxxutil.hpp"
#include "../../d_main.h" // srb2home
@ -40,10 +39,10 @@ private:
const std::filesystem::path root_ = std::filesystem::path{srb2home} / "media/replay/online";
const std::filesystem::path favoritesPath_ = root_ / "favorites.json";
nlohmann::json favoritesFile_ = cache_favorites();
nlohmann::json& favorites_;
JsonValue favoritesFile_ = cache_favorites();
JsonValue& favorites_;
nlohmann::json cache_favorites() const;
JsonValue cache_favorites() const;
void cache_folders();
void save_favorites() const;
@ -91,20 +90,21 @@ public:
released_ = true;
}
bool favorited() const { return iterator_to_favorite() != favorites().end(); }
nlohmann::json& favorites() const { return cache().folder().tv().favorites_; }
bool favorited() const { return iterator_to_favorite() != favorites().as_array().end(); }
JsonValue& favorites() const { return cache().folder().tv().favorites_; }
std::string favorites_path() const
srb2::String favorites_path() const
{
// path::generic_string converts to forward
// slashes on Windows. This should suffice to make
// the JSON file portable across installations.
return (std::filesystem::path{cache().folder().name()} / filename()).generic_string();
return (std::filesystem::path{std::string_view(cache().folder().name())} / filename()).generic_string();
}
nlohmann::json::const_iterator iterator_to_favorite() const
JsonArray::const_iterator iterator_to_favorite() const
{
return std::find(favorites().begin(), favorites().end(), favorites_path());
srb2::String path = favorites_path();
return std::find(favorites().as_array().begin(), favorites().as_array().end(), static_cast<std::string_view>(path));
}
private:
@ -134,13 +134,13 @@ public:
int y = 0;
bool empty() { return size() == 0; }
std::filesystem::path path() const { return tv_->root_ / name_; }
std::filesystem::path path() const { return tv_->root_ / std::string_view(name_); }
EggTVData& tv() const { return *tv_; }
std::size_t size() const { return size_; }
const time_point_t& time() const { return time_; }
const std::string& name() const { return name_; }
const srb2::String& name() const { return name_; }
std::unique_ptr<Cache> load() { return std::make_unique<Cache>(*this); };
@ -150,7 +150,7 @@ public:
std::size_t size_;
time_point_t time_;
EggTVData* tv_;
std::string name_;
srb2::String name_;
};
class Replay
@ -165,18 +165,18 @@ public:
{
}
const std::string& first() const { return first_; }
const std::string& second() const { return second_; }
const srb2::String& first() const { return first_; }
const srb2::String& second() const { return second_; }
operator const std::string() const;
operator const srb2::String() const;
private:
std::string first_, second_;
srb2::String first_, second_;
};
struct Standing
{
std::string name;
srb2::String name;
std::optional<std::size_t> skin;
std::size_t color;
std::optional<tic_t> time;
@ -247,7 +247,7 @@ public:
void toggle_favorite() const;
bool invalid() const { return invalid_; }
bool favorited() const { return ref_->iterator_to_favorite() != ref_->favorites().end(); }
bool favorited() const { return ref_->iterator_to_favorite() != ref_->favorites().as_array().end(); }
std::filesystem::path path() const { return ref_->cache().folder().path() / ref_->filename(); }
const time_point_t& date() const { return ref_->time(); }

View file

@ -13,8 +13,8 @@
#include <array>
#include <string_view>
#include <unordered_map>
#include "../../core/hash_map.hpp"
#include "../../doomdef.h" // skincolornum_t
#include "../../v_draw.hpp"
@ -90,7 +90,7 @@ public:
patch select = "RHTVSQSL";
std::unordered_map<std::string_view, patch> gametype = {
srb2::HashMap<std::string_view, patch> gametype = {
{"Race", "RHGT1"},
{"Battle", "RHGT2"},
{"Prison Break", "RHGT3"},

View file

@ -11,6 +11,8 @@
/// \file menus/extras-challenges.c
/// \brief Statistics menu
#include <algorithm>
#include "../k_menu.h"
#include "../z_zone.h"
#include "../m_cond.h" // Condition Sets
@ -260,7 +262,7 @@ static void M_StatisticsPageInit(void)
M_StatisticsChars();
break;
}
case statisticspage_gp:
{
M_StatisticsGP();

View file

@ -29,6 +29,8 @@
#include <forward_list>
#include "../core/string.h"
static void M_GonerDrawer(void);
static void M_GonerConclude(INT32 choice);
static boolean M_GonerInputs(INT32 ch);
@ -46,7 +48,7 @@ menuitem_t MAIN_Goner[] =
{.routine = M_VideoOptions}, 0, 0},
{IT_STRING | IT_CALL, "SOUND OPTIONS",
"CALIBRATE AURAL DATASTREAM.", NULL,
"CALIBRATE AURAL DATASTREAM.", NULL,
{.routine = M_SoundOptions}, 0, 0},
{IT_STRING | IT_CALL, "PROFILE SETUP",
@ -95,7 +97,7 @@ class GonerSpeaker
public:
float offset = 0;
GonerSpeaker(std::string skinName, float offset)
GonerSpeaker(const srb2::String& skinName, float offset)
{
if (!skinName.empty())
{
@ -144,11 +146,11 @@ class GonerChatLine
{
public:
gonerspeakers_t speaker;
std::string dialogue;
srb2::String dialogue;
int value; // Mutlipurpose.
void (*routine)(void);
GonerChatLine(gonerspeakers_t speaker, int delay, std::string dialogue)
GonerChatLine(gonerspeakers_t speaker, int delay, const srb2::String& dialogue)
{
char *newText = V_ScaledWordWrap(
(BASEVIDWIDTH/2 + 6) << FRACBITS,
@ -158,7 +160,7 @@ public:
);
this->speaker = speaker;
this->dialogue = std::string(newText);
this->dialogue = srb2::String(newText);
this->value = delay;
this->routine = nullptr;
@ -1142,7 +1144,7 @@ static void M_GonerDrawer(void)
for (auto & element : LinesOutput)
{
std::string text;
srb2::String text;
INT32 flags;
if (newy < 0) break;

View file

@ -174,7 +174,7 @@ void Music_Init(void)
{
Tune& tune = g_tunes.insert("credits");
tune.priority = 100;
tune.priority = 101;
tune.song = "_creds";
tune.credit = true;
}
@ -182,7 +182,7 @@ void Music_Init(void)
{
Tune& tune = g_tunes.insert("shore");
tune.priority = 100;
tune.priority = 101;
tune.loop = false;
}

View file

@ -14,13 +14,13 @@
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
#include <fmt/format.h>
#include "music_manager.hpp"
#include "music_tune.hpp"
#include "core/string.h"
#include "d_clisrv.h"
#include "doomtype.h"
#include "i_sound.h"
@ -49,8 +49,8 @@ void TuneManager::tick()
Tune* tune = current_tune();
std::string old_song = current_song_;
current_song_ = tune && tune->playing() && !tune->suspend ? tune->song : std::string{};
srb2::String old_song = current_song_;
current_song_ = tune && tune->playing() && !tune->suspend ? tune->song : srb2::String{};
bool changed = current_song_ != old_song;
@ -167,7 +167,8 @@ void TuneManager::pause_unpause() const
bool TuneManager::load() const
{
lumpnum_t lumpnum = W_CheckNumForLongName(fmt::format("O_{}", current_song_).c_str());
srb2::String lumpstring = srb2::format("O_{}", current_song_);
lumpnum_t lumpnum = W_CheckNumForLongName(lumpstring.c_str());
if (lumpnum == LUMPERROR)
{

View file

@ -11,11 +11,10 @@
#ifndef MUSIC_MANAGER_HPP
#define MUSIC_MANAGER_HPP
#include <algorithm>
#include <cstdlib>
#include <string>
#include <unordered_map>
#include "core/hash_map.hpp"
#include "core/string.h"
#include "cxxutil.hpp"
#include "music_tune.hpp"
@ -25,7 +24,7 @@ namespace srb2::music
class TuneManager
{
public:
const std::string& current_song() const { return current_song_; }
const srb2::String& current_song() const { return current_song_; }
Tune* current_tune() const
{
@ -99,8 +98,8 @@ public:
}
private:
std::unordered_map<std::string, Tune> map_;
std::string current_song_;
srb2::HashMap<srb2::String, Tune> map_;
srb2::String current_song_;
tic_t time_sync_;
tic_t time_local_;
@ -113,11 +112,20 @@ private:
decltype(map_)::const_iterator current_iterator() const
{
return std::max_element(
map_.begin(),
map_.end(),
[](const auto& a, const auto& b) { return a.second < b.second; }
);
// Not using std::max_element due to buggy clang libc++ LegacyInputIterator assertion
auto first = map_.begin();
auto last = map_.end();
if (first == last) return first;
auto max = first;
while (++first != last)
{
if (max->second < first->second)
{
max = first;
}
}
return max;
}
bool load() const;

View file

@ -14,8 +14,8 @@
#include <algorithm>
#include <cstdint>
#include <optional>
#include <string>
#include "core/string.h"
#include "doomdef.h"
#include "doomtype.h"
#include "k_boss.h"
@ -29,7 +29,7 @@ class Tune
public:
explicit Tune() {}
std::string song; // looks up the lump
srb2::String song; // looks up the lump
// Higher priority tunes play first.
int priority = 0;

View file

@ -10,6 +10,8 @@
/// \file ballhog.cpp
/// \brief Ballhog item code.
#include <algorithm>
#include "../doomdef.h"
#include "../doomstat.h"
#include "../info.h"

View file

@ -9,13 +9,13 @@
//-----------------------------------------------------------------------------
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <fmt/format.h>
#include "../mobj_list.hpp"
#include "../core/hash_map.hpp"
#include "../core/vector.hpp"
#include "../doomdef.h"
#include "../doomtype.h"
#include "../info.h"
@ -224,7 +224,7 @@ struct Checkpoint : mobj_t
speed(speed() - FixedDiv(speed() / 50, max<fixed_t>(speed_multiplier(), 1)));
}
}
if (!top_half_has_passed())
{
sparkle_between(0);
@ -506,7 +506,7 @@ struct CheckpointManager
auto count() { return list_.count(); }
const std::vector<line_t*>* lines_for(const Checkpoint* chk) const
const srb2::Vector<line_t*>* lines_for(const Checkpoint* chk) const
{
auto it = lines_.find(chk->linetag());
return it != lines_.end() ? &it->second : nullptr;
@ -514,11 +514,11 @@ struct CheckpointManager
private:
srb2::MobjList<Checkpoint, svg_checkpoints> list_;
std::unordered_map<INT32, std::vector<line_t*>> lines_;
srb2::HashMap<INT32, srb2::Vector<line_t*>> lines_;
static std::vector<line_t*> tagged_lines(INT32 tag)
static srb2::Vector<line_t*> tagged_lines(INT32 tag)
{
std::vector<line_t*> checklines;
srb2::Vector<line_t*> checklines;
INT32 li;
TAG_ITER_LINES(tag, li)
{
@ -573,18 +573,18 @@ void __attribute__((optimize("O0"))) Obj_CrossCheckpoints(player_t* player, fixe
}
LineOnDemand* gate;
const std::vector<line_t*>* lines = g_checkpoints.lines_for(chk);
const srb2::Vector<line_t*>* lines = g_checkpoints.lines_for(chk);
if (!lines || lines->empty())
{
LineOnDemand dyngate = chk->crossing_line();
if (!ray.overlaps(dyngate))
return false;
gate = &dyngate;
gate = &dyngate;
}
else
else
{
auto it = find_if(
auto it = std::find_if(
lines->begin(),
lines->end(),
[&](const line_t* line)
@ -592,7 +592,7 @@ void __attribute__((optimize("O0"))) Obj_CrossCheckpoints(player_t* player, fixe
return ray.overlaps(*line);
}
);
if (it == lines->end())
{
return false;
@ -615,7 +615,7 @@ void __attribute__((optimize("O0"))) Obj_CrossCheckpoints(player_t* player, fixe
{
// Did not cross.
return false;
}
return true;

View file

@ -13,8 +13,6 @@
/// \brief Do all the WAD I/O, get map description, set up initial state and misc. LUTs
#include <algorithm>
#include <string>
#include <vector>
#include <fmt/format.h>
@ -96,6 +94,8 @@
#include "taglist.h"
// SRB2Kart
#include "core/string.h"
#include "core/vector.hpp"
#include "k_kart.h"
#include "k_race.h"
#include "k_battle.h" // K_BattleInit
@ -7854,7 +7854,7 @@ static void P_LoadRecordGhosts(void)
map(cv_ghost_last, value, kLast);
};
auto add_ghosts = [gpath](const std::string& base, UINT8 bits)
auto add_ghosts = [gpath](const srb2::String& base, UINT8 bits)
{
auto load = [base](const char* suffix) { P_TryAddExternalGhost(fmt::format("{}-{}.lmp", base, suffix).c_str()); };
@ -7991,7 +7991,7 @@ static void P_ShuffleTeams(void)
CONS_Debug(DBG_TEAMS, "Shuffling player teams...\n");
std::vector<UINT8> player_shuffle;
srb2::Vector<UINT8> player_shuffle;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] == false || players[i].spectator == true)
@ -9135,7 +9135,7 @@ static tic_t round_to_next_second(tic_t time)
static void P_DeriveAutoMedalTimes(mapheader_t& map)
{
// Gather staff ghost times
std::vector<tic_t> stafftimes;
srb2::Vector<tic_t> stafftimes;
for (int i = 0; i < map.ghostCount; i++)
{
tic_t time = map.ghostBrief[i]->time;
@ -9325,7 +9325,7 @@ UINT8 P_InitMapData(void)
{
continue;
}
std::string ghostdirname = fmt::format("staffghosts/{}/", mapheaderinfo[i]->lumpname);
srb2::String ghostdirname = srb2::format("staffghosts/{}/", mapheaderinfo[i]->lumpname);
UINT16 lumpstart = W_CheckNumForFolderStartPK3(ghostdirname.c_str(), wadindex, 0);
if (lumpstart == INT16_MAX)

View file

@ -9,12 +9,12 @@
//-----------------------------------------------------------------------------
#include <string_view>
#include <unordered_map>
#include <unordered_set>
#include "r_debug.hpp"
#include "v_draw.hpp"
#include "core/hash_map.hpp"
#include "core/hash_set.hpp"
#include "doomdef.h"
#include "doomtype.h"
#include "r_textures.h"
@ -25,7 +25,7 @@ using srb2::Draw;
namespace
{
std::unordered_set<INT32> frame_list;
srb2::HashSet<INT32> frame_list;
}; // namespace

View file

@ -14,6 +14,8 @@
/// while maintaining a per column clipping list only.
/// Moreover, the sky areas have to be determined.
#include <algorithm>
#include <tracy/tracy/Tracy.hpp>
#include "command.h"

View file

@ -13,14 +13,14 @@
#include <cstdint>
#include <filesystem>
#include <map>
#include <string>
#include <string_view>
#include <thread>
#include <unordered_map>
#include <vector>
#include <fmt/format.h>
#include "core/hash_map.hpp"
#include "core/string.h"
#include "core/vector.hpp"
#include "cxxutil.hpp"
#include "doomstat.h"
#include "r_textures.h"
@ -29,14 +29,14 @@
namespace
{
std::unordered_map<std::string, std::vector<const texture_t*>> g_dups;
std::map<std::string, std::vector<std::string>> g_warnings;
srb2::HashMap<srb2::String, srb2::Vector<const texture_t*>> g_dups;
std::map<srb2::String, srb2::Vector<srb2::String>> g_warnings;
std::thread g_dups_thread;
std::string key8char(const char cstr[8])
srb2::String key8char(const char cstr[8])
{
std::string_view view(cstr, 8);
std::string key;
srb2::String key;
view = view.substr(0, view.find('\0')); // terminate by '\0'
key.reserve(view.size());
@ -50,7 +50,7 @@ std::string key8char(const char cstr[8])
return key;
}
std::string texture_location(const texture_t& tex)
srb2::String texture_location(const texture_t& tex)
{
if (tex.type == TEXTURETYPE_SINGLEPATCH)
{
@ -59,7 +59,7 @@ std::string texture_location(const texture_t& tex)
const texpatch_t& texpat = tex.patches[0];
const wadfile_t& wad = *wadfiles[texpat.wad];
return fmt::format(
return srb2::format(
"'{}/{}'",
std::filesystem::path(wad.filename).filename().string(),
wad.lumpinfo[texpat.lump].fullname
@ -108,7 +108,7 @@ void R_CheckTextureDuplicates(INT32 start, INT32 end)
auto collate_dups = [end, find_dup](int32_t start)
{
const texture_t* t1 = textures[start];
const std::string key = key8char(t1->name);
const srb2::String key = key8char(t1->name);
if (g_dups.find(key) != g_dups.end())
{
@ -119,7 +119,7 @@ void R_CheckTextureDuplicates(INT32 start, INT32 end)
if (idx < end)
{
std::vector<const texture_t*>& v = g_dups[key];
srb2::Vector<const texture_t*>& v = g_dups[key];
v.push_back(textures[start]);
@ -175,7 +175,7 @@ void R_PrintTextureWarnings(void)
{
CONS_Alert(CONS_WARNING, "\n%s", header.c_str());
for (const std::string& warning : v)
for (const srb2::String& warning : v)
{
CONS_Printf("%s\n", warning.c_str());
}

View file

@ -14,13 +14,13 @@
#include <string>
#include <string_view>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <fmt/format.h>
#include <glad/gl.h>
#include <glm/gtc/type_ptr.hpp>
#include "../../core/vector.hpp"
#include "../shader_load_context.hpp"
using namespace srb2;
@ -840,8 +840,8 @@ rhi::Handle<rhi::Program> Gl2Rhi::create_program(const ProgramDesc& desc)
// breaks the AMD driver's program linker in a bizarre way.
// Process shader sources
std::vector<const char*> vert_sources;
std::vector<const char*> frag_sources;
srb2::Vector<const char*> vert_sources;
srb2::Vector<const char*> frag_sources;
ShaderLoadContext vert_ctx;
ShaderLoadContext frag_ctx;
vert_ctx.set_version("120");
@ -873,11 +873,11 @@ rhi::Handle<rhi::Program> Gl2Rhi::create_program(const ProgramDesc& desc)
{
GLint max_length = 0;
gl_->GetShaderiv(program.vertex_shader, GL_INFO_LOG_LENGTH, &max_length);
std::vector<GLchar> compile_error(max_length);
srb2::Vector<GLchar> compile_error(max_length);
gl_->GetShaderInfoLog(program.vertex_shader, max_length, &max_length, compile_error.data());
gl_->DeleteShader(program.vertex_shader);
throw std::runtime_error(fmt::format("Vertex shader compilation failed: {}", std::string(compile_error.data())));
throw std::runtime_error(fmt::format("Vertex shader compilation failed: {}", String(compile_error.data())));
}
program.fragment_shader = gl_->CreateShader(GL_FRAGMENT_SHADER);
@ -889,11 +889,11 @@ rhi::Handle<rhi::Program> Gl2Rhi::create_program(const ProgramDesc& desc)
{
GLint max_length = 0;
gl_->GetShaderiv(program.fragment_shader, GL_INFO_LOG_LENGTH, &max_length);
std::vector<GLchar> compile_error(max_length);
srb2::Vector<GLchar> compile_error(max_length);
gl_->GetShaderInfoLog(program.fragment_shader, max_length, &max_length, compile_error.data());
gl_->DeleteShader(program.fragment_shader);
throw std::runtime_error(fmt::format("Fragment shader compilation failed: {}", std::string(compile_error.data())));
throw std::runtime_error(fmt::format("Fragment shader compilation failed: {}", String(compile_error.data())));
}
program.program = gl_->CreateProgram();
@ -907,13 +907,13 @@ rhi::Handle<rhi::Program> Gl2Rhi::create_program(const ProgramDesc& desc)
{
GLint max_length = 0;
gl_->GetProgramiv(program.program, GL_INFO_LOG_LENGTH, &max_length);
std::vector<GLchar> link_error(max_length);
srb2::Vector<GLchar> link_error(max_length);
gl_->GetProgramInfoLog(program.program, max_length, &max_length, link_error.data());
gl_->DeleteProgram(program.program);
gl_->DeleteShader(program.fragment_shader);
gl_->DeleteShader(program.vertex_shader);
throw std::runtime_error(fmt::format("Pipeline program link failed: {}", std::string(link_error.data())));
throw std::runtime_error(fmt::format("Pipeline program link failed: {}", String(link_error.data())));
}
// get attribute information
@ -936,7 +936,7 @@ rhi::Handle<rhi::Program> Gl2Rhi::create_program(const ProgramDesc& desc)
GL_ASSERT;
GLint location = gl_->GetAttribLocation(program.program, name);
GL_ASSERT;
program.attrib_locations[std::string(name)] = location;
program.attrib_locations[String(name)] = location;
}
// get uniform information
@ -959,7 +959,7 @@ rhi::Handle<rhi::Program> Gl2Rhi::create_program(const ProgramDesc& desc)
GL_ASSERT;
GLint location = gl_->GetUniformLocation(program.program, name);
GL_ASSERT;
program.uniform_locations[std::string(name)] = location;
program.uniform_locations[String(name)] = location;
}
Handle<Program> program_handle = program_slab_.insert(std::move(program));

View file

@ -14,11 +14,11 @@
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <unordered_map>
#include <vector>
#include "../../core/hash_map.hpp"
#include "../../core/string.h"
#include "../../core/vector.hpp"
#include "../rhi.hpp"
namespace srb2::rhi
@ -71,7 +71,7 @@ struct Gl2Platform
virtual ~Gl2Platform();
virtual void present() = 0;
virtual std::tuple<std::vector<std::string>, std::vector<std::string>> find_shader_sources(const char* name) = 0;
virtual std::tuple<srb2::Vector<srb2::String>, srb2::Vector<srb2::String>> find_shader_sources(const char* name) = 0;
virtual Rect get_default_framebuffer_dimensions() = 0;
};
@ -98,8 +98,8 @@ struct Gl2Program : public rhi::Program
uint32_t vertex_shader = 0;
uint32_t fragment_shader = 0;
uint32_t program = 0;
std::unordered_map<std::string, uint32_t> attrib_locations;
std::unordered_map<std::string, uint32_t> uniform_locations;
srb2::HashMap<srb2::String, uint32_t> attrib_locations;
srb2::HashMap<srb2::String, uint32_t> uniform_locations;
};
struct Gl2ActiveUniform
@ -121,14 +121,14 @@ class Gl2Rhi final : public Rhi
Handle<Buffer> current_index_buffer_;
std::unordered_map<Gl2FramebufferKey, uint32_t> framebuffers_ {16};
srb2::HashMap<Gl2FramebufferKey, uint32_t> framebuffers_ {16};
struct DefaultRenderPassState
{
bool clear = false;
};
using RenderPassState = std::variant<DefaultRenderPassState, RenderPassBeginInfo>;
std::vector<RenderPassState> render_pass_stack_;
srb2::Vector<RenderPassState> render_pass_stack_;
std::optional<Handle<Program>> current_program_;
PrimitiveType current_primitive_type_ = PrimitiveType::kPoints;
uint32_t index_buffer_offset_ = 0;

View file

@ -12,6 +12,9 @@
#include <fmt/core.h>
#include "../core/string.h"
#include "../core/vector.hpp"
using namespace srb2;
using namespace rhi;
@ -19,27 +22,27 @@ ShaderLoadContext::ShaderLoadContext() = default;
void ShaderLoadContext::set_version(std::string_view version)
{
version_ = fmt::format("#version {}\n", version);
version_ = srb2::format("#version {}\n", version);
}
void ShaderLoadContext::add_source(const std::string& source)
void ShaderLoadContext::add_source(const srb2::String& source)
{
sources_.push_back(source);
}
void ShaderLoadContext::add_source(std::string&& source)
void ShaderLoadContext::add_source(srb2::String&& source)
{
sources_.push_back(std::move(source));
}
void ShaderLoadContext::define(std::string_view name)
{
defines_.append(fmt::format("#define {}\n", name));
defines_.append(srb2::format("#define {}\n", name));
}
std::vector<const char*> ShaderLoadContext::get_sources_array()
srb2::Vector<const char*> ShaderLoadContext::get_sources_array()
{
std::vector<const char*> ret;
srb2::Vector<const char*> ret;
ret.push_back(version_.c_str());
ret.push_back(defines_.c_str());

View file

@ -11,29 +11,30 @@
#ifndef __SRB2_RHI_SHADER_LOAD_CONTEXT_HPP__
#define __SRB2_RHI_SHADER_LOAD_CONTEXT_HPP__
#include <string>
#include <string_view>
#include <vector>
#include "../core/string.h"
#include "../core/vector.hpp"
namespace srb2::rhi
{
class ShaderLoadContext
{
std::string version_;
std::string defines_;
std::vector<std::string> sources_;
srb2::String version_;
srb2::String defines_;
srb2::Vector<srb2::String> sources_;
public:
ShaderLoadContext();
void set_version(std::string_view version);
void add_source(const std::string& source);
void add_source(std::string&& source);
void add_source(const srb2::String& source);
void add_source(srb2::String&& source);
void define(std::string_view name);
std::vector<const char*> get_sources_array();
srb2::Vector<const char*> get_sources_array();
};
}; // namespace srb2::rhi

View file

@ -11,9 +11,9 @@
#include <algorithm>
#include <cctype>
#include <iterator>
#include <string>
#include <string_view>
#include "core/string.h"
#include "doomtype.h"
#include "sanitize.h"
#include "v_draw.hpp"
@ -34,7 +34,7 @@ bool color_filter(char c)
}
template <typename F>
std::string& filter_out(std::string& out, const std::string_view& range, F filter)
srb2::String& filter_out(srb2::String& out, const std::string_view& range, F filter)
{
std::remove_copy_if(
range.begin(),
@ -62,9 +62,9 @@ int hexconv(int c)
namespace srb2::sanitize
{
std::string sanitize(std::string_view in, SanitizeMode mode)
srb2::String sanitize(std::string_view in, SanitizeMode mode)
{
std::string out;
srb2::String out;
return filter_out(out, in, [mode]
{
switch (mode)
@ -78,9 +78,9 @@ std::string sanitize(std::string_view in, SanitizeMode mode)
}());
}
std::string parse_carets(std::string_view in, ParseMode mode)
srb2::String parse_carets(std::string_view in, ParseMode mode)
{
std::string out;
srb2::String out;
using std::size_t;
for (;;)

View file

@ -14,9 +14,10 @@
#include "doomtype.h"
#ifdef __cplusplus
#include <string>
#include <string_view>
#include "core/string.h"
namespace srb2::sanitize
{
@ -33,10 +34,10 @@ enum class ParseMode
};
// sanitizes string of all 0x80 codes
std::string sanitize(std::string_view in, SanitizeMode mode);
srb2::String sanitize(std::string_view in, SanitizeMode mode);
// sanitizes string of all 0x80 codes then parses caret codes
std::string parse_carets(std::string_view in, ParseMode mode);
srb2::String parse_carets(std::string_view in, ParseMode mode);
}; // namespace srb2

View file

@ -17,10 +17,10 @@
#include "../d_main.h"
#include "../m_misc.h"/* path shit */
#include "../i_system.h"
#include "../core/string.h"
#include <exception>
#include <stdexcept>
#include <string>
#include <tracy/tracy/Tracy.hpp>
@ -227,14 +227,14 @@ ChDirToExe (void)
}
#endif
static void walk_exception_stack(std::string& accum, bool nested) {
static void walk_exception_stack(srb2::String& accum, bool nested) {
if (nested)
accum.append("\n Caused by: Unknown exception");
else
accum.append("Uncaught exception: Unknown exception");
}
static void walk_exception_stack(std::string& accum, const std::exception& ex, bool nested) {
static void walk_exception_stack(srb2::String& accum, const std::exception& ex, bool nested) {
if (nested)
accum.append("\n Caused by: ");
else
@ -331,11 +331,11 @@ int main(int argc, char **argv)
D_SRB2Loop();
} catch (const std::exception& ex) {
std::string exception;
srb2::String exception;
walk_exception_stack(exception, ex, false);
I_Error("%s", exception.c_str());
} catch (...) {
std::string exception;
srb2::String exception;
walk_exception_stack(exception, false);
I_Error("%s", exception.c_str());
}

View file

@ -11,11 +11,13 @@
#include "rhi_gl2_platform.hpp"
#include <array>
#include <string>
#include <sstream>
#include <SDL.h>
#include <fmt/core.h>
#include "../core/string.h"
#include "../core/vector.hpp"
#include "../cxxutil.hpp"
#include "../doomstat.h" // mainwads
#include "../w_wad.h"
@ -34,22 +36,22 @@ void SdlGl2Platform::present()
SDL_GL_SwapWindow(window);
}
static std::array<std::string, 2> glsllist_lump_names(const char* name)
static std::array<srb2::String, 2> glsllist_lump_names(const char* name)
{
std::string vertex_list_name = fmt::format("rhi_glsllist_{}_vertex.txt", name);
std::string fragment_list_name = fmt::format("rhi_glsllist_{}_fragment.txt", name);
srb2::String vertex_list_name = fmt::format("rhi_glsllist_{}_vertex.txt", name);
srb2::String fragment_list_name = fmt::format("rhi_glsllist_{}_fragment.txt", name);
return {std::move(vertex_list_name), std::move(fragment_list_name)};
}
static std::vector<std::string> get_sources_from_glsllist_lump(const char* lumpname)
static srb2::Vector<srb2::String> get_sources_from_glsllist_lump(const char* lumpname)
{
size_t buffer_size;
if (!W_ReadShader(lumpname, &buffer_size, nullptr))
{
throw std::runtime_error(fmt::format("Unable to find glsllist lump {}", lumpname));
}
std::string glsllist_lump_data;
srb2::String glsllist_lump_data;
glsllist_lump_data.resize(buffer_size);
if (!W_ReadShader(lumpname, &buffer_size, glsllist_lump_data.data()))
{
@ -57,7 +59,7 @@ static std::vector<std::string> get_sources_from_glsllist_lump(const char* lumpn
}
std::istringstream glsllist(glsllist_lump_data);
std::vector<std::string> sources;
srb2::Vector<srb2::String> sources;
for (std::string line; std::getline(glsllist, line); )
{
if (line.empty())
@ -87,7 +89,7 @@ static std::vector<std::string> get_sources_from_glsllist_lump(const char* lumpn
{
throw std::runtime_error(fmt::format("Unable to find glsl source lump lump {}", line));
}
std::string source_lump;
srb2::String source_lump;
source_lump.resize(source_lump_size);
if (!W_ReadShader(line.c_str(), &source_lump_size, source_lump.data()))
{
@ -100,13 +102,13 @@ static std::vector<std::string> get_sources_from_glsllist_lump(const char* lumpn
return sources;
}
std::tuple<std::vector<std::string>, std::vector<std::string>>
std::tuple<srb2::Vector<srb2::String>, srb2::Vector<srb2::String>>
SdlGl2Platform::find_shader_sources(const char* name)
{
std::array<std::string, 2> glsllist_names = glsllist_lump_names(name);
std::array<srb2::String, 2> glsllist_names = glsllist_lump_names(name);
std::vector<std::string> vertex_sources = get_sources_from_glsllist_lump(glsllist_names[0].c_str());
std::vector<std::string> fragment_sources = get_sources_from_glsllist_lump(glsllist_names[1].c_str());
srb2::Vector<srb2::String> vertex_sources = get_sources_from_glsllist_lump(glsllist_names[0].c_str());
srb2::Vector<srb2::String> fragment_sources = get_sources_from_glsllist_lump(glsllist_names[1].c_str());
return std::make_tuple(std::move(vertex_sources), std::move(fragment_sources));
}

View file

@ -11,6 +11,10 @@
#ifndef __SRB2_SDL_RHI_GL2_PLATFORM_HPP__
#define __SRB2_SDL_RHI_GL2_PLATFORM_HPP__
#include <tuple>
#include "../core/string.h"
#include "../core/vector.hpp"
#include "../rhi/gl2/gl2_rhi.hpp"
#include "../rhi/rhi.hpp"
@ -26,7 +30,7 @@ struct SdlGl2Platform final : public Gl2Platform
virtual ~SdlGl2Platform();
virtual void present() override;
virtual std::tuple<std::vector<std::string>, std::vector<std::string>>
virtual std::tuple<Vector<srb2::String>, Vector<srb2::String>>
find_shader_sources(const char* name) override;
virtual Rect get_default_framebuffer_dimensions() override;
};

View file

@ -8,8 +8,7 @@
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#include <unordered_map>
#include "core/hash_map.hpp"
#include "doomdef.h" // skincolornum_t
#include "doomtype.h"
#include "hu_stuff.h"
@ -34,7 +33,7 @@ int Draw::TextElement::width() const
Draw::TextElement& Draw::TextElement::parse(std::string_view raw)
{
static const std::unordered_map<std::string_view, char> translation = {
static const srb2::HashMap<std::string_view, char> translation = {
#define BUTTON(str, lower_bits) \
{str, 0xB0 | lower_bits},\
{str "_animated", 0xA0 | lower_bits},\
@ -88,7 +87,7 @@ Draw::TextElement& Draw::TextElement::parse(std::string_view raw)
};
// When we encounter a Saturn button, what gamecontrol does it represent?
static const std::unordered_map<char, gamecontrols_e> inputdefinition = {
static const srb2::HashMap<char, gamecontrols_e> inputdefinition = {
{sb_up, gc_up},
{sb_down, gc_down},
{sb_right, gc_right},
@ -114,7 +113,7 @@ Draw::TextElement& Draw::TextElement::parse(std::string_view raw)
// What physical binds should appear as Saturn icons anyway?
// (We don't have generic binds for stick/dpad directions, so
// using the existing arrow graphics is the best thing here.)
static const std::unordered_map<INT32, char> prettyinputs = {
static const srb2::HashMap<INT32, char> prettyinputs = {
{KEY_UPARROW, sb_up},
{KEY_DOWNARROW, sb_down},
{KEY_LEFTARROW, sb_left},
@ -164,7 +163,7 @@ Draw::TextElement& Draw::TextElement::parse(std::string_view raw)
// SPECIAL: Generic button that we invoke explicitly, not via gamecontrol reference.
// If we ever add anything else to this category, I promise I will create a real abstraction,
// but for now, just hardcode the character replacements and pray for forgiveness.
string_.push_back(0xEF); // Control code: "switch to descriptive input mode"
string_.push_back(0xEB); // Control code: "large button"
if (code == "dpad")
@ -198,7 +197,7 @@ Draw::TextElement& Draw::TextElement::parse(std::string_view raw)
// EXTRA: descriptiveinput values above 1 translate binds back to Saturn buttons,
// with various modes for various fucked up 6bt pads
std::unordered_map<INT32, char> padconfig = {};
srb2::HashMap<INT32, char> padconfig = {};
switch (cv_descriptiveinput[localplayer].value)
{
case 1:
@ -277,7 +276,7 @@ Draw::TextElement& Draw::TextElement::parse(std::string_view raw)
pad->second = pad->second & (0x0F);
// original invocation has the animation bits, but the glyph bits come from the table
string_.push_back((it->second & 0xF0) | pad->second);
string_.push_back((it->second & 0xF0) | pad->second);
}
else
{
@ -349,6 +348,11 @@ void Chain::fill(UINT8 color) const
void Chain::string(const char* str, INT32 flags, Font font) const
{
if (!str)
{
return;
}
const auto _ = Clipper(*this);
flags |= default_font_flags(font);
@ -576,5 +580,10 @@ INT32 Draw::default_font_flags(Font font)
fixed_t Draw::font_width(Font font, INT32 flags, const char* string)
{
if (!string)
{
return 0;
}
return V_StringScaledWidth(FRACUNIT, FRACUNIT, FRACUNIT, flags, font_to_fontno(font), string);
}

View file

@ -11,14 +11,14 @@
#ifndef __V_DRAW_HPP__
#define __V_DRAW_HPP__
#include <string>
#include <string_view>
#include <optional>
#include <utility>
#include <unordered_map>
#include <fmt/core.h>
#include "core/hash_map.hpp"
#include "core/string.h"
#include "doomdef.h" // skincolornum_t
#include "doomtype.h"
#include "screen.h" // BASEVIDWIDTH
@ -66,7 +66,7 @@ typedef enum
} saturn_buttons_e;
// Garden-variety standard gamepad
static const std::unordered_map<INT32, char> standardpad = {
static const srb2::HashMap<INT32, char> standardpad = {
{nc_a, gb_a},
{nc_b, gb_b},
{nc_x, gb_x},
@ -83,7 +83,7 @@ static const std::unordered_map<INT32, char> standardpad = {
// Standard gamepad, but evil Nintendo layout flip was applied by your
// controller firmware or Steam Input—swap B/A and X/Y
static const std::unordered_map<INT32, char> flippedpad = {
static const srb2::HashMap<INT32, char> flippedpad = {
{nc_a, gb_b},
{nc_b, gb_a},
{nc_x, gb_y},
@ -99,7 +99,7 @@ static const std::unordered_map<INT32, char> flippedpad = {
};
// Saturn Type A - Retrobit Wired Dinput, RB RT LB LT (CZLR)
static const std::unordered_map<INT32, char> saturntypeA = {
static const srb2::HashMap<INT32, char> saturntypeA = {
{nc_a, sb_a},
{nc_b, sb_b},
{nc_x, sb_x},
@ -115,7 +115,7 @@ static const std::unordered_map<INT32, char> saturntypeA = {
};
// Saturn Type B - Retrobit Wireless Dinput, LB RB LT RT (CZLR)
static const std::unordered_map<INT32, char> saturntypeB = {
static const srb2::HashMap<INT32, char> saturntypeB = {
{nc_a, sb_a},
{nc_b, sb_b},
{nc_x, sb_x},
@ -131,7 +131,7 @@ static const std::unordered_map<INT32, char> saturntypeB = {
};
// Saturn Type C - Retrobit Xinput, RT LT LB RB (CZLR)
static const std::unordered_map<INT32, char> saturntypeC = {
static const srb2::HashMap<INT32, char> saturntypeC = {
{nc_a, sb_a},
{nc_b, sb_b},
{nc_x, sb_x},
@ -150,7 +150,7 @@ static const std::unordered_map<INT32, char> saturntypeC = {
// This cannot be disambiguated (shares L/R with type 1)
// but is more spatially correct w/r/t SDL expectations
// and standard arcade mapping (Z on top, C on bottom)
static const std::unordered_map<INT32, char> saturntypeD = {
static const srb2::HashMap<INT32, char> saturntypeD = {
{nc_a, sb_a},
{nc_b, sb_b},
{nc_x, sb_x},
@ -169,7 +169,7 @@ static const std::unordered_map<INT32, char> saturntypeD = {
// The Hori layout is, to my knowledge, the only 6bt one that has fully
// unique buttons in every slot while having both bumpers and triggers,
// so there's no way to accurately portray it without using generics.
static const std::unordered_map<INT32, char> saturntypeE = {
static const srb2::HashMap<INT32, char> saturntypeE = {
{nc_a, sb_a},
{nc_b, sb_b},
{nc_x, sb_x},
@ -263,7 +263,7 @@ public:
public:
explicit TextElement() {}
explicit TextElement(std::string string) : string_(string) {}
explicit TextElement(const srb2::String& string) : string_(string) {}
template <class... Args>
explicit TextElement(fmt::format_string<Args...> format, Args&&... args) :
@ -271,14 +271,14 @@ public:
{
}
const std::string& string() const { return string_; }
const srb2::String& string() const { return string_; }
std::optional<Font> font() const { return font_; }
std::optional<INT32> flags() const { return flags_; }
std::optional<UINT8> as() const { return as_; }
int width() const;
TextElement& string(std::string string)
TextElement& string(srb2::String string)
{
string_ = string;
return *this;
@ -310,7 +310,7 @@ public:
return *this;
}
private:
std::string string_;
srb2::String string_;
std::optional<Font> font_;
std::optional<INT32> flags_;
std::optional<UINT8> as_;
@ -357,7 +357,7 @@ public:
Chain& colorize(UINT16 color);
void text(const char* str) const { string(str, flags_, font_); }
void text(const std::string& str) const { text(str.c_str()); }
void text(const srb2::String& str) const { text(str.c_str()); }
void text(const TextElement& elm) const
{
string(elm.string().c_str(), elm.flags().value_or(flags_), elm.font().value_or(font_));
@ -370,7 +370,7 @@ public:
void patch(patch_t* patch) const;
void patch(const char* name) const { patch(Draw::cache_patch(name)); }
void patch(const std::string& name) const { patch(name.c_str()); }
void patch(const srb2::String& name) const { patch(name.c_str()); }
void thumbnail(UINT16 mapnum) const;

View file

@ -322,9 +322,9 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
{
srb2::StandingJson standing {};
standing.ranking = data.pos[data.numplayers];
standing.name = std::string(player_names[i]);
standing.name = srb2::String(player_names[i]);
standing.demoskin = players[i].skin;
standing.skincolor = std::string(skincolors[players[i].skincolor].name);
standing.skincolor = srb2::String(skincolors[players[i].skincolor].name);
standing.timeorscore = data.val[data.numplayers];
standings.standings.emplace_back(std::move(standing));
}