rott/kf_sources/AcediaCore/Classes/AcediaObjectPool.uc
2026-07-14 20:27:09 +07:00

166 lines
5.7 KiB
Ucode

/**
* Author: dkanus
* Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore
* License: GPL
* Copyright 2020-2024 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class AcediaObjectPool extends Object
config(AcediaSystem);
//! Acedia's implementation for object pool.
//!
//! Unlike generic built in [`Engine::ObjectPool`], that can only store objects
//! of one specific class, it specializes in a single class to allow for both
//! faster allocation and faster deallocation (we don't need to look for
//! an object of particular class to return an unused instance).
//!
//! Allows to set a maximum capacity in a config.
/// Represents config entry about pool capacity.
///
/// This struct and it's associated array [`poolSizeOverwrite`] allows server
/// admins to rewrite
/// the pool capacity for each class.
struct PoolSizeSetting {
var class<AcediaObject> objectClass;
var int maxPoolSize;
};
var private config const array<PoolSizeSetting> poolSizeOverwrite;
// Class of objects that this `AcediaObjectPool` stores.
// if `== none`, - object pool is considered uninitialized.
var private class<AcediaObject> storedClass;
// Capacity for object pool that we are using.
// Obtained from [`poolSizeOverwrite`] during initialization and cannot be changed later.
var private int usedMaxPoolSize;
// Actual storage, functions on LIFO principle.
var private array<AcediaObject> objectPool;
// Determines default object pool size for the initialization.
private final function int GetMaxPoolSizeForClass(class<AcediaObject> classToCheck) {
local int i;
local int result;
if (classToCheck != none) {
result = classToCheck.default.defaultMaxPoolSize;
}
else {
result = -1;
}
// Try to replace it with server's settings
for (i = 0; i < poolSizeOverwrite.length; i += 1) {
if (poolSizeOverwrite[i].objectClass == classToCheck) {
result = poolSizeOverwrite[i].maxPoolSize;
break;
}
}
return result;
}
/// Initializes caller object pool to store objects of the given class.
///
/// Returns `true` if initialization completed, `false` otherwise (including if
/// it was already completed with passed [`classToStore`]).
///
/// If successful, this action is irreversible: same pool cannot be
/// re-initialized.
///
/// [`forcedPoolSize`] defines max pool size for the caller
/// [`AcediaObjectPool`].
/// Leaving it at default `0` value will cause method to auto-determine
/// the size: gives priority to the [`poolSizeOverwrite`] config array;
/// if not specified, uses [`AcediaObject`]'s
/// [`AcediaObject::defaultMaxPoolSize`]
/// (ignoring [`AcediaObject::usesObjectPool`] setting).
public final function bool Initialize(
class<AcediaObject> classToStore,
optional int forcedPoolSize
) {
if (storedClass != none) return false;
if (classToStore == none) return false;
// If does not matter that we've set those variables until
// we set `storedClass`.
if (forcedPoolSize == 0) {
usedMaxPoolSize = GetMaxPoolSizeForClass(classToStore);
}
else {
usedMaxPoolSize = forcedPoolSize;
}
if (usedMaxPoolSize == 0) {
return false;
}
storedClass = classToStore;
return true;
}
/// Returns class of objects stored inside the caller [`AcediaObjectPool`].
///
/// `none` means object pool was not initialized.
public final function class<AcediaObject> GetClassOfStoredObjects() {
return storedClass;
}
/// Clear the storage of all its contents.
public final function Clear() {
objectPool.length = 0;
}
/// Adds object to the caller storage (that needs to be initialized to store
/// [`newObject.class`] classes).
///
/// Returns `true` on success and `false` on failure (can happen if passed
/// [`newObject`] reference was invalid, caller storage is not initialized yet
/// or reached it's capacity).
///
/// For performance purposes does not do duplicates checks, this should be
/// verified from outside [`AcediaObjectPool`].
///
/// Performs type checks and only allows objects of the class that caller
/// [`AcediaObjectPool`] was initialized for.
public final function bool Store(AcediaObject newObject) {
if (newObject == none) return true;
if (newObject.class != storedClass) return false;
if (usedMaxPoolSize >= 0 && objectPool.length >= usedMaxPoolSize) {
return false;
}
objectPool[objectPool.length] = newObject;
return true;
}
/// Returns last stored object from the pool, removing it from that pool in
/// the process.
///
/// Only returns `none` if caller `AcediaObjectPool` is either empty or not
/// initialized.
public final function AcediaObject Fetch() {
local AcediaObject result;
if (storedClass == none) return none;
if (objectPool.length <= 0) return none;
result = objectPool[objectPool.length - 1];
objectPool.length = objectPool.length - 1;
return result;
}
defaultproperties {
}