99 lines
3.2 KiB
C#
99 lines
3.2 KiB
C#
#nullable enable
|
|
namespace Bts.DataStreamCore;
|
|
|
|
using BCG;
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
|
|
// I would have named this ImmutableBlueTable, but that was already taken.
|
|
public class BlueTableImmutable : IBlueRowCollection, IImmutableRowCollection {
|
|
readonly ImmutableDictionary<int, IBlueRow> rows;
|
|
|
|
public BlueTableImmutable(IBlueTableSchema schema)
|
|
: this(schema, ImmutableDictionary<int, IBlueRow>.Empty) { }
|
|
|
|
public BlueTableImmutable(IBlueTableSchema schema, ImmutableDictionary<int, IBlueRow> rows) {
|
|
this.schema = schema;
|
|
this.rows = rows;
|
|
}
|
|
|
|
public int Count => rows.Count;
|
|
public bool IsSynchronized => false;
|
|
public IBlueTableSchema schema { get; }
|
|
public object SyncRoot => this;
|
|
|
|
public IBlueRow this[int id] => rows[id];
|
|
|
|
public bool containsID(int id) =>
|
|
rows.ContainsKey(id);
|
|
|
|
public void CopyTo(Array array, int index) {
|
|
foreach (var r in rows.Values) {
|
|
array.SetValue(r, index++);
|
|
}
|
|
}
|
|
|
|
public IEnumerator GetEnumerator() =>
|
|
rows.Values.GetEnumerator();
|
|
|
|
public DataPacketBuilder ToDataPacketBuilder() =>
|
|
new(this);
|
|
|
|
public class DataPacketBuilder {
|
|
readonly IBlueTableSchema schema;
|
|
readonly ImmutableDictionary<int, IBlueRow>.Builder table;
|
|
readonly ImmutableDictionary<int, IBlueRow>.Builder added =
|
|
ImmutableDictionary<int, IBlueRow>.Empty.ToBuilder();
|
|
readonly ImmutableDictionary<int, IBlueRow>.Builder removed =
|
|
ImmutableDictionary<int, IBlueRow>.Empty.ToBuilder();
|
|
|
|
public DataPacketBuilder(BlueTableImmutable table) {
|
|
schema = table.schema;
|
|
this.table = table.rows.ToBuilder();
|
|
}
|
|
|
|
public void AddOrUpdate(IBlueRow row, IEqualityComparer<IBlueRow>? comparer = null) {
|
|
var id = row.Id();
|
|
if (table.TryGetValue(id, out var orig)) {
|
|
if (comparer?.Equals(row, orig) ?? false) {
|
|
// No op: This row was already in the table (according to 'comparer').
|
|
// Remove it from 'added' and 'removed'.
|
|
added.Remove(id);
|
|
removed.Remove(id);
|
|
return;
|
|
}
|
|
// Change op: A row with this id was already in the table,
|
|
// but its values have changed (according to 'comparer').
|
|
removed[id] = orig;
|
|
}
|
|
added[id] = row;
|
|
}
|
|
|
|
public void Remove(int id) {
|
|
added.Remove(id);
|
|
if (table.TryGetValue(id, out var orig)) {
|
|
removed[id] = orig;
|
|
}
|
|
}
|
|
|
|
public DataPacket ToDataPacket(bool reset = true) {
|
|
table.RemoveRange(removed.Keys);
|
|
table.AddRange(added);
|
|
var newRows = new BlueTableImmutable(schema, table.ToImmutable());
|
|
var addedRows = new BlueTableImmutable(schema, added.ToImmutable());
|
|
var removedRows = new BlueTableImmutable(schema, removed.ToImmutable());
|
|
if (reset) {
|
|
added.Clear();
|
|
removed.Clear();
|
|
}
|
|
return new(newRows, addedRows, removedRows);
|
|
}
|
|
|
|
public BlueTableImmutable ToImmutable() =>
|
|
new(schema, table.ToImmutable());
|
|
}
|
|
}
|