Merge pull request #10272 from RoosterDragon/player-dict
Speed up dictionaries keyed on Player
This commit is contained in:
@@ -153,6 +153,7 @@
|
||||
<Compile Include="Orders\UnitOrderGenerator.cs" />
|
||||
<Compile Include="Player.cs" />
|
||||
<Compile Include="Primitives\MergedStream.cs" />
|
||||
<Compile Include="Primitives\PlayerDictionary.cs" />
|
||||
<Compile Include="Primitives\SegmentStream.cs" />
|
||||
<Compile Include="Primitives\SpatiallyPartitioned.cs" />
|
||||
<Compile Include="Primitives\ConcurrentCache.cs" />
|
||||
|
||||
49
OpenRA.Game/Primitives/PlayerDictionary.cs
Normal file
49
OpenRA.Game/Primitives/PlayerDictionary.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Primitives
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a mapping of players to values, as well as fast lookup by player index.
|
||||
/// </summary>
|
||||
public struct PlayerDictionary<T> : IReadOnlyList<T>, IReadOnlyDictionary<Player, T> where T : class
|
||||
{
|
||||
readonly T[] valueByPlayerIndex;
|
||||
readonly Dictionary<Player, T> valueByPlayer;
|
||||
|
||||
public PlayerDictionary(World world, Func<Player, T> valueFactory)
|
||||
{
|
||||
var players = world.Players;
|
||||
if (players.Length == 0)
|
||||
throw new InvalidOperationException("The players in the world have not yet been set.");
|
||||
|
||||
// The world players never change, so we can safely maintain an array of values.
|
||||
// We need to enforce T is a class, so if it changes that change is available in both collections.
|
||||
valueByPlayerIndex = new T[players.Length];
|
||||
valueByPlayer = new Dictionary<Player, T>(players.Length);
|
||||
for (var i = 0; i < players.Length; i++)
|
||||
{
|
||||
var player = players[i];
|
||||
var state = valueFactory(player);
|
||||
valueByPlayerIndex[i] = state;
|
||||
valueByPlayer[player] = state;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets the value for the specified player. This is slower than specifying a player index.</summary>
|
||||
public T this[Player player] { get { return valueByPlayer[player]; } }
|
||||
|
||||
/// <summary>Gets the value for the specified player index.</summary>
|
||||
public T this[int playerIndex] { get { return valueByPlayerIndex[playerIndex]; } }
|
||||
|
||||
public int Count { get { return valueByPlayerIndex.Length; } }
|
||||
public IEnumerator<T> GetEnumerator() { return ((IEnumerable<T>)valueByPlayerIndex).GetEnumerator(); }
|
||||
|
||||
ICollection<Player> IReadOnlyDictionary<Player, T>.Keys { get { return valueByPlayer.Keys; } }
|
||||
ICollection<T> IReadOnlyDictionary<Player, T>.Values { get { return valueByPlayer.Values; } }
|
||||
bool IReadOnlyDictionary<Player, T>.ContainsKey(Player key) { return valueByPlayer.ContainsKey(key); }
|
||||
bool IReadOnlyDictionary<Player, T>.TryGetValue(Player key, out T value) { return valueByPlayer.TryGetValue(key, out value); }
|
||||
IEnumerator<KeyValuePair<Player, T>> IEnumerable<KeyValuePair<Player, T>>.GetEnumerator() { return valueByPlayer.GetEnumerator(); }
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,8 @@ namespace OpenRA
|
||||
|
||||
public void SetPlayers(IEnumerable<Player> players, Player localPlayer)
|
||||
{
|
||||
if (Players.Length > 0)
|
||||
throw new InvalidOperationException("Players are fixed once they have been set.");
|
||||
Players = players.ToArray();
|
||||
SetLocalPlayer(localPlayer);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user