Skip to content

Neohertz/neocache

Repository files navigation

Neocache

A very fast caching module for instances and beyond.

Warning

Neocache is pre v1.0 software. You may encounter bugs.

Example Usage

local audioCache = neocache.new(function()
	local sfx = Instance.new("Sound")
	sfx.Parent = SoundService
	return sfx
end, 100, 10)

function playSoundEffect(id: string)
	local sound = audioCache:next()
	sound.SoundID = id
	sound:Play()
end

Behavior

Neocache acts like a ring buffer. Whenever :next() or reserveNext() is invoked, it will increment the pointer to find the next available instance. If it doesn't exist, it will just create it.

Neocache also has support for locking, allowing you to "check out" a result from the cache, modify it, then return it once done. While an entry is locked, it will be skipped in all future next() / reserveNext() calls.

Install

Wally

Get the latest version from Wally.

# wally.toml
neocache = "neohertz/neocache@x.x.x"

Typescript (Roblox-TS)

Install neocache via npm. (coming soon)

npm i @rbxts/neocache

Creating a Cache

neocache.new(factory: () -> T, size: number, buffer: number?)

  • Factory
    • Invoked whenever the cache needs to create a new instance. Returns a value.
  • Size
    • How big the cache should be.
  • Buffer
    • Prewarm the cache by populating the first X entries.
local audioCache = neocache.new(function()
	local sfx = Instance.new("Sound")
	sfx.Parent = SoundService
	return sfx
end, 100, 10)

API

cache:next(fast: boolean?)

Get a reference to the next available item in the cache and increment the internal pointer.

If fast is true, the cache will grab the next item in the queue. If this item is locked, :next(true) will return nil.

local sound = audioCache:next()

if sound then
	sound:Play()
end

cache:reserveNext(fast: boolean?)

Same thing as cache:next(), but this instance is locked until the returned unlock method is invoked.

While this item is locked or "checked out", it will be skipped in any future next() or reserveNext() calls.

If fast is true, the cache will grab the next item in the queue. If this item is locked, :reserveNext(true) will return nil.

This is useful if you want to prevent overlapping operations on a specific item in the cache.

local sound, release = audioCache:reserveNext()

if sound then
	sound:Play()
	sound.Ended:Once(function()
		release()
	end)
end

cache:unique()

Grab a unique, non cached instance from the factory.

local uniqueSoundEffect = audioCache:unique()

cache:peek()

View the next item in the cache.

local ref = audioCache:peek()

cache:resize(newSize: number, newBuffer: number?)

Resize the cache. This operation is destructive on shrinking.

If the cache grows to a size below the buffer, those items will be immediately generated.

-- Current Size: 100 | Current Buffer: 10
-- 5 deletions guaranteed, 90 possible.
cache:resize(5)

-- Current Size: 5 | Current Buffer: 10
-- 5 factory invocations guaranteed.
cache:resize(10)

cache:clear()

Entirely wipe the cache. Invokes the cleanup method. Neocache will automatically regenerate the objects upon subsequent next() or reserveNext() calls.

audioCache:clear()
audioCache:next() -- invokes factory.

cache:useCleanupMethod<T>(fn: (obj: T) -> ())

Override the default cleanup method with a custom one. This method will be invoked by both cache:clear() and cache:destroy().

Useful when using non-instance items within the cache.

cache:useCleanupMethod(function(class: MyClass)
	class:Cleanup()
end)

cache:destroy()

Destroy the cache and any instances within entirely. Subsequent calls to this cache will error.

cahce:destroy()
cache:next() -- ❌ error!

About

A very fast instance cache module for luau.

Resources

License

Stars

Watchers

Forks

Contributors

Languages