Skip to content

Commit 6a174e3

Browse files
authored
V5.1.0
1 parent 9598028 commit 6a174e3

17 files changed

Lines changed: 675 additions & 267 deletions

‎CHANGELOG.md‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
<!-- markdownlint-disable-file MD025 -->
22

3+
# 5.1.0
4+
5+
- **BinaryWriterPool**:
6+
- **New Feature**: Added `BinaryWriterPool.configure()` for global pool settings (`maxPoolSize`, `initialBufferSize`, `maxReusableCapacity`).
7+
- **New Feature**: Implemented "best-fit" acquisition strategy to minimize memory fragmentation.
8+
- **New Feature**: Added `BinaryWriterPool.stats` for real-time pool performance monitoring.
9+
- **Improvement**: Optimized `release()` and `clear()` logic with zero-allocation buffer detachment.
10+
- **Bug Fix**: Renamed `initialBufferSizer` to `initialBufferSize` (API alignment).
11+
12+
- **BinaryWriter**:
13+
- **New Feature**: Added `operator []` and `operator []=` for symmetric random access to written bytes.
14+
- **New Feature**: Added `copy` parameter to `takeBytes()` to allow returning data while retaining the internal buffer for pool reuse.
15+
- **Improvement**: Refactored `writeUint8At` as a functional alias for `operator []=`.
16+
- **Fix**: Corrected documentation for bounds checks on random access methods.
17+
18+
- **Documentation**:
19+
- Unified terminology (using "1 KiB" consistently).
20+
- Updated `withWriter` examples to recommend `takeBytes(copy: true)` for pooling scenarios.
21+
322
# 5.0.0
423

524
- **BREAKING CHANGES:**

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
```yaml
2222
dependencies:
23-
pro_binary: ^5.0.0
23+
pro_binary: ^5.1.0
2424
```
2525
2626
## Quick Start

‎lib/src/binary_reader.dart‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:convert';
22
import 'dart:typed_data';
33

44
import 'constants.dart';
5+
import 'internal.dart';
56

67
/// A high-performance binary reader for decoding data from a byte buffer.
78
///
@@ -635,7 +636,7 @@ extension type BinaryReader._(_ReaderState _rs) {
635636
}
636637

637638
if (length == 0) {
638-
return Uint8List(0);
639+
return emptyUintList_;
639640
}
640641

641642
final peekOffset = offset ?? _rs.offset;

‎lib/src/binary_writer.dart‎

Lines changed: 87 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,24 @@ extension type BinaryWriter._(_WriterState _ws) {
163163
writeVarUint(encoded);
164164
}
165165

166+
/// Writes a boolean value as a single byte.
167+
///
168+
/// `true` is written as `1` and `false` as `0`.
169+
///
170+
/// Example:
171+
/// ```dart
172+
/// writer.writeBool(true); // Writes byte 0x01
173+
/// writer.writeBool(false); // Writes byte 0x00
174+
/// ```
175+
///
176+
@pragma('vm:prefer-inline')
177+
@pragma('dart2js:tryInline')
178+
// Disable lint to allow positional boolean parameter for simplicity
179+
// ignore: avoid_positional_boolean_parameters
180+
void writeBool(bool value) {
181+
writeUint8(value ? 1 : 0);
182+
}
183+
166184
/// Writes an 8-bit unsigned integer (0-255).
167185
///
168186
/// Example:
@@ -657,7 +675,7 @@ extension type BinaryWriter._(_WriterState _ws) {
657675
}
658676

659677
@pragma('vm:prefer-inline')
660-
@pragma('vm:prefer-inline')
678+
@pragma('dart2js:tryInline')
661679
int _varIntSize(int value) => switch (value) {
662680
< 0x80 => 1,
663681
< 0x4000 => 2,
@@ -684,7 +702,7 @@ extension type BinaryWriter._(_WriterState _ws) {
684702
/// writer.writeStringFixed('Hello', lengthEncoding: LengthEncoding.u16);
685703
/// ```
686704
@pragma('vm:prefer-inline')
687-
@pragma('vm:prefer-inline')
705+
@pragma('dart2js:tryInline')
688706
void writeStringFixed(
689707
String value, {
690708
LengthEncoding lengthEncoding = .u8,
@@ -728,24 +746,6 @@ extension type BinaryWriter._(_WriterState _ws) {
728746
}
729747
}
730748

731-
/// Writes a boolean value as a single byte.
732-
///
733-
/// `true` is written as `1` and `false` as `0`.
734-
///
735-
/// Example:
736-
/// ```dart
737-
/// writer.writeBool(true); // Writes byte 0x01
738-
/// writer.writeBool(false); // Writes byte 0x00
739-
/// ```
740-
///
741-
@pragma('vm:prefer-inline')
742-
@pragma('dart2js:tryInline')
743-
// Disable lint to allow positional boolean parameter for simplicity
744-
// ignore: avoid_positional_boolean_parameters
745-
void writeBool(bool value) {
746-
writeUint8(value ? 1 : 0);
747-
}
748-
749749
/// Writes a sequence of bytes.
750750
///
751751
/// This is a concise alias for [writeBytes].
@@ -760,35 +760,51 @@ extension type BinaryWriter._(_WriterState _ws) {
760760

761761
/// Extracts all written bytes and resets the writer.
762762
///
763-
/// After calling this method, the writer is reset and ready for reuse.
764-
/// This is more efficient than creating a new writer for each operation.
765-
///
766-
/// Returns a view of the written bytes (no copying occurs).
763+
/// [copy] determines how the bytes are extracted:
764+
/// - If `true`: The written bytes are copied into a new [Uint8List]. The
765+
/// internal buffer is retained and its offset is reset to 0. This is
766+
/// highly efficient for pooling (e.g., [BinaryWriterPool]) as the same
767+
/// large buffer is reused for subsequent operations without re-allocation.
768+
/// - If `false` (default): A view of the internal buffer is returned, and
769+
/// the writer detaches from it by allocating a fresh initial-sized buffer.
770+
/// While the returned bytes are "zero-copy" relative to the old buffer,
771+
/// this forces the writer to re-allocate memory, which is less efficient
772+
/// for pooling long-term.
767773
///
768-
/// **Use case:** When you're done with this batch and want to start fresh.
774+
/// After calling this method, the writer is reset and ready for reuse.
769775
///
770776
/// Example:
771777
/// ```dart
772778
/// final writer = BinaryWriter();
773779
/// writer.writeUint32(42);
774-
/// final packet1 = writer.takeBytes(); // Get bytes and reset
775-
/// writer.writeUint32(100); // Writer is ready for reuse
776-
/// final packet2 = writer.takeBytes();
780+
/// // For best pooling performance (retains internal buffer):
781+
/// final packet = writer.takeBytes(copy: true);
777782
/// ```
778783
@pragma('vm:prefer-inline')
779784
@pragma('dart2js:tryInline')
780-
Uint8List takeBytes() {
785+
Uint8List takeBytes({bool copy = false}) {
786+
if (copy) {
787+
final result = _ws.list.sublist(0, _ws.offset);
788+
_ws.offset = 0;
789+
790+
return result;
791+
}
792+
781793
final result = Uint8List.sublistView(_ws.list, 0, _ws.offset);
782794
_ws._initializeBuffer();
783795

784796
return result;
785797
}
786798

787-
/// Returns a view of the written bytes without resetting the writer.
799+
/// Returns a view of the written bytes (from index 0 up to the current
800+
/// [bytesWritten]) without resetting the writer.
788801
///
789802
/// Unlike [takeBytes], this does not reset the writer's state.
790803
/// Subsequent writes will continue appending to the buffer.
791804
///
805+
/// **Note:** Since this returns a view, the content of the returned list
806+
/// will change if you continue writing to this writer.
807+
///
792808
/// **Use case:** When you need to inspect or copy data mid-stream.
793809
///
794810
/// Example:
@@ -827,33 +843,60 @@ extension type BinaryWriter._(_WriterState _ws) {
827843
_ws.offset = position;
828844
}
829845

846+
/// Returns the byte at the specified [index] without changing the current
847+
/// write position.
848+
///
849+
/// Throws [RangeError] if [index] is negative or greater than or equal to
850+
/// [bytesWritten].
851+
@pragma('vm:prefer-inline')
852+
@pragma('dart2js:tryInline')
853+
int operator [](int index) {
854+
if (index < 0 || index >= _ws.offset) {
855+
throw RangeError.range(index, 0, _ws.offset - 1, 'index');
856+
}
857+
return _ws.list[index];
858+
}
859+
860+
/// Writes a byte at the specified [index] without changing the current
861+
/// write position.
862+
///
863+
/// This operator is used to overwrite already written bytes. To append data,
864+
/// use the standard `write*` methods.
865+
///
866+
/// Throws [RangeError] if [index] is negative or greater than or equal to
867+
/// [bytesWritten].
868+
@pragma('vm:prefer-inline')
869+
@pragma('dart2js:tryInline')
870+
void operator []=(int index, int value) {
871+
if (index < 0 || index >= _ws.offset) {
872+
throw RangeError.range(index, 0, _ws.offset - 1, 'index');
873+
}
874+
875+
_checkRange(value, 0, 255, 'Uint8');
876+
_ws.list[index] = value;
877+
}
878+
830879
/// Writes a byte at the specified [position] without changing the current
831880
/// write position.
832881
///
833-
/// This is useful for overwriting data at a known offset (e.g., updating a
834-
/// length field after writing the payload).
882+
/// Used to overwrite data at a previously written offset (e.g.,
883+
/// updating a length field).
835884
///
836-
/// Throws [RangeError] if [position] is negative or exceeds [bytesWritten].
885+
/// This is a functional alias for `operator []=`.
886+
///
887+
/// Throws [RangeError] if [position] is negative or greater than or equal to
888+
/// [bytesWritten].
837889
///
838890
/// Example:
839891
/// ```dart
840892
/// writer.writeUint32(10); // Write length placeholder
841893
/// writer.writeString('data');
842894
/// writer.writeUint8At(0, 15); // Overwrite length at position 0
895+
/// // or: writer[0] = 15;
843896
/// ```
844897
@pragma('vm:prefer-inline')
845898
@pragma('dart2js:tryInline')
846-
void writeUint8At(int position, int value) {
847-
if (position < 0 || position > _ws.offset) {
848-
throw RangeError.range(position, 0, _ws.offset, 'position');
849-
}
850-
851-
_checkRange(value, 0, 255, 'Uint8');
852-
_ws.list[position] = value;
853-
if (position == _ws.offset) {
854-
_ws.offset = position + 1;
855-
}
856-
}
899+
void writeUint8At(int position, int value) => this[position] = value;
857900

858901
/// Resets the writer to its initial state, discarding all written data.
859902
@pragma('vm:prefer-inline')

0 commit comments

Comments
 (0)