internal static int GetRecordLength(ArrayHeader header)
        {
            var len = header.OverallLength / header.RecordCount;

            if (len > int.MaxValue || len < 1)
            {
                throw new InvalidOperationException();
            }
            return((int)len);
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
0
        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);
        }