public override DatabaseBuilder AddArray <T, TKey>( IConstSizeSerializer <T> serializer, Func <Database, IEnumerable <T> > elements, Func <T, TKey> selector, IComparer <TKey>?comparer) { try { var headerPosition = stream.Position; // write a dummy header var dummyHeaderBytes = new ArrayHeader(serializer).AsBytes(); stream.Write(dummyHeaderBytes); var elementLength = serializer.ElementSize; Utility.EnsureArrayOfMinimalSize(ref buffer, elementLength); long elementCount = 0; var elementsEnumerable = elements(db); if (comparer != null) { elementsEnumerable = elementsEnumerable.OrderBy(selector, comparer); } foreach (var element in elementsEnumerable) { serializer.TrySerialize(element, buffer.AsSpan(), out _); stream.Write(buffer, 0, elementLength); elementCount++; } var pastEndPosition = stream.Position; stream.Seek(headerPosition, SeekOrigin.Begin); var arrayHeader = new ArrayHeader(serializer) { OverallLength = elementLength * elementCount, RecordCount = elementCount, StartsAt = headerPosition + dummyHeaderBytes.Length, EndsAt = pastEndPosition, Type = 1 }; stream.Write(arrayHeader.AsBytes()); stream.Seek(pastEndPosition, SeekOrigin.Begin); headers.Add(arrayHeader); } catch { stream.Dispose(); db.Dispose(); throw; } return(this); }
private ArrayHeader ReadNextHeader <T>(ISerializer <T> serializer) where T : notnull { var preHeaderPosition = stream.Position; var header = new ArrayHeader(serializer); var buffer = new byte[sizeof(long)]; stream.ReadFully(buffer); header.RecordCount = BitConverter.ToInt64(buffer, 0); stream.ReadFully(buffer); header.OverallLength = BitConverter.ToInt64(buffer, 0); stream.ReadFully(buffer); header.Type = BitConverter.ToInt64(buffer, 0); // TODO: validate header var headerBytes = header.AsBytes(); header.StartsAt = preHeaderPosition + headerBytes.Length; header.EndsAt = header.StartsAt + header.OverallLength; stream.Seek(header.EndsAt, SeekOrigin.Begin); return(header); }
public override DatabaseBuilder AddIndirectArray <T, TKey>( ISerializer <T> serializer, Func <Database, IEnumerable <T> > elements, Func <T, TKey> selector, IComparer <TKey>?comparer) { try { var headerPosition = stream.Position; // write a dummy header var dummyHeaderBytes = new ArrayHeader(serializer).AsBytes(); stream.Write(dummyHeaderBytes); var pointersArrayOffsetPosition = stream.Position; stream.Write(BitConverter.GetBytes(0L)); var dataStartPosition = stream.Position; long elementCount = 0; // TODO: less lazy way var offsetList = new List <long>(); var elementsEnumerable = elements(db); if (comparer != null) { elementsEnumerable = elementsEnumerable.OrderBy(selector, comparer); } foreach (var element in elementsEnumerable) { int actualLength; while (!serializer.TrySerialize(element, buffer.AsSpan(), out actualLength)) { Utility.Reallocate(ref buffer); } offsetList.Add(stream.Position - dataStartPosition); stream.Write(BitConverter.GetBytes(actualLength)); stream.Write(buffer, 0, actualLength); elementCount++; } var pointerArrayPosition = stream.Position; stream.Position += elementCount * sizeof(long); var pastEndPosition = stream.Position; stream.Seek(headerPosition, SeekOrigin.Begin); var arrayHeader = new ArrayHeader(serializer) { OverallLength = pastEndPosition - pointersArrayOffsetPosition, RecordCount = elementCount, StartsAt = pointersArrayOffsetPosition, EndsAt = pastEndPosition, Type = 2 }; stream.Write(arrayHeader.AsBytes()); stream.Write(BitConverter.GetBytes(pointerArrayPosition - pointersArrayOffsetPosition)); stream.Seek(pointerArrayPosition, SeekOrigin.Begin); foreach (var off in offsetList) { stream.Write(BitConverter.GetBytes(off)); } stream.Seek(pastEndPosition, SeekOrigin.Begin); headers.Add(arrayHeader); } catch { stream.Dispose(); db.Dispose(); throw; } return(this); }