Skip to content

Commit 28e43b8

Browse files
authored
Merge pull request #276 from objectbox/fb-string-ascii
flatbuffers - optimization for ASCII strings
2 parents aa52476 + df33a2a commit 28e43b8

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

objectbox/lib/flatbuffers/flat_buffers.dart

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -703,18 +703,48 @@ class Builder {
703703
}
704704

705705
int _writeString(String value) {
706-
// TODO(scheglov) optimize for ASCII strings
707-
List<int> bytes = utf8.encode(value);
708-
int length = bytes.length;
706+
// [utf8.encode()] is slow (up to at least Dart SDK 2.13). If the given
707+
// string is ASCII we can just write it directly, without any conversion.
708+
final originalTail = _tail;
709+
if (!_tryWriteASCIIString(value)) {
710+
// reset the output buffer position for [_writeUTFString()]
711+
_tail = originalTail;
712+
_writeUTFString(value);
713+
}
714+
return _tail;
715+
}
716+
717+
// Try to write the string as ASCII, return false if there's a non-ascii char.
718+
@pragma('vm:prefer-inline')
719+
bool _tryWriteASCIIString(String value) {
720+
_prepare(4, 1, additionalBytes: value.length + 1);
721+
final length = value.length;
722+
var offset = _buf.lengthInBytes - _tail + 4;
723+
for (var i = 0; i < length; i++) {
724+
// utf16 code unit, e.g. for '†' it's [0x20 0x20], which is 8224 decimal.
725+
// ASCII characters go from 0x00 to 0x7F (which is 0 to 127 decimal).
726+
final char = value.codeUnitAt(i);
727+
if (char >= 128) {
728+
return false;
729+
}
730+
_buf.setUint8(offset++, char);
731+
}
732+
_buf.setUint8(offset, 0); // trailing zero
733+
_setUint32AtTail(_buf, _tail, value.length);
734+
return true;
735+
}
736+
737+
@pragma('vm:prefer-inline')
738+
void _writeUTFString(String value) {
739+
final bytes = utf8.encode(value) as Uint8List;
740+
final length = bytes.length;
709741
_prepare(4, 1, additionalBytes: length + 1);
710-
final int result = _tail;
711742
_setUint32AtTail(_buf, _tail, length);
712-
int offset = _buf.lengthInBytes - _tail + 4;
743+
var offset = _buf.lengthInBytes - _tail + 4;
713744
for (int i = 0; i < length; i++) {
714745
_buf.setUint8(offset++, bytes[i]);
715746
}
716747
_buf.setUint8(offset, 0); // trailing zero
717-
return result;
718748
}
719749

720750
/// Throw an exception if there is not currently a vtable.

objectbox/test/flatbuffers_test.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ void main() {
8383
as EntityDefinition<TestEntityNonRel>;
8484

8585
final source = TestEntityNonRel.filled();
86+
// Test the "dagger" char (0x20 0x20) which may cause problems if
87+
// utf16/ascii isn't recognized properly.
88+
source.tString = source.tString! + '†asdf';
8689

8790
final fb1 = BuilderWithCBuffer();
8891
binding.objectToFB(source, fb1.fbb);

0 commit comments

Comments
 (0)