using System; using System.Collections.Generic; using System.Linq; using ZeroLevel.Services.Serialization; namespace ZeroLevel.HNSW { internal sealed class ReadOnlyCompactBiDirectionalLinksSet : IBinarySerializable, IDisposable { private const int HALF_LONG_BITS = 32; private Dictionary _set = new Dictionary(); internal int Count => _set.Count; internal IEnumerable FindLinksForId(int id) { if (_set.ContainsKey(id)) { return _set[id]; } return Enumerable.Empty(); } public void Dispose() { _set.Clear(); _set = null; } public void Serialize(IBinaryWriter writer) { writer.WriteBoolean(false); // false - set without weights writer.WriteInt32(_set.Count); foreach (var record in _set) { writer.WriteInt32(record.Key); writer.WriteCollection(record.Value); } } public void Deserialize(IBinaryReader reader) { _set.Clear(); _set = null; if (reader.ReadBoolean() == false) { var count = reader.ReadInt32(); _set = new Dictionary(count); for (int i = 0; i < count; i++) { var key = reader.ReadInt32(); var value = reader.ReadInt32Array(); _set.Add(key, value); } } else { var count = reader.ReadInt32(); _set = new Dictionary(count); // hack, We know that an sortedset has been saved long key; int id1, id2; var prevId = -1; var set = new HashSet(); for (int i = 0; i < count; i++) { key = reader.ReadLong(); id1 = (int)(key >> HALF_LONG_BITS); id2 = (int)(key - (((long)id1) << HALF_LONG_BITS)); reader.ReadFloat(); // SKIP if (prevId == -1) { prevId = id1; if (id1 != id2) { set.Add(id2); } } else if (prevId != id1) { _set.Add(prevId, set.ToArray()); set.Clear(); prevId = id1; } else { if (id1 != id2) { set.Add(id2); } } } if (set.Count > 0) { _set.Add(prevId, set.ToArray()); set.Clear(); } } } } }