mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
Add a basic ID pool.
This commit is contained in:
parent
c0d142ab34
commit
8d15f4b6e9
@ -8,6 +8,9 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMOD_DECL_TYPENAME(SqIdPoolTypename, _SC("SqIdPool"))
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Probably not the best implementation but should cover all sorts of weird cases.
|
||||
*/
|
||||
@ -83,15 +86,18 @@ static SQInteger SqExtractIPv4(HSQUIRRELVM vm)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern void Register_IdPool(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_Vector(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_Native_String(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_ServerAnnouncer(HSQUIRRELVM vm, Table & ns);
|
||||
|
||||
|
||||
// ================================================================================================
|
||||
void Register_Utils(HSQUIRRELVM vm)
|
||||
{
|
||||
Table ns(vm);
|
||||
|
||||
Register_IdPool(vm, ns);
|
||||
Register_Vector(vm, ns);
|
||||
Register_Native_String(vm, ns);
|
||||
Register_ServerAnnouncer(vm, ns);
|
||||
@ -101,4 +107,35 @@ void Register_Utils(HSQUIRRELVM vm)
|
||||
RootTable(vm).Bind(_SC("SqUtils"), ns);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Register_IdPool(HSQUIRRELVM vm, Table & ns)
|
||||
{
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ns.Bind(_SC("IdPool"),
|
||||
Class< SqIdPool, NoCopy< SqIdPool > >(vm, SqIdPoolTypename::Str)
|
||||
// Constructors
|
||||
.Ctor()
|
||||
.template Ctor< SqIdPool::Type >()
|
||||
.template Ctor< SqIdPool::Type, SqIdPool::Type >()
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &SqIdPoolTypename::Fn)
|
||||
// Member Variables
|
||||
.ConstVar(_SC("Next"), &SqIdPool::mNext)
|
||||
.ConstVar(_SC("Step"), &SqIdPool::mStep)
|
||||
.ConstVar(_SC("Start"), &SqIdPool::mStart)
|
||||
// Properties
|
||||
.Prop(_SC("FreeCount"), &SqIdPool::FreeCount)
|
||||
.Prop(_SC("UsedCount"), &SqIdPool::UsedCount)
|
||||
// Member Methods
|
||||
.Func(_SC("Reset"), &SqIdPool::Reset)
|
||||
.Func(_SC("Acquire"), &SqIdPool::Acquire)
|
||||
.Func(_SC("Release"), &SqIdPool::Release)
|
||||
.Func(_SC("Using"), &SqIdPool::Using)
|
||||
.Func(_SC("EachUsed"), &SqIdPool::EachUsed)
|
||||
.Func(_SC("WhileUsed"), &SqIdPool::WhileUsed)
|
||||
.Func(_SC("EachFree"), &SqIdPool::EachFree)
|
||||
.Func(_SC("WhileFree"), &SqIdPool::WhileFree)
|
||||
);
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
@ -6,4 +6,187 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Helper utility used to provide reusable unique IDs of signed integer type.
|
||||
* It is not thread-safe since the script runs in single-threaded mode.
|
||||
*/
|
||||
struct SqIdPool
|
||||
{
|
||||
using Type = SQInteger; // Type that is used to represent an ID.
|
||||
using Pool = std::vector< Type >; // Container for both used and unused IDs.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Pool of available IDs.
|
||||
Pool mPool{};
|
||||
// Pool of currently used IDs.
|
||||
Pool mUsed{};
|
||||
// The ID that will be generated next time the pool is empty.
|
||||
Type mNext{0};
|
||||
// How much to increment with each ID.
|
||||
Type mStep{1};
|
||||
// Where to start generating IDs.
|
||||
Type mStart{0};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructors.
|
||||
*/
|
||||
SqIdPool() noexcept = default;
|
||||
SqIdPool(Type start) noexcept
|
||||
: SqIdPool(start, 1)
|
||||
{
|
||||
}
|
||||
SqIdPool(Type start, Type step) noexcept
|
||||
: mPool(), mUsed(), mNext(start), mStep(step), mStart(start)
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy/Move constructors (disabled).
|
||||
*/
|
||||
SqIdPool(const SqIdPool &) noexcept = delete;
|
||||
SqIdPool(SqIdPool &&) noexcept = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy/Move assignment operators (disabled).
|
||||
*/
|
||||
SqIdPool & operator = (const SqIdPool &) noexcept = delete;
|
||||
SqIdPool & operator = (SqIdPool &&) noexcept = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Discard all current IDs (free and used) and reset the start to the specified start.
|
||||
* This invalidates all IDs that are currently left in use.
|
||||
*/
|
||||
void Reset()
|
||||
{
|
||||
mNext = mStart;
|
||||
mPool.clear();
|
||||
mUsed.clear();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Acquire a unique ID from the pool.
|
||||
*/
|
||||
SQMOD_NODISCARD Type Acquire()
|
||||
{
|
||||
Type id = mNext;
|
||||
// Do we have some reusable IDs?
|
||||
if (mPool.empty())
|
||||
{
|
||||
mNext += mStep; // Create a new one and update the next one
|
||||
}
|
||||
else
|
||||
{
|
||||
id = mPool.back(); // Get one from the back of the pool
|
||||
mPool.pop_back(); // Remove it from the free pool
|
||||
}
|
||||
// Store it in the list of active IDs
|
||||
mUsed.push_back(id);
|
||||
// Return this ID
|
||||
return id;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release a unique ID back to the pool.
|
||||
*/
|
||||
bool Release(Type id)
|
||||
{
|
||||
// Find the specified ID into
|
||||
for (Pool::size_type i = 0; i < mUsed.size(); ++i)
|
||||
{
|
||||
// Is this the ID we're looking for?
|
||||
if (mUsed[i] == id)
|
||||
{
|
||||
// Swap the element with the last one
|
||||
std::swap(mUsed[i], mUsed.back());
|
||||
// Remove the last element
|
||||
mUsed.pop_back();
|
||||
// Make this ID available, again
|
||||
mPool.push_back(id);
|
||||
// We actually found this ID
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// This ID does not belong to this pool
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Check if the pool has the specified ID currently in use.
|
||||
*/
|
||||
SQMOD_NODISCARD bool Using(Type id)
|
||||
{
|
||||
return std::find(mUsed.begin(), mUsed.end(), id) != mUsed.end();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of IDs that are currently available in the free pool.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger FreeCount() const
|
||||
{
|
||||
return mPool.size();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of IDs that are currently in use.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger UsedCount() const
|
||||
{
|
||||
return mUsed.size();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all used IDs through a functor.
|
||||
*/
|
||||
void EachUsed(Function & fn) const
|
||||
{
|
||||
for (const auto & id : mUsed)
|
||||
{
|
||||
fn.Execute(id);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all used IDs through a functor until stopped (i.e false is returned).
|
||||
*/
|
||||
void WhileUsed(Function & fn) const
|
||||
{
|
||||
for (const auto & id : mUsed)
|
||||
{
|
||||
auto ret = fn.Eval(id);
|
||||
// (null || true) == continue & false == break
|
||||
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all free IDs through a functor.
|
||||
*/
|
||||
void EachFree(Function & fn) const
|
||||
{
|
||||
for (const auto & id : mPool)
|
||||
{
|
||||
fn.Execute(id);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all free IDs through a functor until stopped (i.e false is returned).
|
||||
*/
|
||||
void WhileFree(Function & fn) const
|
||||
{
|
||||
for (const auto & id : mPool)
|
||||
{
|
||||
auto ret = fn.Eval(id);
|
||||
// (null || true) == continue & false == break
|
||||
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
Loading…
Reference in New Issue
Block a user