Skip to content

Commit f7b3d1a

Browse files
authored
Optimize FlagCollection (#342)
* Optimize `FlagCollection` * Simplify * Equals()
1 parent 8f33dde commit f7b3d1a

File tree

2 files changed

+54
-125
lines changed

2 files changed

+54
-125
lines changed

Orm/Xtensive.Orm/Collections/FlagCollection.cs

Lines changed: 52 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
// Created by: Alexey Kochetov
55
// Created: 2007.10.01
66

7-
using System;
87
using System.Collections;
9-
using System.Collections.Generic;
108
using System.Collections.ObjectModel;
119
using System.Collections.Specialized;
1210
using System.Diagnostics;
@@ -15,8 +13,6 @@
1513
using Xtensive.Conversion;
1614
using Xtensive.Core;
1715

18-
19-
2016
namespace Xtensive.Collections
2117
{
2218
/// <summary>
@@ -32,42 +28,29 @@ namespace Xtensive.Collections
3228
[DebuggerDisplay("Count = {Count}")]
3329
public class FlagCollection<TKey, TFlag>: LockableBase,
3430
IList<KeyValuePair<TKey, TFlag>>,
35-
IDictionary<TKey, TFlag>,
31+
IReadOnlyDictionary<TKey, TFlag>,
3632
IEquatable<FlagCollection<TKey, TFlag>>,
3733
ISerializable
3834
{
3935
private const int MaxItemCount = 32;
40-
private readonly Biconverter<TFlag, bool> converter;
41-
private readonly List<TKey> keys;
42-
private readonly ReadOnlyCollection<TKey> readOnlyKeys;
36+
private readonly List<TKey> keys = new();
4337
private BitVector32 flags;
4438

4539
/// <summary>
4640
/// Gets <see cref="Biconverter{TFrom,TTo}"/> instance
4741
/// used to convert flag value to <see cref="bool"/> and vice versa.
4842
/// </summary>
49-
public Biconverter<TFlag, bool> Converter
50-
{
51-
[DebuggerStepThrough]
52-
get { return converter; }
53-
}
43+
public Biconverter<TFlag, bool> Converter { [DebuggerStepThrough] get; }
5444

5545
/// <summary>
5646
/// Gets an <see cref="Collection{T}"/> containing the flags.
5747
/// </summary>
58-
public ICollection<TFlag> Flags
59-
{
60-
[DebuggerStepThrough]
61-
get { return Values; }
62-
}
48+
public ICollection<TFlag> Flags => Values;
6349

64-
#region IDictionary<TKey,TFlag> Members
50+
#region IReadOnlyDictionary<TKey,TFlag> Members
6551

6652
/// <inheritdoc/>
67-
public bool ContainsKey(TKey key)
68-
{
69-
return keys.Contains(key);
70-
}
53+
public bool ContainsKey(TKey key) => keys.Contains(key);
7154

7255
/// <inheritdoc/>
7356
public void Add(TKey key, TFlag flag)
@@ -78,13 +61,20 @@ public void Add(TKey key, TFlag flag)
7861
if (keys.Count >= MaxItemCount)
7962
throw new InvalidOperationException(string.Format(Strings.ExMaxItemCountIsN, MaxItemCount));
8063
keys.Add(key);
81-
flags[1 << (keys.Count - 1)] = converter.ConvertForward(flag);
64+
flags[1 << (keys.Count - 1)] = Converter.ConvertForward(flag);
8265
}
8366

8467
/// <inheritdoc/>
85-
public virtual void Add(TKey key)
68+
public virtual void Add(TKey key) => Add(key, default);
69+
70+
public bool TryAdd(TKey key, TFlag flag)
8671
{
87-
Add(key, default(TFlag));
72+
if (!ContainsKey(key)) {
73+
Add(key, flag);
74+
return true;
75+
}
76+
77+
return false;
8878
}
8979

9080
/// <inheritdoc/>
@@ -107,11 +97,11 @@ public bool Remove(TKey key)
10797
/// <inheritdoc/>
10898
public bool TryGetValue(TKey key, out TFlag value)
10999
{
110-
value = converter.ConvertBackward(false);
100+
value = Converter.ConvertBackward(false);
111101
int index = keys.IndexOf(key);
112102
if (index < 0)
113103
return false;
114-
value = converter.ConvertBackward(flags[1 << index]);
104+
value = Converter.ConvertBackward(flags[1 << index]);
115105
return true;
116106
}
117107

@@ -121,11 +111,7 @@ public TFlag this[TKey key]
121111
get
122112
{
123113
ArgumentValidator.EnsureArgumentIsNotDefault(key, "key");
124-
TFlag value;
125-
bool result = TryGetValue(key, out value);
126-
if (!result)
127-
throw new KeyNotFoundException();
128-
return value;
114+
return TryGetValue(key, out var value) ? value : throw new KeyNotFoundException();
129115
}
130116
set
131117
{
@@ -135,58 +121,42 @@ public TFlag this[TKey key]
135121
if (index < 0)
136122
Add(key, value);
137123
else
138-
flags[1 << index] = converter.ConvertForward(value);
124+
flags[1 << index] = Converter.ConvertForward(value);
139125
}
140126
}
141127

142128
/// <summary>
143129
/// Gets a list of keys.
144130
/// </summary>
145131
/// <returns>A list of keys.</returns>
146-
public IReadOnlyList<TKey> Keys
147-
{
148-
get { return readOnlyKeys; }
149-
}
132+
public IReadOnlyList<TKey> Keys => keys;
150133

151134
/// <inheritdoc/>
152-
ICollection<TKey> IDictionary<TKey, TFlag>.Keys
153-
{
154-
get { return readOnlyKeys; }
155-
}
135+
IEnumerable<TKey> IReadOnlyDictionary<TKey, TFlag>.Keys => Keys;
156136

157137
/// <summary>
158138
/// Gets an array of values.
159139
/// </summary>
160140
/// <returns>An array of values.</returns>
161141
public TFlag[] Values {
162142
get {
163-
var array = new TFlag[keys.Count];
164-
for (int i = 0; i < keys.Count; i++)
165-
array[i] = converter.ConvertBackward(flags[1 << i]);
143+
var n = keys.Count;
144+
var array = new TFlag[n];
145+
for (int i = 0; i < n; i++)
146+
array[i] = Converter.ConvertBackward(flags[1 << i]);
166147
return array;
167148
}
168149
}
169150

170151
/// <inheritdoc/>
171-
ICollection<TFlag> IDictionary<TKey, TFlag>.Values {
172-
get {
173-
var list = new List<TFlag>(keys.Count);
174-
for (int i = 0; i < keys.Count; i++) {
175-
list.Add(converter.ConvertBackward(flags[1 << i]));
176-
}
177-
return list;
178-
}
179-
}
152+
IEnumerable<TFlag> IReadOnlyDictionary<TKey, TFlag>.Values => Values;
180153

181154
#endregion
182155

183156
#region IList<KeyValuePair<TKey,TFlag>> Members
184157

185158
/// <inheritdoc/>
186-
public void Add(KeyValuePair<TKey, TFlag> item)
187-
{
188-
Add(item.Key, item.Value);
189-
}
159+
public void Add(KeyValuePair<TKey, TFlag> item) => Add(item.Key, item.Value);
190160

191161
/// <inheritdoc/>
192162
public void Clear()
@@ -197,61 +167,35 @@ public void Clear()
197167
}
198168

199169
/// <inheritdoc/>
200-
public bool Contains(KeyValuePair<TKey, TFlag> item)
201-
{
202-
return ContainsKey(item.Key);
203-
}
170+
public bool Contains(KeyValuePair<TKey, TFlag> item) => ContainsKey(item.Key);
204171

205172
/// <inheritdoc/>
206-
public void CopyTo(KeyValuePair<TKey, TFlag>[] array, int arrayIndex)
207-
{
208-
this.Copy(array, arrayIndex);
209-
}
173+
public void CopyTo(KeyValuePair<TKey, TFlag>[] array, int arrayIndex) => this.Copy(array, arrayIndex);
210174

211175
/// <inheritdoc/>
212-
public bool Remove(KeyValuePair<TKey, TFlag> item)
213-
{
214-
return Remove(item.Key);
215-
}
176+
public bool Remove(KeyValuePair<TKey, TFlag> item) => Remove(item.Key);
216177

217178
/// <inheritdoc/>
218-
public int Count
219-
{
220-
[DebuggerStepThrough]
221-
get { return keys.Count; }
222-
}
179+
public int Count => keys.Count;
223180

224181
/// <inheritdoc/>
225-
public bool IsReadOnly
226-
{
227-
[DebuggerStepThrough]
228-
get { return IsLocked; }
229-
}
182+
public bool IsReadOnly => IsLocked;
230183

231184
/// <inheritdoc/>
232-
int IList<KeyValuePair<TKey, TFlag>>.IndexOf(KeyValuePair<TKey, TFlag> item)
233-
{
234-
throw new NotSupportedException();
235-
}
185+
int IList<KeyValuePair<TKey, TFlag>>.IndexOf(KeyValuePair<TKey, TFlag> item) => throw new NotSupportedException();
236186

237187
/// <inheritdoc/>
238-
void IList<KeyValuePair<TKey, TFlag>>.Insert(int index, KeyValuePair<TKey, TFlag> item)
239-
{
240-
throw new NotSupportedException();
241-
}
188+
void IList<KeyValuePair<TKey, TFlag>>.Insert(int index, KeyValuePair<TKey, TFlag> item) => throw new NotSupportedException();
242189

243190
/// <inheritdoc/>
244-
void IList<KeyValuePair<TKey, TFlag>>.RemoveAt(int index)
245-
{
246-
throw new NotSupportedException();
247-
}
191+
void IList<KeyValuePair<TKey, TFlag>>.RemoveAt(int index) => throw new NotSupportedException();
248192

249193
/// <inheritdoc/>
250194
public KeyValuePair<TKey, TFlag> this[int index] {
251195
get {
252196
if (keys.Count <= index)
253197
throw new ArgumentOutOfRangeException("index");
254-
return new KeyValuePair<TKey, TFlag>(keys[index], converter.ConvertBackward(flags[1<<index]));
198+
return new KeyValuePair<TKey, TFlag>(keys[index], Converter.ConvertBackward(flags[1<<index]));
255199
}
256200
set {
257201
// TODO: implement?
@@ -264,31 +208,22 @@ public KeyValuePair<TKey, TFlag> this[int index] {
264208
#region ICollection<KeyValuePair<TKey, TFlag>> Members
265209

266210
/// <inheritdoc/>
267-
void ICollection<KeyValuePair<TKey, TFlag>>.Add(KeyValuePair<TKey, TFlag> key)
268-
{
269-
Add(key.Key, key.Value);
270-
}
211+
void ICollection<KeyValuePair<TKey, TFlag>>.Add(KeyValuePair<TKey, TFlag> key) => Add(key.Key, key.Value);
271212

272213
/// <inheritdoc/>
273214
bool ICollection<KeyValuePair<TKey, TFlag>>.Contains(KeyValuePair<TKey, TFlag> item)
274215
{
275216
int index = keys.IndexOf(item.Key);
276217
if (index < 0)
277218
return false;
278-
return flags[1 << index] == converter.ConvertForward(item.Value);
219+
return flags[1 << index] == Converter.ConvertForward(item.Value);
279220
}
280221

281222
/// <inheritdoc/>
282-
void ICollection<KeyValuePair<TKey, TFlag>>.CopyTo(KeyValuePair<TKey, TFlag>[] array, int arrayIndex)
283-
{
284-
this.Copy(array, arrayIndex);
285-
}
223+
void ICollection<KeyValuePair<TKey, TFlag>>.CopyTo(KeyValuePair<TKey, TFlag>[] array, int arrayIndex) => this.Copy(array, arrayIndex);
286224

287225
/// <inheritdoc/>
288-
bool ICollection<KeyValuePair<TKey, TFlag>>.Remove(KeyValuePair<TKey, TFlag> item)
289-
{
290-
throw new NotSupportedException();
291-
}
226+
bool ICollection<KeyValuePair<TKey, TFlag>>.Remove(KeyValuePair<TKey, TFlag> item) => throw new NotSupportedException();
292227

293228
#endregion
294229

@@ -298,7 +233,7 @@ bool ICollection<KeyValuePair<TKey, TFlag>>.Remove(KeyValuePair<TKey, TFlag> ite
298233
public IEnumerator<KeyValuePair<TKey, TFlag>> GetEnumerator()
299234
{
300235
for (int i = 0; i < keys.Count; i++)
301-
yield return new KeyValuePair<TKey, TFlag>(keys[i], converter.ConvertBackward(flags[1 << i]));
236+
yield return new KeyValuePair<TKey, TFlag>(keys[i], Converter.ConvertBackward(flags[1 << i]));
302237
}
303238

304239
/// <inheritdoc/>
@@ -314,23 +249,21 @@ IEnumerator IEnumerable.GetEnumerator()
314249
/// <inheritdoc/>
315250
public bool Equals(FlagCollection<TKey, TFlag> other)
316251
{
252+
if (ReferenceEquals(this, other))
253+
return true;
317254
if (other == null)
318255
return false;
319-
if (Count != other.Count)
256+
var count = Count;
257+
if (count != other.Count)
320258
return false;
321-
for (int i = 0; i < Count; i++)
259+
for (int i = 0; i < count; i++)
322260
if (!this[i].Equals(other[i]))
323261
return false;
324262
return true;
325263
}
326264

327265
/// <inheritdoc/>
328-
public override bool Equals(object obj)
329-
{
330-
if (ReferenceEquals(this, obj))
331-
return true;
332-
return Equals(obj as FlagCollection<TKey, TFlag>);
333-
}
266+
public override bool Equals(object obj) => obj is FlagCollection<TKey, TFlag> other && Equals(other);
334267

335268
/// <inheritdoc/>
336269
public override int GetHashCode() => HashCode.Combine(keys, flags);
@@ -347,7 +280,7 @@ public override bool Equals(object obj)
347280
public FlagCollection(Biconverter<TFlag, bool> converter)
348281
: this()
349282
{
350-
this.converter = converter;
283+
Converter = converter;
351284
}
352285

353286
/// <summary>
@@ -358,15 +291,13 @@ public FlagCollection(Biconverter<TFlag, bool> converter)
358291
public FlagCollection(Biconverter<TFlag, bool> converter, IEnumerable<KeyValuePair<TKey, TFlag>> enumerable)
359292
: this()
360293
{
361-
this.converter = converter;
294+
Converter = converter;
362295
foreach (KeyValuePair<TKey, TFlag> pair in enumerable)
363296
Add(pair.Key, pair.Value);
364297
}
365298

366299
private FlagCollection()
367300
{
368-
keys = new List<TKey>();
369-
readOnlyKeys = keys.AsReadOnly();
370301
}
371302

372303
#region ISerializable members
@@ -379,10 +310,9 @@ private FlagCollection()
379310
protected FlagCollection(SerializationInfo info, StreamingContext context)
380311
: base(info.GetBoolean("IsLocked"))
381312
{
382-
converter = (Biconverter<TFlag, bool>)
313+
Converter = (Biconverter<TFlag, bool>)
383314
info.GetValue("AdvancedConverter", typeof(Biconverter<TFlag, bool>));
384315
keys = (List<TKey>)info.GetValue("Keys", typeof(List<TKey>));
385-
readOnlyKeys = keys.AsReadOnly();
386316
flags = new BitVector32(info.GetInt32("Flags"));
387317
}
388318

@@ -395,7 +325,7 @@ protected FlagCollection(SerializationInfo info, StreamingContext context)
395325
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
396326
{
397327
info.AddValue("IsLocked", IsLocked);
398-
info.AddValue("AdvancedConverter", converter);
328+
info.AddValue("AdvancedConverter", Converter);
399329
info.AddValue("Keys", keys);
400330
info.AddValue("Flags", flags.Data);
401331
}

0 commit comments

Comments
 (0)