mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
Implement dictionary type.
Basically a fast (hybrid) contiguous hash map.
This commit is contained in:
parent
3c30b9c7a2
commit
323dc3ad1b
@ -86,6 +86,7 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp
|
||||
Library/System/Path.cpp Library/System/Path.hpp
|
||||
Library/Utils.cpp Library/Utils.hpp
|
||||
Library/Utils/Announce.cpp Library/Utils/Announce.hpp
|
||||
Library/Utils/Dictionary.cpp Library/Utils/Dictionary.hpp
|
||||
Library/Utils/Map.cpp Library/Utils/Map.hpp
|
||||
Library/Utils/String.cpp Library/Utils/String.hpp
|
||||
Library/Utils/Vector.cpp Library/Utils/Vector.hpp
|
||||
|
@ -85,6 +85,7 @@ static SQInteger SqExtractIPv4(HSQUIRRELVM vm)
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern void Register_Map(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_Vector(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_Dictionary(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_Native_String(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_ServerAnnouncer(HSQUIRRELVM vm, Table & ns);
|
||||
|
||||
@ -95,6 +96,7 @@ void Register_Utils(HSQUIRRELVM vm)
|
||||
|
||||
Register_Map(vm, ns);
|
||||
Register_Vector(vm, ns);
|
||||
Register_Dictionary(vm, ns);
|
||||
Register_Native_String(vm, ns);
|
||||
Register_ServerAnnouncer(vm, ns);
|
||||
|
||||
|
35
module/Library/Utils/Dictionary.cpp
Normal file
35
module/Library/Utils/Dictionary.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Library/Utils/Dictionary.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMOD_DECL_TYPENAME(SqDictionaryTn, _SC("SqDictionary"))
|
||||
|
||||
// ================================================================================================
|
||||
void Register_Dictionary(HSQUIRRELVM vm, Table & ns)
|
||||
{
|
||||
ns.Bind(_SC("Dictionary"),
|
||||
Class< SqDictionary >(vm, SqDictionaryTn::Str)
|
||||
// Constructors
|
||||
.Ctor()
|
||||
.Ctor< SQInteger >()
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &SqDictionaryTn::Fn)
|
||||
// Properties
|
||||
.Prop(_SC("Empty"), &SqDictionary::Empty)
|
||||
.Prop(_SC("Size"), &SqDictionary::Size)
|
||||
// Member Methods
|
||||
.Func(_SC("Get"), &SqDictionary::Get)
|
||||
.Func(_SC("Set"), &SqDictionary::Set)
|
||||
.Func(_SC("Clear"), &SqDictionary::Clear)
|
||||
.Func(_SC("Erase"), &SqDictionary::Erase)
|
||||
.CbFunc(_SC("Each"), &SqDictionary::Each)
|
||||
.CbFunc(_SC("EachWith"), &SqDictionary::EachWith)
|
||||
.CbFunc(_SC("While"), &SqDictionary::While)
|
||||
.CbFunc(_SC("WhileWith"), &SqDictionary::WhileWith)
|
||||
);
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
289
module/Library/Utils/Dictionary.hpp
Normal file
289
module/Library/Utils/Dictionary.hpp
Normal file
@ -0,0 +1,289 @@
|
||||
#pragma once
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Utility.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace Sqrat {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Helper type used to retrieve the hash of a value instead of the value itself.
|
||||
*/
|
||||
struct SqKeyHash
|
||||
{
|
||||
SQHash mH{};
|
||||
constexpr SqKeyHash() noexcept = default;
|
||||
constexpr explicit SqKeyHash(SQHash h) noexcept : mH(h) { }
|
||||
constexpr SqKeyHash(const SqKeyHash &) noexcept = default;
|
||||
constexpr SqKeyHash & operator = (const SqKeyHash &) noexcept = default;
|
||||
constexpr operator SQHash () const noexcept { return mH; } //NOLINT (explicit)
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Allows the binding system to know how to interact with SqKeyHash type.
|
||||
*/
|
||||
template < > struct Var< SqKeyHash > {
|
||||
|
||||
SqKeyHash value;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
Var(HSQUIRRELVM vm, SQInteger idx) noexcept : value(sq_gethash(vm, idx)) { }
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Push the associated object on the stack.
|
||||
*/
|
||||
static void push(HSQUIRRELVM vm, const SqKeyHash& value)
|
||||
{
|
||||
sq_pushinteger(vm, static_cast< SQInteger >(value));
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Specialization for SqKeyHash reference.
|
||||
*/
|
||||
template < > struct Var< SqKeyHash & > : Var< SqKeyHash >
|
||||
{
|
||||
Var(HSQUIRRELVM vm, SQInteger idx) noexcept : Var< SqKeyHash >(vm, idx) { }
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Specialization for constant SqKeyHash reference.
|
||||
*/
|
||||
template < > struct Var< const SqKeyHash & > : Var< SqKeyHash >
|
||||
{
|
||||
Var(HSQUIRRELVM vm, SQInteger idx) noexcept : Var< SqKeyHash >(vm, idx) { }
|
||||
};
|
||||
|
||||
} // Namespace:: Sqrat
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Wrapper around a std::vector of std::pair values. Efficient contiguous associative container.
|
||||
*/
|
||||
struct SqDictionary
|
||||
{
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Type stored in the container.
|
||||
*/
|
||||
using Element = std::pair< SQHash, LightObj >;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* The typeof container that will be used.
|
||||
*/
|
||||
using Container = std::vector< Element >;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Container instance.
|
||||
*/
|
||||
Container mC{};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
SqDictionary() = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Construct with initial capacity. No element is created.
|
||||
*/
|
||||
explicit SqDictionary(SQInteger n)
|
||||
: SqDictionary()
|
||||
{
|
||||
mC.reserve(static_cast< size_t >(n));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
SqDictionary(const SqDictionary &) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
SqDictionary(SqDictionary &&) noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destroys the Statement.
|
||||
*/
|
||||
~SqDictionary() = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Assignment operator.
|
||||
*/
|
||||
SqDictionary & operator = (const SqDictionary &) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment.
|
||||
*/
|
||||
SqDictionary & operator = (SqDictionary &&) noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve a value from the container.
|
||||
*/
|
||||
SQMOD_NODISCARD LightObj & Get(SqKeyHash k)
|
||||
{
|
||||
for (auto & e : mC)
|
||||
{
|
||||
if (e.first == k.mH) return e.second;
|
||||
}
|
||||
// See if we can get the specified value as a string
|
||||
StackStrF val(SqVM(), 2);
|
||||
// Include the value in the error if we can
|
||||
if (SQ_SUCCEEDED(val.Proc(false)))
|
||||
{
|
||||
STHROWF("No element found for ({}) key", val.ToStr());
|
||||
}
|
||||
else
|
||||
{
|
||||
STHROWF("No element found for specified key");
|
||||
}
|
||||
// This should not be reached
|
||||
SQ_UNREACHABLE
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify a value from the container.
|
||||
*/
|
||||
void Set(SqKeyHash k, LightObj & v)
|
||||
{
|
||||
for (auto & e : mC)
|
||||
{
|
||||
if (e.first == k.mH)
|
||||
{
|
||||
e.second = std::move(v);
|
||||
return; // We updated existing element
|
||||
}
|
||||
}
|
||||
// Create the element now
|
||||
mC.emplace_back(k.mH, std::move(v));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Check if the container has no elements.
|
||||
*/
|
||||
SQMOD_NODISCARD bool Empty() const
|
||||
{
|
||||
return mC.empty();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of elements in the container.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger Size() const
|
||||
{
|
||||
return static_cast< SQInteger >(mC.size());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of elements that the container has currently allocated space for.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger Capacity() const
|
||||
{
|
||||
return static_cast< SQInteger >(mC.capacity());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Increase the capacity of the container to a value that's greater or equal to the one specified.
|
||||
*/
|
||||
SqDictionary & Reserve(SQInteger n)
|
||||
{
|
||||
mC.reserve(ClampL< SQInteger, size_t >(n));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Request the removal of unused capacity.
|
||||
*/
|
||||
void Compact()
|
||||
{
|
||||
mC.shrink_to_fit();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Erase all elements from the container.
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
mC.clear();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Erase the element with the specified key.
|
||||
*/
|
||||
bool Erase(SqKeyHash k)
|
||||
{
|
||||
auto itr = std::find_if(mC.cbegin(), mC.cend(),
|
||||
[&](Container::const_reference e) -> bool { return e.first == k.mH; });
|
||||
if (itr != mC.end())
|
||||
{
|
||||
mC.erase(itr);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all values through a functor.
|
||||
*/
|
||||
void Each(Function & fn) const
|
||||
{
|
||||
for (const auto & e : mC)
|
||||
{
|
||||
fn.Execute(static_cast< SQInteger >(e.first), e.second);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all values through a functor.
|
||||
*/
|
||||
void EachWith(LightObj & ctx, Function & fn) const
|
||||
{
|
||||
for (const auto & e : mC)
|
||||
{
|
||||
fn.Execute(ctx, static_cast< SQInteger >(e.first), e.second);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all values through a functor until stopped (i.e false is returned).
|
||||
*/
|
||||
void While(Function & fn) const
|
||||
{
|
||||
for (const auto & e : mC)
|
||||
{
|
||||
auto ret = fn.Eval(static_cast< SQInteger >(e.first), e.second);
|
||||
// (null || true) == continue & false == break
|
||||
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all values through a functor until stopped (i.e false is returned).
|
||||
*/
|
||||
void WhileWith(LightObj & ctx, Function & fn) const
|
||||
{
|
||||
for (const auto & e : mC)
|
||||
{
|
||||
auto ret = fn.Eval(ctx, static_cast< SQInteger >(e.first), e.second);
|
||||
// (null || true) == continue & false == break
|
||||
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
@ -12,7 +12,7 @@ SQMOD_DECL_TYPENAME(SqMapString, _SC("SqMapString"))
|
||||
template < class T, class U >
|
||||
static void Register_Map(HSQUIRRELVM vm, Table & ns, const SQChar * name)
|
||||
{
|
||||
using Container = SqMap< T >;
|
||||
using Container = SqMap< T >;
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ns.Bind(name,
|
||||
Class< Container, NoCopy< Container > >(vm, U::Str)
|
||||
|
Loading…
Reference in New Issue
Block a user