Created
August 27, 2026 12:35
-
-
Save roipeker/bb9e5b4be96fc826fd8321545ff7ac89 to your computer and use it in GitHub Desktop.
Graphx Buffer
This file contains hidden or 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
| abstract base class _GNumericBuffer { | |
| _GNumericBuffer(this._length, this._growable); | |
| int _length; | |
| final bool _growable; | |
| int _version = 0; | |
| int _dirtyStart = -1; | |
| int _dirtyEnd = -1; | |
| /// Number of logical elements currently exposed by this buffer. | |
| int get length => _length; | |
| /// Number of elements available in the current typed storage. | |
| int get capacity; | |
| /// Whether [setLength] and capacity growth are permitted. | |
| bool get isGrowable => _growable; | |
| /// Monotonic change counter for content notifications and structural changes. | |
| /// | |
| /// Direct writes through [GFloat32Buffer.data], [GUint16Buffer.data], or | |
| /// [GUint32Buffer.data] become visible to this counter only when the caller | |
| /// explicitly invokes [markDirty]. | |
| int get version => _version; | |
| /// Whether a content/storage range is currently dirty. | |
| bool get isDirty => _dirtyStart >= 0; | |
| /// Inclusive dirty start, or `-1` when [isDirty] is false. | |
| int get dirtyStart => _dirtyStart; | |
| /// Exclusive dirty end, or `-1` when [isDirty] is false. | |
| int get dirtyEnd => _dirtyEnd; | |
| /// Changes logical length without allocating. | |
| /// | |
| /// Fixed buffers reject length changes. Growable buffers accept values only | |
| /// through [capacity]; callers must reserve explicitly before exceeding it. | |
| /// Growing within capacity marks the newly exposed range dirty. Shrinking | |
| /// changes [version] but does not rewrite storage. | |
| void setLength(int newLength) { | |
| if (newLength < 0 || newLength > capacity) { | |
| throw RangeError.range(newLength, 0, capacity, 'newLength'); | |
| } | |
| if (newLength == _length) return; | |
| if (!_growable) { | |
| throw StateError('Fixed buffers cannot change logical length.'); | |
| } | |
| final oldLength = _length; | |
| _length = newLength; | |
| _version++; | |
| if (newLength > oldLength) { | |
| _mergeDirty(oldLength, newLength); | |
| } else { | |
| _trimDirty(newLength); | |
| } | |
| } | |
| /// Marks changed logical elements in `[start, end)`. | |
| /// | |
| /// Multiple calls merge into one retained range and never allocate. | |
| void markDirty(int start, int end) { | |
| if (start < 0 || start > _length) { | |
| throw RangeError.range(start, 0, _length, 'start'); | |
| } | |
| if (end < start || end > _length) { | |
| throw RangeError.range(end, start, _length, 'end'); | |
| } | |
| if (start == end) return; | |
| _mergeDirty(start, end); | |
| _version++; | |
| } | |
| /// Marks the complete logical range dirty. | |
| void markAllDirty() { | |
| if (_length == 0) return; | |
| _mergeDirty(0, _length); | |
| _version++; | |
| } | |
| /// Clears dirty state without changing [version]. | |
| void clearDirty() { | |
| _dirtyStart = -1; | |
| _dirtyEnd = -1; | |
| } | |
| void _validateReserve(int newCapacity) { | |
| _validateNonNegative(newCapacity, 'newCapacity'); | |
| if (newCapacity > capacity && !_growable) { | |
| throw StateError('Fixed buffers cannot grow capacity.'); | |
| } | |
| } | |
| void _didReplaceStorage() { | |
| _version++; | |
| if (_length > 0) _mergeDirty(0, _length); | |
| } | |
| void _mergeDirty(int start, int end) { | |
| if (start == end) return; | |
| if (_dirtyStart < 0) { | |
| _dirtyStart = start; | |
| _dirtyEnd = end; | |
| return; | |
| } | |
| if (start < _dirtyStart) _dirtyStart = start; | |
| if (end > _dirtyEnd) _dirtyEnd = end; | |
| } | |
| void _trimDirty(int newLength) { | |
| if (_dirtyStart < 0) return; | |
| if (_dirtyStart >= newLength) { | |
| clearDirty(); | |
| return; | |
| } | |
| if (_dirtyEnd > newLength) _dirtyEnd = newLength; | |
| } | |
| } | |
| void _validateInitialState(int length, int capacity) { | |
| _validateNonNegative(capacity, 'capacity'); | |
| if (length < 0 || length > capacity) { | |
| throw RangeError.range(length, 0, capacity, 'length'); | |
| } | |
| } | |
| void _validateNonNegative(int value, String name) { | |
| if (value < 0) { | |
| throw RangeError.range(value, 0, null, name); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment