Skip to content

Commit

Permalink
Merge pull request #24 from chickensoft-games/feat/entity-table
Browse files Browse the repository at this point in the history
feat: entity table
  • Loading branch information
jolexxa authored Jun 3, 2024
2 parents 2ee15ec + 32791f9 commit ec8a866
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 0 deletions.
29 changes: 29 additions & 0 deletions Chickensoft.Collections.Tests/src/EntityTableTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace Chickensoft.Collections.Tests;

using Shouldly;
using Xunit;

public class EntityTableTest {
[Fact]
public void Initializes() {
new EntityTable<int>().ShouldBeAssignableTo<EntityTable<int>>();
new EntityTable().ShouldBeAssignableTo<EntityTable<string>>();
}

[Fact]
public void StoresValues() {
var table = new EntityTable();

table.Set("a", "one");
table.Set("b", new object());

table.Get<string>("a").ShouldBe("one");
table.Get<object>("b").ShouldNotBeNull();

table.Remove("a");
table.Remove(null);

table.Get<string>("a").ShouldBeNull();
table.Get<object>("b").ShouldNotBeNull();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Chickensoft.Collections;

/// <summary>
/// Very simple wrapper over a concurrent dictionary that allows entities to
/// be associated to a string id and retrieved by that id as a specific type, if
/// the entity is of that type.
/// </summary>
public sealed class EntityTable : EntityTable<string> { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
namespace Chickensoft.Collections;

using System.Collections.Concurrent;

/// <summary>
/// Very simple wrapper over a concurrent dictionary that allows entities to
/// be associated to an id and retrieved by that id as a specific type, if
/// the entity is of that type.
/// </summary>
/// <typeparam name="TId">Key type.</typeparam>
public class EntityTable<TId> where TId : notnull {
private readonly ConcurrentDictionary<TId, object> _entities = new();

/// <summary>
/// Set an entity in the table.
/// </summary>
/// <param name="id">Entity id.</param>
/// <param name="entity">Entity object.</param>
public void Set(TId id, object entity) => _entities.TryAdd(id, entity);

/// <summary>
/// Remove an entity from the table.
/// </summary>
/// <param name="id">Entity id.</param>
public void Remove(TId? id) {
if (id is null) { return; }

_entities.TryRemove(id, out _);
}

/// <summary>
/// Retrieve an entity from the table.
/// </summary>
/// <typeparam name="TUsage">Type to use the entity as — entity must be
/// assignable to this type.</typeparam>
/// <param name="id"></param>
/// <returns>Entity with the associated id as the given type, if the entity
/// exists and is of that type.</returns>
public TUsage? Get<TUsage>(TId? id) where TUsage : class {
if (
id is not null &&
_entities.TryGetValue(id, out var entity) &&
entity is TUsage expected
) {
return expected;
}

return default;
}
}
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,35 @@ var myObj = blackboard.Get<MyObject>();
// ...and various other convenience methods.
```

## EntityTable

The `EntityTable<TId>` is a simple wrapper over a `ConcurrentDictionary` that is provided to help you conveniently associate any type of value with an identifier. Table entries are requested by their identifier *and* type. If the value exists and matches the requested type, it is returned. Otherwise, `null` is returned.

```csharp
var table = new EntityTable<int>();

table.Set(42, "dolphins");

// Use pattern matching for an optimal experience.
if (table.Get<string>(42) is { } value) {
Console.WriteLine("Dolphins are present.");
}

table.Remove(42);
```

A default implementation that uses `string` is also provided:

```csharp
var table = new EntityTable();

table.Set("identifier", new object())

if (table.Get<object>("identifier") is { } value) {
Console.WriteLine("Object is present.");
}
```

---

🐣 Created with love by Chickensoft 🐤 — <https://chickensoft.games>
Expand Down

0 comments on commit ec8a866

Please sign in to comment.