rework ReadMessages to return a Span
continuous-integration/drone/push Build is passing Details

pull/3/head
Evan Hemsley 2020-03-22 13:41:55 -07:00
parent 67bc55e780
commit cdc68e46e5
9 changed files with 40 additions and 40 deletions

View File

@ -18,17 +18,17 @@ namespace Encompass
return _stores[typeof(TMessage)] as TypedMessageStore<TMessage>; return _stores[typeof(TMessage)] as TypedMessageStore<TMessage>;
} }
public void AddMessage<TMessage>(TMessage message) where TMessage : struct, IMessage public void AddMessage<TMessage>(in TMessage message) where TMessage : struct, IMessage
{ {
Lookup<TMessage>().Add(message); Lookup<TMessage>().Add(message);
} }
public void AddMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage public void AddMessage<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
{ {
Lookup<TMessage>().Add(message, time); Lookup<TMessage>().Add(message, time);
} }
public void AddMessageIgnoringTimeDilation<TMessage>(TMessage message, double time) where TMessage : struct, IMessage public void AddMessageIgnoringTimeDilation<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
{ {
Lookup<TMessage>().AddIgnoringTimeDilation(message, time); Lookup<TMessage>().AddIgnoringTimeDilation(message, time);
} }
@ -38,7 +38,7 @@ namespace Encompass
return Lookup<TMessage>().First(); return Lookup<TMessage>().First();
} }
public IEnumerable<TMessage> All<TMessage>() where TMessage : struct, IMessage public Span<TMessage> All<TMessage>() where TMessage : struct, IMessage
{ {
return Lookup<TMessage>().All(); return Lookup<TMessage>().All();
} }

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Encompass namespace Encompass
@ -10,12 +11,13 @@ namespace Encompass
internal class TypedMessageStore<TMessage> : TypedMessageStore where TMessage : struct, IMessage internal class TypedMessageStore<TMessage> : TypedMessageStore where TMessage : struct, IMessage
{ {
private readonly List<int> _indices = new List<int>(); // messages are placed in a contiguous region
// so we can return the collection as a Span
private int _nextIndex = 0;
private readonly TMessage[] _store = new TMessage[128]; private readonly TMessage[] _store = new TMessage[128];
private readonly List<(TMessage, double)> _delayedStore = new List<(TMessage, double)>(128); private readonly List<(TMessage, double)> _delayedStore = new List<(TMessage, double)>(128);
private readonly List<(TMessage, double)> _delayedStoreIgnoringTimeDilation = new List<(TMessage, double)>(128); private readonly List<(TMessage, double)> _delayedStoreIgnoringTimeDilation = new List<(TMessage, double)>(128);
private readonly Dictionary<int, HashSet<int>> _entityToIndices = new Dictionary<int, HashSet<int>>(); private readonly Dictionary<int, HashSet<int>> _entityToIndices = new Dictionary<int, HashSet<int>>();
private readonly IDManager _idManager = new IDManager();
public override void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta) public override void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta)
{ {
@ -56,8 +58,7 @@ namespace Encompass
public void Add(in TMessage message) public void Add(in TMessage message)
{ {
var index = _idManager.NextID(); var index = _nextIndex++;
_indices.Add(index);
_store[index] = message; _store[index] = message;
if (message is IHasEntity entityMessage) if (message is IHasEntity entityMessage)
{ {
@ -79,20 +80,17 @@ namespace Encompass
public TMessage First() public TMessage First()
{ {
return _store[_indices[0]]; return _store[0];
} }
public bool Any() public bool Any()
{ {
return _indices.Count > 0; return _nextIndex != 0;
} }
public IEnumerable<TMessage> All() public Span<TMessage> All()
{ {
foreach (var index in _indices) return new Span<TMessage>(_store, 0, _nextIndex);
{
yield return _store[index];
}
} }
public IEnumerable<TMessage> WithEntity(int entityID) public IEnumerable<TMessage> WithEntity(int entityID)
@ -113,11 +111,7 @@ namespace Encompass
public override void Clear() public override void Clear()
{ {
foreach (var index in _indices) _nextIndex = 0;
{
_idManager.Free(index);
}
_indices.Clear();
foreach (var set in _entityToIndices.Values) foreach (var set in _entityToIndices.Values)
{ {
set.Clear(); set.Clear();

View File

@ -529,7 +529,7 @@ namespace Encompass
/// <exception cref="Encompass.Exceptions.IllegalSendException"> /// <exception cref="Encompass.Exceptions.IllegalSendException">
/// Thrown when the Engine does not declare that it Sends the Message Type. /// Thrown when the Engine does not declare that it Sends the Message Type.
/// </exception> /// </exception>
protected void SendMessage<TMessage>(TMessage message) where TMessage : struct, IMessage protected void SendMessage<TMessage>(in TMessage message) where TMessage : struct, IMessage
{ {
if (!SendTypes.Contains(typeof(TMessage))) if (!SendTypes.Contains(typeof(TMessage)))
{ {
@ -543,7 +543,7 @@ namespace Encompass
/// Sends a message after the specified number of seconds, respecting time dilation. /// Sends a message after the specified number of seconds, respecting time dilation.
/// </summary> /// </summary>
/// <param name="time">The time in seconds that will elapse before the message is sent.</param> /// <param name="time">The time in seconds that will elapse before the message is sent.</param>
protected void SendMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage protected void SendMessage<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
{ {
_messageManager.AddMessage(message, time); _messageManager.AddMessage(message, time);
} }
@ -552,7 +552,7 @@ namespace Encompass
/// Sends a message after the specified number of seconds, ignoring time dilation. /// Sends a message after the specified number of seconds, ignoring time dilation.
/// </summary> /// </summary>
/// <param name="time">The time in seconds that will elapse before the message is sent.</param> /// <param name="time">The time in seconds that will elapse before the message is sent.</param>
protected void SendMessageIgnoringTimeDilation<TMessage>(TMessage message, double time) where TMessage : struct, IMessage protected void SendMessageIgnoringTimeDilation<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
{ {
_messageManager.AddMessageIgnoringTimeDilation(message, time); _messageManager.AddMessageIgnoringTimeDilation(message, time);
} }
@ -563,7 +563,7 @@ namespace Encompass
/// <exception cref="Encompass.Exceptions.IllegalReadException"> /// <exception cref="Encompass.Exceptions.IllegalReadException">
/// Thrown when the Engine does not declare that it Receives the specified Message Type. /// Thrown when the Engine does not declare that it Receives the specified Message Type.
/// </exception> /// </exception>
protected IEnumerable<TMessage> ReadMessages<TMessage>() where TMessage : struct, IMessage protected Span<TMessage> ReadMessages<TMessage>() where TMessage : struct, IMessage
{ {
CheckMessageRead<TMessage>(); CheckMessageRead<TMessage>();
return _messageManager.GetMessagesByType<TMessage>(); return _messageManager.GetMessagesByType<TMessage>();

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Encompass namespace Encompass
@ -12,17 +13,17 @@ namespace Encompass
_timeManager = timeManager; _timeManager = timeManager;
} }
internal void AddMessage<TMessage>(TMessage message) where TMessage : struct, IMessage internal void AddMessage<TMessage>(in TMessage message) where TMessage : struct, IMessage
{ {
_messageStore.AddMessage(message); _messageStore.AddMessage(message);
} }
internal void AddMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage internal void AddMessage<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
{ {
_messageStore.AddMessage(message, time); _messageStore.AddMessage(message, time);
} }
internal void AddMessageIgnoringTimeDilation<TMessage>(TMessage message, double time) where TMessage : struct, IMessage internal void AddMessageIgnoringTimeDilation<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
{ {
_messageStore.AddMessageIgnoringTimeDilation(message, time); _messageStore.AddMessageIgnoringTimeDilation(message, time);
} }
@ -37,7 +38,7 @@ namespace Encompass
_messageStore.ProcessDelayedMessages(dt * _timeManager.TimeDilationFactor, dt); _messageStore.ProcessDelayedMessages(dt * _timeManager.TimeDilationFactor, dt);
} }
internal IEnumerable<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage internal Span<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage
{ {
return _messageStore.All<TMessage>(); return _messageStore.All<TMessage>();
} }

View File

@ -58,7 +58,9 @@ namespace Encompass
CallGenericMethod(type, "SendMessage", 1, new object[] { Activator.CreateInstance(type) }); CallGenericMethod(type, "SendMessage", 1, new object[] { Activator.CreateInstance(type) });
CallGenericMethod(type, "SendMessage", 2, new object[] { Activator.CreateInstance(type), 1 }); CallGenericMethod(type, "SendMessage", 2, new object[] { Activator.CreateInstance(type), 1 });
CallGenericMethod(type, "ReadMessage", null); CallGenericMethod(type, "ReadMessage", null);
CallGenericMethod(type, "ReadMessages", null);
// can't reflect on methods that return a span...
//CallGenericMethod(type, "ReadMessages", null);
CallGenericMethod(type, "SomeMessage", null); CallGenericMethod(type, "SomeMessage", null);
if (typeof(IHasEntity).IsAssignableFrom(type)) if (typeof(IHasEntity).IsAssignableFrom(type))
{ {

View File

@ -68,7 +68,7 @@ namespace Encompass
/// <summary> /// <summary>
/// Specifies that the given Message should be sent immediately on the first World Update. /// Specifies that the given Message should be sent immediately on the first World Update.
/// </summary> /// </summary>
public void SendMessage<TMessage>(TMessage message) where TMessage : struct, IMessage public void SendMessage<TMessage>(in TMessage message) where TMessage : struct, IMessage
{ {
_messageManager.AddMessage(message); _messageManager.AddMessage(message);
} }
@ -76,7 +76,7 @@ namespace Encompass
/// <summary> /// <summary>
/// Specifies that the given Message should be sent after the specified number of seconds after the first World Update. /// Specifies that the given Message should be sent after the specified number of seconds after the first World Update.
/// </summary> /// </summary>
public void SendMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage public void SendMessage<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
{ {
_messageManager.AddMessage<TMessage>(message, time); _messageManager.AddMessage<TMessage>(message, time);
} }

View File

@ -45,7 +45,7 @@ namespace Tests
{ {
public override void Update(double dt) public override void Update(double dt)
{ {
foreach (var addComponentTestMessage in ReadMessages<AddComponentTestMessage>()) foreach (ref readonly var addComponentTestMessage in ReadMessages<AddComponentTestMessage>())
{ {
Assert.IsTrue(HasComponent<MockComponent>(addComponentTestMessage.entity)); Assert.IsTrue(HasComponent<MockComponent>(addComponentTestMessage.entity));
ref readonly var gottenComponent = ref GetComponent<MockComponent>(addComponentTestMessage.entity); ref readonly var gottenComponent = ref GetComponent<MockComponent>(addComponentTestMessage.entity);

View File

@ -20,7 +20,7 @@ namespace Tests
static List<MockComponent> resultComponents; static List<MockComponent> resultComponents;
static MockComponent resultComponent; static MockComponent resultComponent;
static List<MockMessage> resultMessages = new List<MockMessage>(); static MockMessage[] resultMessages;
[Reads(typeof(MockComponent))] [Reads(typeof(MockComponent))]
public class ReadComponentsTestEngine : Engine public class ReadComponentsTestEngine : Engine
@ -279,7 +279,7 @@ namespace Tests
{ {
public override void Update(double dt) public override void Update(double dt)
{ {
resultMessages = this.ReadMessages<MockMessage>().ToList(); resultMessages = ReadMessages<MockMessage>().ToArray();
} }
} }
@ -308,14 +308,14 @@ namespace Tests
} }
} }
static IEnumerable<MockMessage> emptyReadMessagesResult; static MockMessage[] emptyReadMessagesResult;
[Receives(typeof(MockMessage))] [Receives(typeof(MockMessage))]
class ReadMessagesWhenNoneExistEngine : Engine class ReadMessagesWhenNoneExistEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
{ {
emptyReadMessagesResult = ReadMessages<MockMessage>(); emptyReadMessagesResult = ReadMessages<MockMessage>().ToArray();
} }
} }
@ -799,7 +799,7 @@ namespace Tests
[Test] [Test]
public void EngineSendMessageDelayed() public void EngineSendMessageDelayed()
{ {
resultMessages.Clear(); Array.Clear(resultMessages, 0, resultMessages.Length);
var worldBuilder = new WorldBuilder(); var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationEngine()); worldBuilder.AddEngine(new ActivateTimeDilationEngine());
@ -846,7 +846,7 @@ namespace Tests
[Test] [Test]
public void EngineSendMessageDelayedIgnoringTimeDilation() public void EngineSendMessageDelayedIgnoringTimeDilation()
{ {
resultMessages.Clear(); Array.Clear(resultMessages, 0, resultMessages.Length);
var worldBuilder = new WorldBuilder(); var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationEngine()); worldBuilder.AddEngine(new ActivateTimeDilationEngine());

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using Encompass.Exceptions; using Encompass.Exceptions;
using System.Linq; using System.Linq;
using FluentAssertions; using FluentAssertions;
using System;
namespace Tests namespace Tests
{ {
@ -479,20 +480,22 @@ namespace Tests
Assert.That(order.IndexOf(engineC), Is.LessThan(order.IndexOf(engineD))); Assert.That(order.IndexOf(engineC), Is.LessThan(order.IndexOf(engineD)));
} }
static List<AMessage> resultMessages = new List<AMessage>(); static AMessage[] resultMessages;
[Receives(typeof(AMessage))] [Receives(typeof(AMessage))]
class ReadMessageEngine : Engine class ReadMessageEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
{ {
resultMessages = ReadMessages<AMessage>().ToList(); resultMessages = ReadMessages<AMessage>().ToArray();
} }
} }
[Test] [Test]
public void SendMessageDelayed() public void SendMessageDelayed()
{ {
resultMessages = Array.Empty<AMessage>();
var worldBuilder = new WorldBuilder(); var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadMessageEngine()); worldBuilder.AddEngine(new ReadMessageEngine());