Class MemoryPatch
- Namespace
- CStructSharp.Memory
- Assembly
- CStructSharp.dll
A prepared, immutable write: the logical range to change and the physical fragments, with expected and replacement bytes, that realize it.
public sealed class MemoryPatch
- Inheritance
-
MemoryPatch
- Inherited Members
Remarks
A patch separates deciding what to write from writing it. Planning (Create(MemoryRegion, ReadOnlySpan<byte>, MemoryAccessContext?, byte[]?), or PlanUpdate(MemoryRegion, string, string, object?, MemoryAccessContext?) which calls it) resolves every known mapping layer into the final physical fragments, records each fragment's current bytes and its source's generation, and stages the replacement bytes. Nothing is modified. An editor can show those fragments to a user before Commit(MemoryAccessContext?) performs the writes.
Two safety rules follow from the design. Physical overlap between fragments is rejected, so a logical edit cannot write the same file bytes twice through aliased mappings. And commit re-validates every fragment (writable source, unchanged generation, unchanged expected bytes) before its first write, so a patch prepared against an image that has since changed fails with StaleSource rather than corrupting it.
What a patch cannot promise is atomicity. Arbitrary sources share no transaction or lock, so a later fragment can fail after earlier ones succeeded, and the failing write may be partial. Commit(MemoryAccessContext?) reports that state precisely through MemoryPatchCommitException and never claims rollback. When the original must survive, commit into an OverlayMemorySource.
Properties
Fragments
Gets the physical fragments in logical order; concatenating their replacements reproduces the logical replacement.
public IReadOnlyList<MemoryPatchFragment> Fragments { get; }
Property Value
LogicalRegion
Gets the logical range the patch changes, before mapping layers were resolved.
public MemoryRegion LogicalRegion { get; }
Property Value
Methods
Commit(MemoryAccessContext?)
Re-validates every fragment, then writes them in order; a failure during writing reports what completed and what is uncertain.
public void Commit(MemoryAccessContext? context = null)
Parameters
contextMemoryAccessContextShared operation budget and cancellation, or null to create a default budget.
Remarks
Validation runs over all fragments before any write, so a patch that is entirely stale fails without touching the image. Each fragment must have a source that implements IWritableMemorySource, a generation equal to the one captured at planning, and current bytes equal to its expected bytes. The generation is checked both before and after the comparison read, so a change during that read is caught.
No lock spans arbitrary sources, so a mutation between validation and writing remains possible. If a write throws, the exception is wrapped in MemoryPatchCommitException with the byte count of the fragments confirmed before it and the index of the fragment whose completion is uncertain. Do not retry automatically or assume the original bytes were restored. Passing the planning context here shares one budget across planning and commit; a fresh context starts a new one.
Exceptions
- NotSupportedException
A fragment's source does not implement IWritableMemorySource.
- MemoryAccessException
Pre-write validation found unavailable bytes, a stale source, or an exhausted budget.
- OperationCanceledException
Cancellation was observed before the write phase.
- MemoryPatchCommitException
A fragment write failed; earlier writes completed and the failing one may be partial.
Create(MemoryRegion, ReadOnlySpan<byte>, MemoryAccessContext?, byte[]?)
Plans a byte-for-byte replacement of a region, flattening mappings and snapshotting each fragment's current bytes and generation.
public static MemoryPatch Create(MemoryRegion region, ReadOnlySpan<byte> replacement, MemoryAccessContext? context = null, byte[]? expected = null)
Parameters
regionMemoryRegionFinite caller-owned region to replace.
replacementReadOnlySpan<byte>New bytes, exactly
region.Lengthof them.contextMemoryAccessContextShared operation budget and cancellation, or null to create a default budget.
expectedbyte[]Bytes the caller believes the region currently holds, or null to skip that check.
Returns
- MemoryPatch
An immutable patch describing the fragments and their bytes.
Remarks
The replacement must be exactly as long as the region. When expected is supplied, each
fragment's current bytes are also compared with it, so a caller can assert that the bytes it read earlier
are still there. Planning does not require a writable source: previewing an edit against a read-only capture
is valid, and the writable check is deferred to Commit(MemoryAccessContext?).
Exceptions
- ArgumentNullException
regionis null.- ArgumentException
replacementorexpectedis not exactlyregion.Lengthbytes long.- CStructWriteException
Aliased mappings make two fragments cover the same physical bytes.
- MemoryAccessException
The current bytes are unavailable, differ from
expected, changed while being read, or exceed the budget.- OperationCanceledException
The context's token was cancelled.