Files
botw/lib/sead/include/container/seadOrderedSet.h
T
Léo Lam 18c60323a9 Switch to subrepos
git subrepo clone https://github.com/open-ead/sead lib/sead

subrepo:
  subdir:   "lib/sead"
  merged:   "1b66e825d"
upstream:
  origin:   "https://github.com/open-ead/sead"
  branch:   "master"
  commit:   "1b66e825d"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

git subrepo clone (merge) https://github.com/open-ead/nnheaders lib/NintendoSDK

subrepo:
  subdir:   "lib/NintendoSDK"
  merged:   "9ee21399f"
upstream:
  origin:   "https://github.com/open-ead/nnheaders"
  branch:   "master"
  commit:   "9ee21399f"
git-subrepo:
  version:  "0.4.3"
  origin:   "ssh://git@github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

git subrepo clone https://github.com/open-ead/agl lib/agl

subrepo:
  subdir:   "lib/agl"
  merged:   "7c063271b"
upstream:
  origin:   "https://github.com/open-ead/agl"
  branch:   "master"
  commit:   "7c063271b"
git-subrepo:
  version:  "0.4.3"
  origin:   "ssh://git@github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

git subrepo clone https://github.com/open-ead/EventFlow lib/EventFlow

subrepo:
  subdir:   "lib/EventFlow"
  merged:   "c35d21b34"
upstream:
  origin:   "https://github.com/open-ead/EventFlow"
  branch:   "master"
  commit:   "c35d21b34"
git-subrepo:
  version:  "0.4.3"
  origin:   "ssh://git@github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"
2022-03-21 21:31:42 +01:00

190 lines
5.0 KiB
C++

#pragma once
#include "container/seadTreeMap.h"
namespace sead
{
/// Requires Value to have operator< defined
/// This can be specialized, but all specializations must define `compare` as follows.
template <typename Value>
struct OrderedSetItemImpl
{
OrderedSetItemImpl() = default;
// NOLINTNEXTLINE(google-explicit-constructor)
OrderedSetItemImpl(const Value& value_) : value(value_) {}
OrderedSetItemImpl& operator=(const Value& value_)
{
value = value_;
return *this;
}
/// Returns -1 if this->value < rhs, 0 if this->value = rhs and 1 if this->value > rhs.
s32 compare(const OrderedSetItemImpl& rhs) const
{
if (value < rhs.value)
return -1;
if (rhs.value < value)
return 1;
return 0;
}
Value value;
};
/// This is essentially std::set<Value>. Values are stored in a red-black tree in an order
/// determined by the partial order defined for Value (via operator<).
template <typename Value>
class OrderedSet : public TreeMapImpl<OrderedSetItemImpl<Value>>
{
public:
using MapImpl = TreeMapImpl<OrderedSetItemImpl<Value>>;
class Node : public MapImpl::Node
{
public:
Node(OrderedSet* set, const Value& value) : mSet(set) { this->mKey = value; }
void erase_() override;
// Values cannot be modified.
const Value& value() const { return this->key().value; }
private:
friend class OrderedSet;
OrderedSet* mSet;
};
/// Clears the set and frees the allocated buffer (if needed).
/// Should only be used if the buffer was allocated using allocBuffer.
void finalize()
{
clear();
freeBuffer();
}
bool allocBuffer(s32 node_max, Heap* heap, s32 alignment = sizeof(void*));
void setBuffer(s32 node_max, void* buffer);
/// Should only be used if the buffer was allocated using allocBuffer.
void freeBuffer();
const Value* insert(const Value& value);
void clear();
Node* find(const Value& value) const;
// Callable must have the signature Value&
template <typename Callable>
void forEach(const Callable& delegate) const;
Node* startIterating() const { return static_cast<Node*>(MapImpl::startIterating()); }
Node* nextNode(Node* node) const { return static_cast<Node*>(MapImpl::nextNode(node)); }
private:
void eraseNodeForClear_(typename MapImpl::Node* node);
FreeList mFreeList;
s32 mSize = 0;
s32 mCapacity = 0;
};
template <typename Value>
inline bool OrderedSet<Value>::allocBuffer(s32 node_max, Heap* heap, s32 alignment)
{
SEAD_ASSERT(mFreeList.work() == nullptr);
if (node_max <= 0)
{
SEAD_ASSERT_MSG(false, "node_max[%d] must be larger than zero", node_max);
AllocFailAssert(heap, node_max * sizeof(Node), alignment);
}
void* work = AllocBuffer(node_max * sizeof(Node), heap, alignment);
if (!work)
return false;
setBuffer(node_max, work);
return true;
}
template <typename Value>
inline void OrderedSet<Value>::setBuffer(s32 node_max, void* buffer)
{
mCapacity = node_max;
mFreeList.setWork(buffer, sizeof(Node), node_max);
}
template <typename Value>
inline void OrderedSet<Value>::freeBuffer()
{
void* buffer = mFreeList.work();
if (!buffer)
return;
mSize = 0;
MapImpl::clear();
::operator delete[](buffer);
mCapacity = 0;
mFreeList.reset();
}
template <typename Value>
inline const Value* OrderedSet<Value>::insert(const Value& value)
{
if (mSize >= mCapacity)
{
if (Node* node = find(value))
{
node->mKey = value;
return &node->value();
}
SEAD_ASSERT_MSG(false, "map is full.");
return nullptr;
}
Node* node = new (mFreeList.alloc()) Node(this, value);
++mSize;
MapImpl::insert(node);
return &node->value();
}
template <typename Value>
inline void OrderedSet<Value>::clear()
{
Delegate1<OrderedSet<Value>, typename MapImpl::Node*> delegate(this,
&OrderedSet::eraseNodeForClear_);
MapImpl::forEach(delegate);
mSize = 0;
MapImpl::clear();
}
template <typename Value>
inline typename OrderedSet<Value>::Node* OrderedSet<Value>::find(const Value& value) const
{
return static_cast<Node*>(MapImpl::find(value));
}
template <typename Value>
template <typename Callable>
inline void OrderedSet<Value>::forEach(const Callable& delegate) const
{
MapImpl::forEach([&delegate](auto* base_node) {
auto* node = static_cast<Node*>(base_node);
delegate(node->value());
});
}
template <typename Value>
inline void OrderedSet<Value>::eraseNodeForClear_(typename MapImpl::Node* node)
{
// Note: Nintendo does not call the destructor, which is dangerous...
mFreeList.free(node);
}
template <typename Value>
inline void OrderedSet<Value>::Node::erase_()
{
OrderedSet* const map = mSet;
void* const this_ = this;
// Note: Nintendo does not call the destructor, which is dangerous...
map->mFreeList.free(this_);
--map->mSize;
}
} // namespace sead