-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add serialization for primitive lists and protobuf lists
- Loading branch information
Showing
8 changed files
with
395 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using System.Buffers; | ||
|
||
namespace RocksDb.Extensions; | ||
|
||
/// <summary> | ||
/// Serializes lists of fixed-size elements like primitive types (int, long, etc.) where each element | ||
/// occupies the same number of bytes in memory. This implementation optimizes for performance by | ||
/// pre-calculating buffer sizes based on element count. | ||
/// </summary> | ||
/// <remarks> | ||
/// Use this serializer when working with lists of primitive types or structs where all elements | ||
/// have identical size. The serialized format consists of: | ||
/// - 4 bytes: List length (number of elements) | ||
/// - Remaining bytes: Contiguous array of serialized elements | ||
/// </remarks> | ||
internal class FixedSizeListSerializer<T> : ISerializer<IList<T>> | ||
{ | ||
private readonly ISerializer<T> _scalarSerializer; | ||
|
||
public FixedSizeListSerializer(ISerializer<T> scalarSerializer) | ||
{ | ||
_scalarSerializer = scalarSerializer; | ||
} | ||
|
||
public bool TryCalculateSize(ref IList<T> value, out int size) | ||
{ | ||
size = sizeof(int); // size of the list | ||
if (value.Count == 0) | ||
{ | ||
return true; | ||
} | ||
|
||
var referentialElement = value[0]; | ||
if (_scalarSerializer.TryCalculateSize(ref referentialElement, out var elementSize)) | ||
{ | ||
size += value.Count * elementSize; | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
public void WriteTo(ref IList<T> value, ref Span<byte> span) | ||
{ | ||
// Write the size of the list | ||
var slice = span.Slice(0, sizeof(int)); | ||
BitConverter.TryWriteBytes(slice, value.Count); | ||
|
||
// Write the elements of the list | ||
int offset = sizeof(int); | ||
var elementSize = (span.Length - offset) / value.Count; | ||
for (int i = 0; i < value.Count; i++) | ||
{ | ||
var element = value[i]; | ||
slice = span.Slice(offset, elementSize); | ||
_scalarSerializer.WriteTo(ref element, ref slice); | ||
offset += elementSize; | ||
} | ||
} | ||
|
||
public void WriteTo(ref IList<T> value, IBufferWriter<byte> buffer) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public IList<T> Deserialize(ReadOnlySpan<byte> buffer) | ||
{ | ||
// Read the size of the list | ||
var slice = buffer.Slice(0, sizeof(int)); | ||
var size = BitConverter.ToInt32(slice); | ||
|
||
var list = new List<T>(size); | ||
|
||
// Read the elements of the list | ||
int offset = sizeof(int); | ||
var elementSize = (buffer.Length - offset) / size; | ||
for (int i = 0; i < size; i++) | ||
{ | ||
slice = buffer.Slice(offset, elementSize); | ||
var element = _scalarSerializer.Deserialize(slice); | ||
list.Add(element); | ||
offset += elementSize; | ||
} | ||
|
||
return list; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
using System.Buffers; | ||
|
||
namespace RocksDb.Extensions; | ||
|
||
/// <summary> | ||
/// Serializes lists containing variable-size elements like strings or complex objects where each element | ||
/// may occupy a different number of bytes when serialized. | ||
/// </summary> | ||
/// <remarks> | ||
/// Use this serializer for lists containing elements that may have different sizes (strings, nested objects, etc.). | ||
/// The serialized format consists of: | ||
/// - 4 bytes: List length (number of elements) | ||
/// - For each element: | ||
/// - 4 bytes: Size of the serialized element | ||
/// - N bytes: Serialized element data | ||
/// </remarks> | ||
internal class VariableSizeListSerializer<T> : ISerializer<IList<T>> | ||
{ | ||
private readonly ISerializer<T> _scalarSerializer; | ||
|
||
public VariableSizeListSerializer(ISerializer<T> scalarSerializer) | ||
{ | ||
_scalarSerializer = scalarSerializer; | ||
} | ||
|
||
public bool TryCalculateSize(ref IList<T> value, out int size) | ||
{ | ||
size = sizeof(int); // size of the list | ||
if (value.Count == 0) | ||
{ | ||
return true; | ||
} | ||
|
||
for (int i = 0; i < value.Count; i++) | ||
{ | ||
var element = value[i]; | ||
if (_scalarSerializer.TryCalculateSize(ref element, out var elementSize)) | ||
{ | ||
size += sizeof(int); | ||
size += elementSize; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public void WriteTo(ref IList<T> value, ref Span<byte> span) | ||
{ | ||
// Write the size of the list | ||
var slice = span.Slice(0, sizeof(int)); | ||
BitConverter.TryWriteBytes(slice, value.Count); | ||
|
||
// Write the elements of the list | ||
int offset = sizeof(int); | ||
for (int i = 0; i < value.Count; i++) | ||
{ | ||
var element = value[i]; | ||
if (_scalarSerializer.TryCalculateSize(ref element, out var elementSize)) | ||
{ | ||
slice = span.Slice(offset, sizeof(int)); | ||
BitConverter.TryWriteBytes(slice, elementSize); | ||
offset += sizeof(int); | ||
|
||
slice = span.Slice(offset, elementSize); | ||
_scalarSerializer.WriteTo(ref element, ref slice); | ||
offset += elementSize; | ||
} | ||
} | ||
} | ||
|
||
public void WriteTo(ref IList<T> value, IBufferWriter<byte> buffer) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public IList<T> Deserialize(ReadOnlySpan<byte> buffer) | ||
{ | ||
// Read the size of the list | ||
var slice = buffer.Slice(0, sizeof(int)); | ||
var size = BitConverter.ToInt32(slice); | ||
|
||
var list = new List<T>(size); | ||
|
||
// Read the elements of the list | ||
int offset = sizeof(int); | ||
for (int i = 0; i < size; i++) | ||
{ | ||
slice = buffer.Slice(offset, sizeof(int)); | ||
var elementSize = BitConverter.ToInt32(slice); | ||
offset += sizeof(int); | ||
|
||
slice = buffer.Slice(offset, elementSize); | ||
var element = _scalarSerializer.Deserialize(slice); | ||
list.Add(element); | ||
offset += elementSize; | ||
} | ||
|
||
return list; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.