Skip to content

Instantly share code, notes, and snippets.

@margaretdax
Last active April 12, 2021 18:28
Show Gist options
  • Save margaretdax/7815bcbba5dfe1dd3d75cc0b823dfeec to your computer and use it in GitHub Desktop.
Save margaretdax/7815bcbba5dfe1dd3d75cc0b823dfeec to your computer and use it in GitHub Desktop.
Example implementation of an abstraction to "simply" implement object pooling for compiler generated IEnumerator state machines. Makes use of goto and requires a great deal of usage dicipline. Not ideal but for those applications that can't tollerate IEnumerator GC/alloc costs.
using System;
using System.Collections;
using Zenject;
public abstract class PooledEnumerator<T> : IDisposable, IEnumerator where T : PooledEnumerator<T>, new()
{
private static readonly StaticMemoryPool<T> Pool = new StaticMemoryPool<T>();
// ReSharper disable once StaticMemberInGenericType
private static readonly object CompletedSignal = new object();
private IEnumerator iterator;
private T self;
private bool interrupted;
protected bool Interrupted => interrupted;
protected static T Create()
{
T spawned = Pool.Spawn();
spawned.self = spawned;
return spawned;
}
private static void Destroy(T obj)
{
// Signal to Run that it might need to Restart
obj.interrupted = true;
Pool.Despawn(obj);
}
public void Dispose()
{
Destroy(self);
}
protected abstract IEnumerator Impl();
protected object Completed()
{
return CompletedSignal;
}
public bool MoveNext()
{
if (iterator == null)
{
interrupted = false;
iterator = Impl();
}
if(iterator != null && iterator.MoveNext())
{
interrupted = false;
if (iterator.Current != CompletedSignal) return true;
}
Pool.Despawn(self);
return false;
}
public void Reset()
{
throw new System.NotImplementedException();
}
public object Current => iterator?.Current;
}
using UnityEngine;
using System.Collections;
public static class Routine
{
// Every time Move() is called codegen generates garbage
// public static IEnumerator Move(Transform trans, Vector3 target, float rate = 0.3f)
// {
// Vector3 pos = trans.localPosition;
// while ((target - pos).sqrMagnitude > 0.1f)
// {
// pos = Vector2.Lerp(pos, target, Lerp(rate));
// trans.localPosition = pos;
// yield return null;
// }
// trans.localPosition = target;
// }
// Calling Move doesn't generate garbage (must be Disposed if interrupted)
public static IEnumerator Move(Transform trans, Vector3 target, float rate = 0.3f)
{
return MoveTransform.Create(trans, target, rate);
}
public class MoveTransform : PooledEnumerator<MoveTransform>
{
private Transform trans;
private Vector3 target;
private float rate;
public static MoveTransform Create(Transform trans, Vector3 target, float rate = 0.3f)
{
MoveTransform obj = Create();
obj.trans = trans;
obj.target = target;
obj.rate = rate;
return obj;
}
protected override IEnumerator Impl()
{
Restart:
Vector3 pos = trans.localPosition;
while ((target - pos).sqrMagnitude > 0.1f)
{
pos = Vector2.Lerp(pos, target, Lerp(rate));
trans.localPosition = pos;
yield return null;
if(Interrupted) goto Restart;
}
trans.localPosition = target;
yield return Completed();
goto Restart;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment