#region Copyright & License Information /* * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, * see LICENSE. */ #endregion using System; using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; using System.Diagnostics; namespace OpenRA { class TraitDictionary { Dictionary traits = new Dictionary(); ITraitContainer InnerGet( Type t ) { return traits.GetOrAdd( t, CreateTraitContainer ); } static ITraitContainer CreateTraitContainer( Type t ) { return (ITraitContainer)typeof( TraitContainer<> ).MakeGenericType( t ) .GetConstructor( new Type[ 0 ] ).Invoke( new object[ 0 ] ); } public void Add( Actor actor, object val ) { var t = val.GetType(); foreach( var i in t.GetInterfaces() ) InnerAdd( actor, i, val ); foreach( var tt in t.BaseTypes() ) InnerAdd( actor, tt, val ); } void InnerAdd( Actor actor, Type t, object val ) { InnerGet( t ).Add( actor, val ); } public bool Contains( Actor actor ) { return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetMultiple( actor ).Count() != 0; } public T Get( Actor actor ) { return ( (TraitContainer)InnerGet( typeof( T ) ) ).Get( actor ); } public T GetOrDefault( Actor actor ) { return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetOrDefault( actor ); } public IEnumerable WithInterface( Actor actor ) { return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetMultiple( actor ); } interface ITraitContainer { void Add( Actor actor, object trait ); } class TraitContainer : ITraitContainer { List actors = new List(); List traits = new List(); public void Add( Actor actor, object trait ) { var insertIndex = actors.BinarySearchMany( actor.ActorID + 1 ); actors.Insert( insertIndex, actor.ActorID ); traits.Insert( insertIndex, (T)trait ); } public T Get( Actor actor ) { var index = actors.BinarySearchMany( actor.ActorID ); if( index >= actors.Count || actors[ index ] != actor.ActorID ) throw new InvalidOperationException( string.Format( "TraitDictionary does not contain instance of type `{0}`", typeof( T ) ) ); else if( index + 1 < actors.Count && actors[ index + 1 ] == actor.ActorID ) throw new InvalidOperationException( string.Format( "TraitDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); else return traits[ index ]; } public T GetOrDefault( Actor actor ) { var index = actors.BinarySearchMany( actor.ActorID ); if( index >= actors.Count || actors[ index ] != actor.ActorID ) return default( T ); else if( index + 1 < actors.Count && actors[ index + 1 ] == actor.ActorID ) throw new InvalidOperationException( string.Format( "TraitDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); else return traits[ index ]; } public IEnumerable GetMultiple( Actor actor ) { var index = actors.BinarySearchMany( actor.ActorID ); while( index < actors.Count && actors[ index ] == actor.ActorID ) { yield return traits[ index ]; ++index; } } } } static class ListExts { public static int BinarySearchMany( this List list, T searchFor ) where T : IComparable { int start = 0; int end = list.Count; int mid = 0; while( start != end ) { mid = ( start + end ) / 2; var c = list[ mid ].CompareTo( searchFor ); if( c < 0 ) start = mid + 1; else end = mid; } return start; } } }