2020-03-22 00:45:04 +01:00
|
|
|
#pragma once
|
2016-02-27 10:57:10 +01:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-01-30 07:51:39 +01:00
|
|
|
#include "Core/Common.hpp"
|
2016-02-27 10:57:10 +01:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
namespace SqMod {
|
|
|
|
|
2023-03-05 18:51:09 +01:00
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-02-27 10:57:10 +01:00
|
|
|
} // Namespace:: SqMod
|