Skip to content

Commit 8ef2852

Browse files
committed
Identity Map + KeyNotFoundException + some tests
1 parent 28cc3d5 commit 8ef2852

File tree

12 files changed

+758
-1
lines changed

12 files changed

+758
-1
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// IIdentityMap.cs
3+
//
4+
// Author:
5+
// Giacomo Tesio <giacomo@tesio.it>
6+
//
7+
// Copyright (c) 2010-2012 Giacomo Tesio
8+
//
9+
// This file is part of Epic.NET.
10+
//
11+
// Epic.NET is free software: you can redistribute it and/or modify
12+
// it under the terms of the GNU Affero General Public License as published by
13+
// the Free Software Foundation, either version 3 of the License, or
14+
// (at your option) any later version.
15+
//
16+
// Epic.NET is distributed in the hope that it will be useful,
17+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
// GNU Affero General Public License for more details.
20+
//
21+
// You should have received a copy of the GNU Affero General Public License
22+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
//
24+
using System;
25+
26+
namespace Epic.Collections
27+
{
28+
/// <summary>
29+
/// Represent an Identity Map.
30+
/// </summary>
31+
/// <typeparam name="TEntity">Type of the entity of interest.</typeparam>
32+
/// <typeparam name="TIdentity">Type of the identity of <typeparamref name="TEntity"/>.</typeparam>
33+
public interface IIdentityMap<TEntity, TIdentity> : IMap<TIdentity, TEntity>, IDisposable
34+
where TEntity : class
35+
where TIdentity : IEquatable<TIdentity>
36+
{
37+
/// <summary>
38+
/// Register in the map the specified entity.
39+
/// </summary>
40+
/// <param name='entity'>
41+
/// Entity to register.
42+
/// </param>
43+
/// <exception cref="ArgumentNullException"><paramref name="entity"/> is <c>null</c>.</exception>
44+
/// <exception cref="ArgumentException"><paramref name="entity"/> has already been registered.</exception>
45+
void Register(TEntity entity);
46+
47+
/// <summary>
48+
/// Determines if the map already knows the specified entity.
49+
/// </summary>
50+
/// <param name='entity'>
51+
/// Identity of the entity of interest.
52+
/// </param>
53+
/// <returns><c>true</c>if the map knows the specified entity, <c>false</c> otherwise.</returns>
54+
/// <exception cref="ArgumentNullException"><paramref name="entity"/> is <c>null</c>.</exception>
55+
bool Knows(TIdentity entity);
56+
}
57+
}
58+

Code/Epic.Prelude/Collections/IMap.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//
2+
// IMap.cs
3+
//
4+
// Author:
5+
// Giacomo Tesio <giacomo@tesio.it>
6+
//
7+
// Copyright (c) 2010-2012 Giacomo Tesio
8+
//
9+
// This file is part of Epic.NET.
10+
//
11+
// Epic.NET is free software: you can redistribute it and/or modify
12+
// it under the terms of the GNU Affero General Public License as published by
13+
// the Free Software Foundation, either version 3 of the License, or
14+
// (at your option) any later version.
15+
//
16+
// Epic.NET is distributed in the hope that it will be useful,
17+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
// GNU Affero General Public License for more details.
20+
//
21+
// You should have received a copy of the GNU Affero General Public License
22+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
//
24+
using System;
25+
26+
namespace Epic.Collections
27+
{
28+
/// <summary>
29+
/// A map that provide access to <typeparamref name="TValue">
30+
/// given a <typeparamref name="TKey"/>.
31+
/// </summary>
32+
public interface IMap<TKey, TValue>
33+
where TKey : IEquatable<TKey>
34+
{
35+
/// <summary>
36+
/// Gets the <typeparamref name="TValue"/> with the specified key.
37+
/// </summary>
38+
/// <param name='key'>
39+
/// The key of the element to get.
40+
/// </param>
41+
/// <exception cref="ArgumentNullException"><paramref name="key"/> is <c>null</c>.</exception>
42+
/// <exception cref="KeyNotFoundException{TKey}">The property is retrieved and <paramref name="key"/> is not found.</exception>
43+
TValue this[TKey key] { get; }
44+
}
45+
}
46+
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
//
2+
// IdentityMap.cs
3+
//
4+
// Author:
5+
// Giacomo Tesio <giacomo@tesio.it>
6+
//
7+
// Copyright (c) 2010-2012 Giacomo Tesio
8+
//
9+
// This file is part of Epic.NET.
10+
//
11+
// Epic.NET is free software: you can redistribute it and/or modify
12+
// it under the terms of the GNU Affero General Public License as published by
13+
// the Free Software Foundation, either version 3 of the License, or
14+
// (at your option) any later version.
15+
//
16+
// Epic.NET is distributed in the hope that it will be useful,
17+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
// GNU Affero General Public License for more details.
20+
//
21+
// You should have received a copy of the GNU Affero General Public License
22+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
//
24+
using System;
25+
using System.Collections.Generic;
26+
using System.Runtime.Serialization;
27+
using Epic.Math;
28+
29+
namespace Epic.Collections
30+
{
31+
/// <summary>
32+
/// Simple identity map.
33+
/// </summary>
34+
/// <typeparam name="TEntity">Type of the entity of interest.</typeparam>
35+
/// <typeparam name="TIdentity">Type of the identity of <typeparamref name="TEntity"/>.</typeparam>
36+
[Serializable]
37+
public sealed class IdentityMap<TEntity, TIdentity> : IIdentityMap<TEntity, TIdentity>, ISerializable
38+
where TEntity : class
39+
where TIdentity : IEquatable<TIdentity>
40+
{
41+
private readonly IMapping<TEntity, TIdentity> _mapping;
42+
private Dictionary<TIdentity, TEntity> _map;
43+
44+
/// <summary>
45+
/// Initializes a new instance of the <see cref="IdentityMap{TEntity, TIdentity}"/> class.
46+
/// </summary>
47+
/// <param name='mapping'>
48+
/// Mapping from instances of <typeparamref name="TEntity"/> and their identities.
49+
/// </param>
50+
/// <exception cref="ArgumentNullException"><paramref name="mapping"/> is <c>null</c>.</exception>
51+
public IdentityMap (IMapping<TEntity, TIdentity> mapping)
52+
{
53+
if (null == mapping)
54+
throw new ArgumentNullException ("mapping");
55+
_mapping = mapping;
56+
_map = new Dictionary<TIdentity, TEntity>();
57+
}
58+
59+
/// <summary>
60+
/// Initializes a new instance of the <see cref="IdentityMap{TEntity, TIdentity}"/> class.
61+
/// </summary>
62+
/// <param name='mapping'>
63+
/// Mapping from instances of <typeparamref name="TEntity"/> and their identities.
64+
/// </param>
65+
/// <exception cref="ArgumentNullException"><paramref name="mapping"/> is <c>null</c>.</exception>
66+
public IdentityMap (Func<TEntity, TIdentity> mapping)
67+
: this(new FunctionMapping<TEntity, TIdentity>(mapping))
68+
{
69+
}
70+
71+
private void ThrowIfDisposed()
72+
{
73+
if(null == _map)
74+
throw new ObjectDisposedException(string.Format("IdentityMap<{0}, {1}>", typeof(TEntity), typeof(TIdentity)));
75+
}
76+
77+
#region IMap implementation
78+
public TEntity this[TIdentity key]
79+
{
80+
get
81+
{
82+
ThrowIfDisposed();
83+
TEntity entity;
84+
try
85+
{
86+
entity = _map[key];
87+
}
88+
catch(ArgumentNullException nullExc)
89+
{
90+
throw nullExc;
91+
}
92+
catch(KeyNotFoundException keyExc)
93+
{
94+
throw new KeyNotFoundException<TIdentity>(key, keyExc.Message, keyExc);
95+
}
96+
return entity;
97+
}
98+
}
99+
#endregion
100+
101+
#region ISerializable implementation
102+
private IdentityMap(SerializationInfo info, StreamingContext context)
103+
{
104+
_mapping = (IMapping<TEntity, TIdentity>)info.GetValue("F", typeof(IMapping<TEntity, TIdentity>));
105+
_map = (Dictionary<TIdentity, TEntity>)info.GetValue("M", typeof(Dictionary<TIdentity, TEntity>));
106+
}
107+
108+
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
109+
{
110+
ThrowIfDisposed();
111+
info.AddValue("F", _mapping, typeof(IMapping<TEntity, TIdentity>));
112+
info.AddValue("M", _map, typeof(Dictionary<TIdentity, TEntity>));
113+
}
114+
#endregion
115+
116+
#region IDisposable implementation
117+
public void Dispose ()
118+
{
119+
Dictionary<TIdentity, TEntity> map = _map;
120+
if(null != map)
121+
map.Clear();
122+
}
123+
#endregion
124+
125+
#region IIdentityMap implementation
126+
public void Register (TEntity entity)
127+
{
128+
ThrowIfDisposed();
129+
if(null == entity)
130+
throw new ArgumentNullException("entity");
131+
TIdentity identity = _mapping.ApplyTo(entity);
132+
if(_map.ContainsKey(identity))
133+
{
134+
string message = string.Format("The {0} identified by '{1}' is already registered.", typeof(TEntity), typeof(TIdentity));
135+
throw new ArgumentException(message, "entity");
136+
}
137+
_map[identity] = entity;
138+
}
139+
140+
public bool Knows(TIdentity entity)
141+
{
142+
ThrowIfDisposed();
143+
if(null == entity)
144+
throw new ArgumentNullException("entity");
145+
return _map.ContainsKey(entity);
146+
}
147+
#endregion
148+
}
149+
}
150+
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//
2+
// KeyNotFoundException.cs
3+
//
4+
// Author:
5+
// Giacomo Tesio <giacomo@tesio.it>
6+
//
7+
// Copyright (c) 2010-2012 Giacomo Tesio
8+
//
9+
// This file is part of Epic.NET.
10+
//
11+
// Epic.NET is free software: you can redistribute it and/or modify
12+
// it under the terms of the GNU Affero General Public License as published by
13+
// the Free Software Foundation, either version 3 of the License, or
14+
// (at your option) any later version.
15+
//
16+
// Epic.NET is distributed in the hope that it will be useful,
17+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
// GNU Affero General Public License for more details.
20+
//
21+
// You should have received a copy of the GNU Affero General Public License
22+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
//
24+
using System;
25+
using System.Collections.Generic;
26+
using System.Runtime.Serialization;
27+
28+
namespace Epic.Collections
29+
{
30+
/// <summary>
31+
/// The exception that is thrown when the key specified for
32+
/// accessing an element in a <see cref="IMap{TKey,TValue}"/> does not match any
33+
/// key in the map.
34+
/// </summary>
35+
[Serializable]
36+
public sealed class KeyNotFoundException<TKey> : KeyNotFoundException
37+
where TKey : IEquatable<TKey>
38+
{
39+
private readonly TKey _key;
40+
41+
/// <summary>
42+
/// Initializes a new instance of the <see cref="KeyNotFoundException{Key}"/> class
43+
/// with the specified error message and a reference to the inner exception that is
44+
/// the cause of this exception.
45+
/// </summary>
46+
/// <param name='notFoundKey'>
47+
/// Not found key.
48+
/// </param>
49+
/// <param name='message'>
50+
/// The message that describes the error.
51+
/// </param>
52+
public KeyNotFoundException(TKey notFoundKey, string message)
53+
: base(message)
54+
{
55+
_key = notFoundKey;
56+
}
57+
58+
/// <summary>
59+
/// Initializes a new instance of the <see cref="KeyNotFoundException{Key}"/> class
60+
/// with the specified error message.
61+
/// </summary>
62+
/// <param name='notFoundKey'>
63+
/// Not found key.
64+
/// </param>
65+
/// <param name='message'>
66+
/// The message that describes the error.
67+
/// </param>
68+
/// <param name='innerException'>
69+
/// Inner exception.
70+
/// </param>
71+
public KeyNotFoundException(TKey notFoundKey, string message, Exception innerException)
72+
: base(message, innerException)
73+
{
74+
_key = notFoundKey;
75+
}
76+
77+
private KeyNotFoundException(SerializationInfo info, StreamingContext context)
78+
: base(info, context)
79+
{
80+
_key = (TKey)info.GetValue("K", typeof(TKey));
81+
}
82+
83+
public override void GetObjectData (SerializationInfo info, StreamingContext context)
84+
{
85+
base.GetObjectData(info, context);
86+
info.AddValue("K", _key, typeof(TKey));
87+
}
88+
89+
/// <summary>
90+
/// Gets the missing key.
91+
/// </summary>
92+
public TKey Key
93+
{
94+
get
95+
{
96+
return _key;
97+
}
98+
}
99+
}
100+
}
101+

Code/Epic.Prelude/Epic.Prelude.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,16 @@
4747
<Compile Include="..\EpicInfo.cs">
4848
<Link>EpicInfo.cs</Link>
4949
</Compile>
50+
<Compile Include="Collections\IMap.cs" />
51+
<Compile Include="Collections\KeyNotFoundException.cs" />
52+
<Compile Include="Collections\IdentityMap.cs" />
53+
<Compile Include="Math\IMapping.cs" />
54+
<Compile Include="Math\FunctionMapping.cs" />
55+
<Compile Include="Collections\IIdentityMap.cs" />
5056
</ItemGroup>
5157
<ItemGroup>
5258
<Folder Include="Specifications\" />
59+
<Folder Include="Collections\" />
60+
<Folder Include="Math\" />
5361
</ItemGroup>
5462
</Project>

0 commit comments

Comments
 (0)