mirror of
https://github.com/zap-proto/cs.git
synced 2026-10-30 15:05:32 +00:00
Finishes the in-flight capnp→ZAP rebrand on this branch. The prior commits
renamed identifiers/namespaces/files/projects (Capnp.Net.Runtime→Zap.Net.Runtime,
CapnpC→ZapC, .capnp→.zap) but left the human-readable brand name "Cap'n Proto"
throughout doc-comments, .csproj/.nuspec descriptions, README, MSBuild .xaml
rule display names, and the generated XML doc. This completes brand neutrality:
- Replace 154 "Cap'n Proto" / 4 "Cap'n-Proto" / 1 "Cap'n'p" prose occurrences
with "ZAP" across 32 first-party files (runtime, generator, zapc-csharp,
MSBuild integration, chocolatey nuspecs, README, docs, XML doc).
- Revert the LICENSE provenance URL to the real upstream fork
(c80k/capnproto-dotnetcore) — upstream-fork license headers must stay.
- Canonicalize project/repo URLs to github.com/zap-proto/cs (were fabricated
c80k/zap-dotnetcore) in csproj/nuspec/VERIFICATION/README badges.
- Canonicalize docs URLs zap-protocol(.github.io|/zap-cs|/zap-cpp-core)
→ zap-proto.dev / github.com/zap-proto/{cs,cpp-core}.
- Collapse redundant "zap \"ZAP\"" PackageTags to "zap".
Verified consistent (no toolchain on host): every .sln/.csproj ProjectReference
resolves; all namespaces are Zap*/ZapC*; MSBuild task chain
(GenerateZapFileCodeBehindTask, ZapFiles ItemGroup, _ZapcCsharp_TaskAssembly)
is uniformly renamed; props/targets/xaml/coverage/chocolatey carry no capnp.
Deliberately preserved as upstream-derived test data (not first-party source):
upstream Cap'n Proto schema fixtures (rpc.zap, rpc-twoparty.zap, json.zap,
rpc-csharp.zap), golden compiler-error outputs (errors.txt), and the
machine-generated DO-NOT-EDIT test.zap.{c++,h}. Their "Cap'n Proto" strings are
the literal output of the external schema compiler the compat test matches.
146 lines
5.2 KiB
C#
146 lines
5.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Zap
|
|
{
|
|
/// <summary>
|
|
/// The segment allocator default implementation.
|
|
/// </summary>
|
|
public class SegmentAllocator : ISegmentAllocator
|
|
{
|
|
class Segment
|
|
{
|
|
public Segment(Memory<ulong> mem, uint id)
|
|
{
|
|
Mem = mem;
|
|
Id = id;
|
|
}
|
|
|
|
public uint Id { get; }
|
|
public Memory<ulong> Mem { get; }
|
|
public int FreeOffset { get; set; }
|
|
|
|
public bool TryAllocate(uint nwords, out int offset)
|
|
{
|
|
if (checked(FreeOffset + (int)nwords) <= Mem.Length)
|
|
{
|
|
offset = FreeOffset;
|
|
int count = (int)nwords;
|
|
FreeOffset += count;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
offset = -1;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool IsFull => FreeOffset >= Mem.Length;
|
|
}
|
|
|
|
readonly int _defaultSegmentSize;
|
|
readonly List<Segment> _segments = new List<Segment>();
|
|
readonly List<Segment> _nonFullSegments = new List<Segment>();
|
|
|
|
/// <summary>
|
|
/// Constructs an instance.
|
|
/// </summary>
|
|
/// <param name="defaultSegmentSize">Default size (in words) of a newly allocated segment. If a single allocation requires
|
|
/// a bigger size, a bigger dedicated segment will be allocated. On the wire, segments will be truncated to their actual
|
|
/// occupancies.</param>
|
|
public SegmentAllocator(int defaultSegmentSize = 64)
|
|
{
|
|
_defaultSegmentSize = defaultSegmentSize;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The list of currently allocated segments, each one truncated to its actual occupancy.
|
|
/// </summary>
|
|
public IReadOnlyList<Memory<ulong>> Segments => _segments.LazyListSelect(s => s.Mem.Slice(0, s.FreeOffset));
|
|
|
|
/// <summary>
|
|
/// Allocates memory.
|
|
/// </summary>
|
|
/// <param name="nwords">Number of words to allocate</param>
|
|
/// <param name="preferredSegmentIndex">Preferred segment index. If enough space is available,
|
|
/// memory will be allocated inside that segment. Otherwise, a different segment will be chosen, or
|
|
/// a new one will be allocated, or allocation will fail (depending on <paramref name="forcePreferredSegment"/>).</param>
|
|
/// <param name="result">The allocated memory slice in case of success (<code>default(SegmentSlice) otherwise)</code></param>
|
|
/// <param name="forcePreferredSegment">Whether using the preferred segment is mandatory. If it is and there is not
|
|
/// enough space available, allocation will fail.</param>
|
|
/// <returns>Whether allocation was successful.</returns>
|
|
public bool Allocate(uint nwords, uint preferredSegmentIndex, out SegmentSlice result, bool forcePreferredSegment)
|
|
{
|
|
result = default;
|
|
Segment segment;
|
|
|
|
if (preferredSegmentIndex < _segments.Count)
|
|
{
|
|
segment = _segments[(int)preferredSegmentIndex];
|
|
|
|
if (segment.TryAllocate(nwords, out result.Offset))
|
|
{
|
|
result.SegmentIndex = preferredSegmentIndex;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (forcePreferredSegment)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < _nonFullSegments.Count; i++)
|
|
{
|
|
segment = _nonFullSegments[i];
|
|
|
|
if (segment.TryAllocate(nwords, out result.Offset))
|
|
{
|
|
result.SegmentIndex = segment.Id;
|
|
|
|
if (segment.IsFull)
|
|
{
|
|
int n = _nonFullSegments.Count - 1;
|
|
var tmp = _nonFullSegments[i];
|
|
_nonFullSegments[i] = _nonFullSegments[n];
|
|
_nonFullSegments[n] = tmp;
|
|
_nonFullSegments.RemoveAt(n);
|
|
}
|
|
else if (i > 0)
|
|
{
|
|
var tmp = _nonFullSegments[i];
|
|
_nonFullSegments[i] = _nonFullSegments[0];
|
|
_nonFullSegments[0] = tmp;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
int size = Math.Max((int)nwords, _defaultSegmentSize);
|
|
var storage = new ulong[size];
|
|
var mem = new Memory<ulong>(storage);
|
|
segment = new Segment(mem, (uint)_segments.Count);
|
|
|
|
_segments.Add(segment);
|
|
|
|
if (!segment.TryAllocate(nwords, out result.Offset))
|
|
throw new InvalidProgramException();
|
|
|
|
result.SegmentIndex = segment.Id;
|
|
|
|
if (!segment.IsFull)
|
|
{
|
|
_nonFullSegments.Add(segment);
|
|
|
|
int n = _nonFullSegments.Count - 1;
|
|
var tmp = _nonFullSegments[0];
|
|
_nonFullSegments[0] = _nonFullSegments[n];
|
|
_nonFullSegments[n] = tmp;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
} |