buffer-builder 0.2.4.6 → 0.2.4.7
raw patch · 6 files changed
+770/−767 lines, 6 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Data.BufferBuilder.Json: instance Data.Semigroup.Semigroup Data.BufferBuilder.Json.ObjectBuilder
+ Data.BufferBuilder.Json: instance GHC.Base.Semigroup Data.BufferBuilder.Json.ObjectBuilder
Files
- buffer-builder.cabal +3/−4
- cbits/branchlut.c +271/−0
- cbits/branchlut.cpp +0/−271
- cbits/buffer.c +492/−0
- cbits/buffer.cpp +0/−492
- changelog.md +4/−0
buffer-builder.cabal view
@@ -1,5 +1,5 @@ name: buffer-builder-version: 0.2.4.6+version: 0.2.4.7 synopsis: Library for efficiently building up buffers, one piece at a time description: @@ -70,10 +70,9 @@ --ghc-options: -ddump-ds -ddump-simpl -ddump-stg -ddump-opt-cmm -ddump-asm -ddump-to-file hs-source-dirs: src- c-sources: cbits/buffer.cpp cbits/branchlut.cpp+ c-sources: cbits/buffer.c cbits/branchlut.c install-includes: cbits/branchlut.h- cc-options: -O2 -Wall- extra-libraries: stdc+++ cc-options: -O2 -Wall -Werror -std=c99 test-suite tests type: exitcode-stdio-1.0
+ cbits/branchlut.c view
@@ -0,0 +1,271 @@+/** <https://github.com/miloyip/itoa-benchmark/blob/940542a7770155ee3e9f2777ebc178dc899b43e0/src/branchlut.cpp>+ */++#include <string.h>+#include <stdint.h>++static const char gDigitsLut[200] = {+ '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',+ '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',+ '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',+ '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',+ '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',+ '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',+ '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',+ '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',+ '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',+ '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'+};++// Branching for different cases (forward)+// Use lookup table of two digits++size_t u32toa_branchlut(uint32_t value, char* buffer) {+ char* start = buffer;++ if (value < 10000) {+ const uint32_t d1 = (value / 100) << 1;+ const uint32_t d2 = (value % 100) << 1;++ if (value >= 1000)+ *buffer++ = gDigitsLut[d1];+ if (value >= 100)+ *buffer++ = gDigitsLut[d1 + 1];+ if (value >= 10)+ *buffer++ = gDigitsLut[d2];+ *buffer++ = gDigitsLut[d2 + 1];+ }+ else if (value < 100000000) {+ // value = bbbbcccc+ const uint32_t b = value / 10000;+ const uint32_t c = value % 10000;++ const uint32_t d1 = (b / 100) << 1;+ const uint32_t d2 = (b % 100) << 1;++ const uint32_t d3 = (c / 100) << 1;+ const uint32_t d4 = (c % 100) << 1;++ if (value >= 10000000)+ *buffer++ = gDigitsLut[d1];+ if (value >= 1000000)+ *buffer++ = gDigitsLut[d1 + 1];+ if (value >= 100000)+ *buffer++ = gDigitsLut[d2];+ *buffer++ = gDigitsLut[d2 + 1];++ *buffer++ = gDigitsLut[d3];+ *buffer++ = gDigitsLut[d3 + 1];+ *buffer++ = gDigitsLut[d4];+ *buffer++ = gDigitsLut[d4 + 1];+ }+ else {+ // value = aabbbbcccc in decimal++ const uint32_t a = value / 100000000; // 1 to 42+ value %= 100000000;++ if (a >= 10) {+ const unsigned i = a << 1;+ *buffer++ = gDigitsLut[i];+ *buffer++ = gDigitsLut[i + 1];+ }+ else+ *buffer++ = '0' + a;++ const uint32_t b = value / 10000; // 0 to 9999+ const uint32_t c = value % 10000; // 0 to 9999++ const uint32_t d1 = (b / 100) << 1;+ const uint32_t d2 = (b % 100) << 1;++ const uint32_t d3 = (c / 100) << 1;+ const uint32_t d4 = (c % 100) << 1;++ *buffer++ = gDigitsLut[d1];+ *buffer++ = gDigitsLut[d1 + 1];+ *buffer++ = gDigitsLut[d2];+ *buffer++ = gDigitsLut[d2 + 1];+ *buffer++ = gDigitsLut[d3];+ *buffer++ = gDigitsLut[d3 + 1];+ *buffer++ = gDigitsLut[d4];+ *buffer++ = gDigitsLut[d4 + 1];+ }+ return buffer - start;+}++size_t i32toa_branchlut(int32_t value, char* buffer) {+ if (value < 0) {+ *buffer++ = '-';+ return 1 + u32toa_branchlut(~(uint32_t)(value) + 1u, buffer);+ } else {+ return u32toa_branchlut((uint32_t)(value), buffer);+ }+}++size_t u64toa_branchlut(uint64_t value, char* buffer) {+ char* start = buffer;+ if (value < 100000000) {+ uint32_t v = (uint32_t)value;+ if (v < 10000) {+ const uint32_t d1 = (v / 100) << 1;+ const uint32_t d2 = (v % 100) << 1;++ if (v >= 1000)+ *buffer++ = gDigitsLut[d1];+ if (v >= 100)+ *buffer++ = gDigitsLut[d1 + 1];+ if (v >= 10)+ *buffer++ = gDigitsLut[d2];+ *buffer++ = gDigitsLut[d2 + 1];+ }+ else {+ // value = bbbbcccc+ const uint32_t b = v / 10000;+ const uint32_t c = v % 10000;++ const uint32_t d1 = (b / 100) << 1;+ const uint32_t d2 = (b % 100) << 1;++ const uint32_t d3 = (c / 100) << 1;+ const uint32_t d4 = (c % 100) << 1;++ if (value >= 10000000)+ *buffer++ = gDigitsLut[d1];+ if (value >= 1000000)+ *buffer++ = gDigitsLut[d1 + 1];+ if (value >= 100000)+ *buffer++ = gDigitsLut[d2];+ *buffer++ = gDigitsLut[d2 + 1];++ *buffer++ = gDigitsLut[d3];+ *buffer++ = gDigitsLut[d3 + 1];+ *buffer++ = gDigitsLut[d4];+ *buffer++ = gDigitsLut[d4 + 1];+ }+ }+ else if (value < 10000000000000000) {+ const uint32_t v0 = (uint32_t)(value / 100000000);+ const uint32_t v1 = (uint32_t)(value % 100000000);++ const uint32_t b0 = v0 / 10000;+ const uint32_t c0 = v0 % 10000;++ const uint32_t d1 = (b0 / 100) << 1;+ const uint32_t d2 = (b0 % 100) << 1;++ const uint32_t d3 = (c0 / 100) << 1;+ const uint32_t d4 = (c0 % 100) << 1;++ const uint32_t b1 = v1 / 10000;+ const uint32_t c1 = v1 % 10000;++ const uint32_t d5 = (b1 / 100) << 1;+ const uint32_t d6 = (b1 % 100) << 1;++ const uint32_t d7 = (c1 / 100) << 1;+ const uint32_t d8 = (c1 % 100) << 1;++ if (value >= 1000000000000000)+ *buffer++ = gDigitsLut[d1];+ if (value >= 100000000000000)+ *buffer++ = gDigitsLut[d1 + 1];+ if (value >= 10000000000000)+ *buffer++ = gDigitsLut[d2];+ if (value >= 1000000000000)+ *buffer++ = gDigitsLut[d2 + 1];+ if (value >= 100000000000)+ *buffer++ = gDigitsLut[d3];+ if (value >= 10000000000)+ *buffer++ = gDigitsLut[d3 + 1];+ if (value >= 1000000000)+ *buffer++ = gDigitsLut[d4];+ if (value >= 100000000)+ *buffer++ = gDigitsLut[d4 + 1];++ *buffer++ = gDigitsLut[d5];+ *buffer++ = gDigitsLut[d5 + 1];+ *buffer++ = gDigitsLut[d6];+ *buffer++ = gDigitsLut[d6 + 1];+ *buffer++ = gDigitsLut[d7];+ *buffer++ = gDigitsLut[d7 + 1];+ *buffer++ = gDigitsLut[d8];+ *buffer++ = gDigitsLut[d8 + 1];+ }+ else {+ const uint32_t a = (uint32_t)(value / 10000000000000000); // 1 to 1844+ value %= 10000000000000000;++ if (a < 10)+ *buffer++ = '0' + a;+ else if (a < 100) {+ const uint32_t i = a << 1;+ *buffer++ = gDigitsLut[i];+ *buffer++ = gDigitsLut[i + 1];+ }+ else if (a < 1000) {+ *buffer++ = '0' + a / 100;++ const uint32_t i = (a % 100) << 1;+ *buffer++ = gDigitsLut[i];+ *buffer++ = gDigitsLut[i + 1];+ }+ else {+ const uint32_t i = (a / 100) << 1;+ const uint32_t j = (a % 100) << 1;+ *buffer++ = gDigitsLut[i];+ *buffer++ = gDigitsLut[i + 1];+ *buffer++ = gDigitsLut[j];+ *buffer++ = gDigitsLut[j + 1];+ }++ const uint32_t v0 = (uint32_t)(value / 100000000);+ const uint32_t v1 = (uint32_t)(value % 100000000);++ const uint32_t b0 = v0 / 10000;+ const uint32_t c0 = v0 % 10000;++ const uint32_t d1 = (b0 / 100) << 1;+ const uint32_t d2 = (b0 % 100) << 1;++ const uint32_t d3 = (c0 / 100) << 1;+ const uint32_t d4 = (c0 % 100) << 1;++ const uint32_t b1 = v1 / 10000;+ const uint32_t c1 = v1 % 10000;++ const uint32_t d5 = (b1 / 100) << 1;+ const uint32_t d6 = (b1 % 100) << 1;++ const uint32_t d7 = (c1 / 100) << 1;+ const uint32_t d8 = (c1 % 100) << 1;++ *buffer++ = gDigitsLut[d1];+ *buffer++ = gDigitsLut[d1 + 1];+ *buffer++ = gDigitsLut[d2];+ *buffer++ = gDigitsLut[d2 + 1];+ *buffer++ = gDigitsLut[d3];+ *buffer++ = gDigitsLut[d3 + 1];+ *buffer++ = gDigitsLut[d4];+ *buffer++ = gDigitsLut[d4 + 1];+ *buffer++ = gDigitsLut[d5];+ *buffer++ = gDigitsLut[d5 + 1];+ *buffer++ = gDigitsLut[d6];+ *buffer++ = gDigitsLut[d6 + 1];+ *buffer++ = gDigitsLut[d7];+ *buffer++ = gDigitsLut[d7 + 1];+ *buffer++ = gDigitsLut[d8];+ *buffer++ = gDigitsLut[d8 + 1];+ }++ return buffer - start;+}++size_t i64toa_branchlut(int64_t value, char* buffer) {+ if (value < 0) {+ *buffer++ = '-';+ return 1 + u64toa_branchlut(~(uint64_t)(value) + 1u, buffer);+ } else {+ return u64toa_branchlut((uint64_t)(value), buffer);+ }+}
− cbits/branchlut.cpp
@@ -1,271 +0,0 @@-/** <https://github.com/miloyip/itoa-benchmark/blob/940542a7770155ee3e9f2777ebc178dc899b43e0/src/branchlut.cpp>- */--#include <string.h>-#include <stdint.h>--static const char gDigitsLut[200] = {- '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',- '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',- '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',- '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',- '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',- '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',- '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',- '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',- '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',- '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'-};--// Branching for different cases (forward)-// Use lookup table of two digits--size_t u32toa_branchlut(uint32_t value, char* buffer) {- char* start = buffer;-- if (value < 10000) {- const uint32_t d1 = (value / 100) << 1;- const uint32_t d2 = (value % 100) << 1;- - if (value >= 1000)- *buffer++ = gDigitsLut[d1];- if (value >= 100)- *buffer++ = gDigitsLut[d1 + 1];- if (value >= 10)- *buffer++ = gDigitsLut[d2];- *buffer++ = gDigitsLut[d2 + 1];- }- else if (value < 100000000) {- // value = bbbbcccc- const uint32_t b = value / 10000;- const uint32_t c = value % 10000;- - const uint32_t d1 = (b / 100) << 1;- const uint32_t d2 = (b % 100) << 1;- - const uint32_t d3 = (c / 100) << 1;- const uint32_t d4 = (c % 100) << 1;- - if (value >= 10000000)- *buffer++ = gDigitsLut[d1];- if (value >= 1000000)- *buffer++ = gDigitsLut[d1 + 1];- if (value >= 100000)- *buffer++ = gDigitsLut[d2];- *buffer++ = gDigitsLut[d2 + 1];- - *buffer++ = gDigitsLut[d3];- *buffer++ = gDigitsLut[d3 + 1];- *buffer++ = gDigitsLut[d4];- *buffer++ = gDigitsLut[d4 + 1];- }- else {- // value = aabbbbcccc in decimal- - const uint32_t a = value / 100000000; // 1 to 42- value %= 100000000;- - if (a >= 10) {- const unsigned i = a << 1;- *buffer++ = gDigitsLut[i];- *buffer++ = gDigitsLut[i + 1];- }- else- *buffer++ = '0' + static_cast<char>(a);-- const uint32_t b = value / 10000; // 0 to 9999- const uint32_t c = value % 10000; // 0 to 9999- - const uint32_t d1 = (b / 100) << 1;- const uint32_t d2 = (b % 100) << 1;- - const uint32_t d3 = (c / 100) << 1;- const uint32_t d4 = (c % 100) << 1;- - *buffer++ = gDigitsLut[d1];- *buffer++ = gDigitsLut[d1 + 1];- *buffer++ = gDigitsLut[d2];- *buffer++ = gDigitsLut[d2 + 1];- *buffer++ = gDigitsLut[d3];- *buffer++ = gDigitsLut[d3 + 1];- *buffer++ = gDigitsLut[d4];- *buffer++ = gDigitsLut[d4 + 1];- }- return buffer - start;-}--size_t i32toa_branchlut(int32_t value, char* buffer) {- if (value < 0) {- *buffer++ = '-';- return 1 + u32toa_branchlut(~static_cast<uint32_t>(value) + 1u, buffer);- } else {- return u32toa_branchlut(static_cast<uint32_t>(value), buffer);- }-}--size_t u64toa_branchlut(uint64_t value, char* buffer) {- char* start = buffer;- if (value < 100000000) {- uint32_t v = static_cast<uint32_t>(value);- if (v < 10000) {- const uint32_t d1 = (v / 100) << 1;- const uint32_t d2 = (v % 100) << 1;- - if (v >= 1000)- *buffer++ = gDigitsLut[d1];- if (v >= 100)- *buffer++ = gDigitsLut[d1 + 1];- if (v >= 10)- *buffer++ = gDigitsLut[d2];- *buffer++ = gDigitsLut[d2 + 1];- }- else {- // value = bbbbcccc- const uint32_t b = v / 10000;- const uint32_t c = v % 10000;- - const uint32_t d1 = (b / 100) << 1;- const uint32_t d2 = (b % 100) << 1;- - const uint32_t d3 = (c / 100) << 1;- const uint32_t d4 = (c % 100) << 1;- - if (value >= 10000000)- *buffer++ = gDigitsLut[d1];- if (value >= 1000000)- *buffer++ = gDigitsLut[d1 + 1];- if (value >= 100000)- *buffer++ = gDigitsLut[d2];- *buffer++ = gDigitsLut[d2 + 1];- - *buffer++ = gDigitsLut[d3];- *buffer++ = gDigitsLut[d3 + 1];- *buffer++ = gDigitsLut[d4];- *buffer++ = gDigitsLut[d4 + 1];- }- }- else if (value < 10000000000000000) {- const uint32_t v0 = static_cast<uint32_t>(value / 100000000);- const uint32_t v1 = static_cast<uint32_t>(value % 100000000);- - const uint32_t b0 = v0 / 10000;- const uint32_t c0 = v0 % 10000;- - const uint32_t d1 = (b0 / 100) << 1;- const uint32_t d2 = (b0 % 100) << 1;- - const uint32_t d3 = (c0 / 100) << 1;- const uint32_t d4 = (c0 % 100) << 1;-- const uint32_t b1 = v1 / 10000;- const uint32_t c1 = v1 % 10000;- - const uint32_t d5 = (b1 / 100) << 1;- const uint32_t d6 = (b1 % 100) << 1;- - const uint32_t d7 = (c1 / 100) << 1;- const uint32_t d8 = (c1 % 100) << 1;-- if (value >= 1000000000000000)- *buffer++ = gDigitsLut[d1];- if (value >= 100000000000000)- *buffer++ = gDigitsLut[d1 + 1];- if (value >= 10000000000000)- *buffer++ = gDigitsLut[d2];- if (value >= 1000000000000)- *buffer++ = gDigitsLut[d2 + 1];- if (value >= 100000000000)- *buffer++ = gDigitsLut[d3];- if (value >= 10000000000)- *buffer++ = gDigitsLut[d3 + 1];- if (value >= 1000000000)- *buffer++ = gDigitsLut[d4];- if (value >= 100000000)- *buffer++ = gDigitsLut[d4 + 1];- - *buffer++ = gDigitsLut[d5];- *buffer++ = gDigitsLut[d5 + 1];- *buffer++ = gDigitsLut[d6];- *buffer++ = gDigitsLut[d6 + 1];- *buffer++ = gDigitsLut[d7];- *buffer++ = gDigitsLut[d7 + 1];- *buffer++ = gDigitsLut[d8];- *buffer++ = gDigitsLut[d8 + 1];- }- else {- const uint32_t a = static_cast<uint32_t>(value / 10000000000000000); // 1 to 1844- value %= 10000000000000000;- - if (a < 10)- *buffer++ = '0' + static_cast<char>(a);- else if (a < 100) {- const uint32_t i = a << 1;- *buffer++ = gDigitsLut[i];- *buffer++ = gDigitsLut[i + 1];- }- else if (a < 1000) {- *buffer++ = '0' + static_cast<char>(a / 100);- - const uint32_t i = (a % 100) << 1;- *buffer++ = gDigitsLut[i];- *buffer++ = gDigitsLut[i + 1];- }- else {- const uint32_t i = (a / 100) << 1;- const uint32_t j = (a % 100) << 1;- *buffer++ = gDigitsLut[i];- *buffer++ = gDigitsLut[i + 1];- *buffer++ = gDigitsLut[j];- *buffer++ = gDigitsLut[j + 1];- }- - const uint32_t v0 = static_cast<uint32_t>(value / 100000000);- const uint32_t v1 = static_cast<uint32_t>(value % 100000000);- - const uint32_t b0 = v0 / 10000;- const uint32_t c0 = v0 % 10000;- - const uint32_t d1 = (b0 / 100) << 1;- const uint32_t d2 = (b0 % 100) << 1;- - const uint32_t d3 = (c0 / 100) << 1;- const uint32_t d4 = (c0 % 100) << 1;- - const uint32_t b1 = v1 / 10000;- const uint32_t c1 = v1 % 10000;- - const uint32_t d5 = (b1 / 100) << 1;- const uint32_t d6 = (b1 % 100) << 1;- - const uint32_t d7 = (c1 / 100) << 1;- const uint32_t d8 = (c1 % 100) << 1;- - *buffer++ = gDigitsLut[d1];- *buffer++ = gDigitsLut[d1 + 1];- *buffer++ = gDigitsLut[d2];- *buffer++ = gDigitsLut[d2 + 1];- *buffer++ = gDigitsLut[d3];- *buffer++ = gDigitsLut[d3 + 1];- *buffer++ = gDigitsLut[d4];- *buffer++ = gDigitsLut[d4 + 1];- *buffer++ = gDigitsLut[d5];- *buffer++ = gDigitsLut[d5 + 1];- *buffer++ = gDigitsLut[d6];- *buffer++ = gDigitsLut[d6 + 1];- *buffer++ = gDigitsLut[d7];- *buffer++ = gDigitsLut[d7 + 1];- *buffer++ = gDigitsLut[d8];- *buffer++ = gDigitsLut[d8 + 1];- }- - return buffer - start;-}--size_t i64toa_branchlut(int64_t value, char* buffer) {- if (value < 0) {- *buffer++ = '-';- return 1 + u64toa_branchlut(~static_cast<uint64_t>(value) + 1u, buffer);- } else {- return u64toa_branchlut(static_cast<uint64_t>(value), buffer);- }-}
+ cbits/buffer.c view
@@ -0,0 +1,492 @@+#include <stdbool.h>+#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include <stdint.h>+#include <assert.h>++#include "branchlut.h"++/*+ * Append utf8, ASCII7, raw bytes, utf16+ * JSON encode utf8, ascii7, utf16+ */++#if defined(__clang__) || defined(__GNUC__)+ #define BW_NOINLINE __attribute__((noinline))+#else+ #define BW_NOINLINE+#endif++#if defined(__clang__) || defined(__GNUC__)+ #define BW_LIKELY(x) __builtin_expect(!!(x), 1)+ #define BW_UNLIKELY(x) __builtin_expect(!!(x), 0)+#else+ #define BW_LIKELY(x) x+ #define BW_UNLIKELY(x) x+#endif++#define BW_ENSURE_CAPACITY(bw, cap, count_size) \+ do { \+ if (!ensureCapacity((bw), (cap))) { \+ if (bw->counting_size) { \+ bw->counted_size += count_size; \+ } \+ return; \+ } \+ } while (0)+++static const unsigned char DEC2HEX[16] = {+ '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'+};++typedef struct BufferWriter {+ unsigned char* end; // the most commonly-accessed field+ unsigned char* capacity;+ unsigned char* data;++ bool counting_size;+ size_t counted_size;++ // invariants:+ // if (counting_size), end, capacity, and data are null+ // else, counted_size is zero and:+ // if (end <= capacity), then data is non-null and end >= data+ // if (capacity == 0), then data and end are null, and object is dead++ // Note: We mark the object dead upon growth failure in order+ // to avoid the need to check for errors after every single+ // append function. The error can be raised upon the final+ // pointer release.+} BufferWriter;++BW_NOINLINE bool actuallyGrow(BufferWriter* bw, size_t amount) {+ if (bw->capacity == 0) {+ // object is dead, ignore append request+ return false;+ }++ size_t size = bw->end - bw->data;+ size_t newCapacity = bw->capacity - bw->data;+ do {+ // TODO: detect overflow?+ newCapacity *= 2;+ } while (newCapacity < size + amount);++ unsigned char* newData = realloc(bw->data, newCapacity);+ if (newData) {+ bw->data = newData;+ bw->end = newData + size;+ bw->capacity = newData + newCapacity;+ return true;+ } else {+ // TODO: try smaller growth?+ free(bw->data);+ bw->data = 0;+ bw->end = 0;+ bw->capacity = 0;+ return false;+ }+}++static inline bool ensureCapacity(BufferWriter* bw, size_t amount) {+ if (BW_LIKELY(bw->end + amount <= bw->capacity)) {+ return true;+ } else {+ return actuallyGrow(bw, amount);+ }+}++BufferWriter* bw_new(size_t initialCapacity) {+ if (!initialCapacity) {+ initialCapacity = 1;+ }++ BufferWriter* bw = malloc(sizeof(BufferWriter));+ if (!bw) {+ return 0;+ }++ bw->data = malloc(initialCapacity);+ if (!bw->data) {+ free(bw);+ return 0;+ }++ bw->end = bw->data;+ bw->capacity = bw->data + initialCapacity;+ bw->counting_size = false;+ bw->counted_size = 0;+ return bw;+}++BufferWriter* bw_new_length_calculator() {+ BufferWriter* bw = malloc(sizeof(BufferWriter));+ if (!bw) {+ return 0;+ }++ bw->data = 0;+ bw->end = 0;+ bw->capacity = 0;+ bw->counting_size = true;+ bw->counted_size = 0;+ return bw;+}++void bw_free(BufferWriter* bw) {+ free(bw->data);+ free(bw);+}++void bw_trim(BufferWriter* bw) {+ if (bw->data == 0) {+ return;+ }++ if (bw->end < bw->capacity) {+ // try to shrink+ size_t size = bw->end - bw->data;+ unsigned char* data = realloc(bw->data, size);+ if (data) {+ bw->data = data;+ bw->end = data + size;+ bw->capacity = data + size;+ } else {+ // no problem+ }+ }++}++size_t bw_get_size(BufferWriter* bw) {+ if (bw->counting_size) {+ return bw->counted_size;+ } else {+ return bw->end - bw->data;+ }+}++unsigned char* bw_release_address(BufferWriter* bw) {+ unsigned char* data = bw->data;++ bw->end = 0;+ bw->capacity = 0;+ bw->data = 0;+ bw->counting_size = false;+ bw->counted_size = 0;+ return data; // null if dead+}++void bw_append_byte(BufferWriter* bw, unsigned char byte) {+ BW_ENSURE_CAPACITY(bw, 1, 1);++ bw->end[0] = byte;+ bw->end += 1;+}++static inline size_t utf8_char_length(uint32_t c) {+ if (c <= 0x7F) {+ return 1;+ } else if (c <= 0x7FF) {+ return 2;+ } else if (c <= 0xFFFF) {+ return 3;+ } else if (c <= 0x1FFFFF) {+ return 4;+ } else {+ // Unicode characters out of this range are illegal...+ return 0;+ }+}++void bw_append_char_utf8(BufferWriter* bw, uint32_t c) {+ BW_ENSURE_CAPACITY(bw, 4, utf8_char_length(c));++ unsigned char* data = bw->end;++ if (c <= 0x7F) {+ data[0] = c;+ data += 1;+ } else if (c <= 0x7FF) {+ data[0] = 0xC0 | (c >> 6);+ data[1] = 0x80 | (c & 0x3F);+ data += 2;+ } else if (c <= 0xFFFF) {+ data[0] = 0xE0 | (c >> 12);+ data[1] = 0x80 | ((c >> 6) & 0x3F);+ data[2] = 0x80 | (c & 0x3F);+ data += 3;+ } else if (c <= 0x1FFFFF) {+ data[0] = 0xF0 | (c >> 18);+ data[1] = 0x80 | ((c >> 12) & 0x3F);+ data[2] = 0x80 | ((c >> 6) & 0x3F);+ data[3] = 0x80 | (c & 0x3F);+ data += 4;+ } else {+ // Unicode characters out of this range are illegal...+ // should we assert? or just ignore...+ }+ bw->end = data;+}++void bw_append_bs(BufferWriter* bw, size_t size, const unsigned char* data) {+ BW_ENSURE_CAPACITY(bw, size, size);++ memcpy(bw->end, data, size);+ bw->end += size;+}++void bw_append_bsz(BufferWriter* bw, const unsigned char* data) {+ bw_append_bs(bw, strlen((char*)data), data);+}++void bw_append_byte7(BufferWriter* bw, unsigned char byte) {+ BW_ENSURE_CAPACITY(bw, 1, 1);++ bw->end[0] = byte & 0x7F;+ bw->end += 1;+}++void bw_append_bs7(BufferWriter* bw, size_t size, const unsigned char* data) {+ BW_ENSURE_CAPACITY(bw, size, size);++ unsigned char* out = bw->end;+ for (size_t i = 0; i < size; ++i) {+ out[i] = data[i] & 0x7F;+ }+ bw->end += size;+}++void bw_append_bsz7(BufferWriter* bw, const unsigned char* data) {+ bw_append_bs7(bw, strlen((char*)data), data);+}++static inline size_t count_escaped_json_length(size_t size, const unsigned char* data) {+ size_t rv = 2;+ for (size_t i = 0; i < size; ++i) {+ switch (data[i]) {+ case '\n': rv += 2; break;+ case '\r': rv += 2; break;+ case '\t': rv += 2; break;+ case '\\': rv += 2; break;+ case '\"': rv += 2; break;+ default:+ if (data[i] <= 0x1F) {+ rv += 6;+ } else {+ rv += 1;+ }+ break;+ }+ }+ return rv;+}++void bw_append_json_escaped(BufferWriter* bw, size_t size, const unsigned char* data) {+ BW_ENSURE_CAPACITY(bw, 2 + size * 6, count_escaped_json_length(size, data));++ unsigned char* dest = bw->end;+ *dest++ = '\"';++ size_t i = 0;+ while (i < size) {+ switch (data[i]) {+ case '\n': *dest++ = '\\'; *dest++ = 'n'; break;+ case '\r': *dest++ = '\\'; *dest++ = 'r'; break;+ case '\t': *dest++ = '\\'; *dest++ = 't'; break;+ case '\\': *dest++ = '\\'; *dest++ = '\\'; break;+ case '\"': *dest++ = '\\'; *dest++ = '\"'; break;+ default: {+ unsigned char d = data[i];+ if (d <= 0x1F) {+ *dest++ = '\\';+ *dest++ = 'u';+ *dest++ = '0';+ *dest++ = '0';+ *dest++ = DEC2HEX[d >> 4];+ *dest++ = DEC2HEX[d & 0xF];+ } else {+ *dest++ = d;+ }+ break;+ }+ }+ ++i;+ }++ *dest++ = '\"';+ bw->end = dest;+}++static inline size_t count_decimal_signed_int_length(int64_t i) {+ char buf[32]; // enough+ return i64toa_branchlut(i, buf);+}++void bw_append_decimal_signed_int(BufferWriter* bw, int64_t i) {+ BW_ENSURE_CAPACITY(bw, 32, count_decimal_signed_int_length(i)); // enough++ unsigned used = i64toa_branchlut(i, (char*)bw->end);+ bw->end += used;+}++static inline size_t count_decimal_double_length(double d) {+ char buf[318];+ return sprintf(buf, "%f", d);+}++void bw_append_decimal_double(BufferWriter* bw, double d) {+ BW_ENSURE_CAPACITY(bw, 318, count_decimal_double_length(d)); // sprintf("%f", -DBL_MAX);++ size_t used = sprintf((char*)bw->end, "%f", d);+ bw->end += used;+}++// From <https://github.com/bos/text/blob/f74427c954fb4479f9db5025f27775e29ace125f/cbits/cbits.c#L234>+void bw_encode_utf8(uint8_t **destp, const uint16_t *src, size_t srcoff, size_t srclen) {+ const uint16_t *srcend;+ uint8_t *dest = *destp;++ src += srcoff;+ srcend = src + srclen;++ ascii:+#if defined(__x86_64__)+ while (srcend - src >= 4) {+ uint64_t w = *((uint64_t *) src);++ if (w & 0xFF80FF80FF80FF80ULL) {+ if (!(w & 0x000000000000FF80ULL)) {+ *dest++ = w & 0xFFFF;+ src++;+ if (!(w & 0x00000000FF800000ULL)) {+ *dest++ = (w >> 16) & 0xFFFF;+ src++;+ if (!(w & 0x0000FF8000000000ULL)) {+ *dest++ = (w >> 32) & 0xFFFF;+ src++;+ }+ }+ }+ break;+ }+ *dest++ = w & 0xFFFF;+ *dest++ = (w >> 16) & 0xFFFF;+ *dest++ = (w >> 32) & 0xFFFF;+ *dest++ = w >> 48;+ src += 4;+ }+#endif++#if defined(__i386__)+ while (srcend - src >= 2) {+ uint32_t w = *((uint32_t *) src);++ if (w & 0xFF80FF80)+ break;+ *dest++ = w & 0xFFFF;+ *dest++ = w >> 16;+ src += 2;+ }+#endif++ while (src < srcend) {+ uint16_t w = *src++;++ if (w <= 0x7F) {+ *dest++ = w;+ /* An ASCII byte is likely to begin a run of ASCII bytes.+ Falling back into the fast path really helps performance. */+ goto ascii;+ }+ else if (w <= 0x7FF) {+ *dest++ = (w >> 6) | 0xC0;+ *dest++ = (w & 0x3f) | 0x80;+ }+ else if (w < 0xD800 || w > 0xDBFF) {+ *dest++ = (w >> 12) | 0xE0;+ *dest++ = ((w >> 6) & 0x3F) | 0x80;+ *dest++ = (w & 0x3F) | 0x80;+ } else {+ uint32_t c = ((((uint32_t) w) - 0xD800) << 10) ++ (((uint32_t) *src++) - 0xDC00) + 0x10000;+ *dest++ = (c >> 18) | 0xF0;+ *dest++ = ((c >> 12) & 0x3F) | 0x80;+ *dest++ = ((c >> 6) & 0x3F) | 0x80;+ *dest++ = (c & 0x3F) | 0x80;+ }+ }++ *destp = dest;+}++void bw_append_json_escaped_utf16(BufferWriter* bw, size_t size, unsigned short* words) {+ // TODO: handle malloc failure+ // ideally no temp buffer would be required here.+ unsigned char* utf8 = malloc(size * 4);+ assert(utf8);+ unsigned char* utf8end = utf8;++ bw_encode_utf8(&utf8end, words, 0, size);++ bw_append_json_escaped(bw, utf8end - utf8, utf8);++ free(utf8);+}++static const unsigned char UNRESERVED[256] = {+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,1,1,0,+ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,++ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,+ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1,+ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,+ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,1,0,++ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,++ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0+};++static inline size_t count_url_encoded_length(size_t size, const unsigned char* data) {+ size_t rv = 0;+ for (size_t i = 0; i < size; ++i) {+ if (UNRESERVED[data[i]]) {+ rv += 1;+ } else {+ rv += 3;+ }+ }+ return rv;+}++void bw_append_url_encoded(BufferWriter* bw, size_t size, const unsigned char* data) {+ // worst case+ BW_ENSURE_CAPACITY(bw, size * 3, count_url_encoded_length(size, data));++ const unsigned char* src = data;+ unsigned char* dst = bw->end;+ while (size--) {+ unsigned char c = *src++;+ if (UNRESERVED[c]) {+ *dst++ = c;+ } else {+ dst[0] = '%';+ dst[1] = DEC2HEX[c >> 4];+ dst[2] = DEC2HEX[c & 0xF];+ dst += 3;+ }+ }++ bw->end = dst;+}
− cbits/buffer.cpp
@@ -1,492 +0,0 @@-#include <stdio.h>-#include <stdlib.h>-#include <string.h>-#include <stdint.h>-#include <assert.h>--#include "branchlut.h"--/*- * Append utf8, ASCII7, raw bytes, utf16- * JSON encode utf8, ascii7, utf16- */--#if defined(__clang__) || defined(__GNUC__)- #define BW_NOINLINE __attribute__((noinline))-#else- #define BW_NOINLINE-#endif--#if defined(__clang__) || defined(__GNUC__)- #define BW_LIKELY(x) __builtin_expect(!!(x), 1)- #define BW_UNLIKELY(x) __builtin_expect(!!(x), 0)-#else- #define BW_LIKELY(x) x- #define BW_UNLIKELY(x) x-#endif--#define BW_ENSURE_CAPACITY(bw, cap, count_size) \- do { \- if (!ensureCapacity((bw), (cap))) { \- if (bw->counting_size) { \- bw->counted_size += count_size; \- } \- return; \- } \- } while (0)---namespace {- static const unsigned char DEC2HEX[16] = {- '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'- };-- struct BufferWriter {- unsigned char* end; // the most commonly-accessed field- unsigned char* capacity;- unsigned char* data;-- bool counting_size;- size_t counted_size;-- // invariants:- // if (counting_size), end, capacity, and data are null- // else, counted_size is zero and:- // if (end <= capacity), then data is non-null and end >= data- // if (capacity == 0), then data and end are null, and object is dead-- // Note: We mark the object dead upon growth failure in order- // to avoid the need to check for errors after every single- // append function. The error can be raised upon the final- // pointer release.- };-- BW_NOINLINE bool actuallyGrow(BufferWriter* bw, size_t amount) {- if (bw->capacity == 0) {- // object is dead, ignore append request- return false;- }-- size_t size = bw->end - bw->data;- size_t newCapacity = bw->capacity - bw->data;- do {- // TODO: detect overflow?- newCapacity *= 2;- } while (newCapacity < size + amount);-- unsigned char* newData = reinterpret_cast<unsigned char*>(realloc(bw->data, newCapacity));- if (newData) {- bw->data = newData;- bw->end = newData + size;- bw->capacity = newData + newCapacity;- return true;- } else {- // TODO: try smaller growth?- free(bw->data);- bw->data = 0;- bw->end = 0;- bw->capacity = 0;- return false;- }- }-- inline bool ensureCapacity(BufferWriter* bw, size_t amount) {- if (BW_LIKELY(bw->end + amount <= bw->capacity)) {- return true;- } else {- return actuallyGrow(bw, amount);- }- }-}--extern "C" BufferWriter* bw_new(size_t initialCapacity) {- if (!initialCapacity) {- initialCapacity = 1;- }-- BufferWriter* bw = reinterpret_cast<BufferWriter*>(malloc(sizeof(BufferWriter)));- if (!bw) {- return 0;- }-- bw->data = reinterpret_cast<unsigned char*>(malloc(initialCapacity));- if (!bw->data) {- free(bw);- return 0;- }-- bw->end = bw->data;- bw->capacity = bw->data + initialCapacity;- bw->counting_size = false;- bw->counted_size = 0;- return bw;-}--extern "C" BufferWriter* bw_new_length_calculator() {- BufferWriter* bw = reinterpret_cast<BufferWriter*>(malloc(sizeof(BufferWriter)));- if (!bw) {- return 0;- }-- bw->data = 0;- bw->end = 0;- bw->capacity = 0;- bw->counting_size = true;- bw->counted_size = 0;- return bw;-}--extern "C" void bw_free(BufferWriter* bw) {- free(bw->data);- free(bw);-}--extern "C" void bw_trim(BufferWriter* bw) {- if (bw->data == 0) {- return;- }-- if (bw->end < bw->capacity) {- // try to shrink- size_t size = bw->end - bw->data;- unsigned char* data = reinterpret_cast<unsigned char*>(realloc(bw->data, size));- if (data) {- bw->data = data;- bw->end = data + size;- bw->capacity = data + size;- } else {- // no problem- }- }--}--extern "C" size_t bw_get_size(BufferWriter* bw) {- if (bw->counting_size) {- return bw->counted_size;- } else {- return bw->end - bw->data;- }-}--extern "C" unsigned char* bw_release_address(BufferWriter* bw) {- unsigned char* data = bw->data;-- bw->end = 0;- bw->capacity = 0;- bw->data = 0;- bw->counting_size = false;- bw->counted_size = 0;- return data; // null if dead-}--extern "C" void bw_append_byte(BufferWriter* bw, unsigned char byte) {- BW_ENSURE_CAPACITY(bw, 1, 1);-- bw->end[0] = byte;- bw->end += 1;-}--inline size_t utf8_char_length(uint32_t c) {- if (c <= 0x7F) {- return 1;- } else if (c <= 0x7FF) {- return 2;- } else if (c <= 0xFFFF) {- return 3;- } else if (c <= 0x1FFFFF) {- return 4;- } else {- // Unicode characters out of this range are illegal...- return 0;- }-}--extern "C" void bw_append_char_utf8(BufferWriter* bw, uint32_t c) {- BW_ENSURE_CAPACITY(bw, 4, utf8_char_length(c));-- unsigned char* data = bw->end;-- if (c <= 0x7F) {- data[0] = static_cast<unsigned char>(c);- data += 1;- } else if (c <= 0x7FF) {- data[0] = static_cast<unsigned char>(0xC0 | (c >> 6));- data[1] = static_cast<unsigned char>(0x80 | (c & 0x3F));- data += 2;- } else if (c <= 0xFFFF) {- data[0] = static_cast<unsigned char>(0xE0 | (c >> 12));- data[1] = static_cast<unsigned char>(0x80 | ((c >> 6) & 0x3F));- data[2] = static_cast<unsigned char>(0x80 | (c & 0x3F));- data += 3;- } else if (c <= 0x1FFFFF) {- data[0] = static_cast<unsigned char>(0xF0 | (c >> 18));- data[1] = static_cast<unsigned char>(0x80 | ((c >> 12) & 0x3F));- data[2] = static_cast<unsigned char>(0x80 | ((c >> 6) & 0x3F));- data[3] = static_cast<unsigned char>(0x80 | (c & 0x3F));- data += 4;- } else {- // Unicode characters out of this range are illegal...- // should we assert? or just ignore...- }- bw->end = data;-}--extern "C" void bw_append_bs(BufferWriter* bw, size_t size, const unsigned char* data) {- BW_ENSURE_CAPACITY(bw, size, size);-- memcpy(bw->end, data, size);- bw->end += size;-}--extern "C" void bw_append_bsz(BufferWriter* bw, const unsigned char* data) {- bw_append_bs(bw, strlen(reinterpret_cast<const char*>(data)), data);-}--extern "C" void bw_append_byte7(BufferWriter* bw, unsigned char byte) {- BW_ENSURE_CAPACITY(bw, 1, 1);-- bw->end[0] = byte & 0x7F;- bw->end += 1;-}--extern "C" void bw_append_bs7(BufferWriter* bw, size_t size, const unsigned char* data) {- BW_ENSURE_CAPACITY(bw, size, size);-- unsigned char* out = bw->end;- for (size_t i = 0; i < size; ++i) {- out[i] = data[i] & 0x7F;- }- bw->end += size;-}--extern "C" void bw_append_bsz7(BufferWriter* bw, const unsigned char* data) {- bw_append_bs7(bw, strlen(reinterpret_cast<const char*>(data)), data);-}--inline size_t count_escaped_json_length(size_t size, const unsigned char* data) {- size_t rv = 2;- for (size_t i = 0; i < size; ++i) {- switch (data[i]) {- case '\n': rv += 2; break;- case '\r': rv += 2; break;- case '\t': rv += 2; break;- case '\\': rv += 2; break;- case '\"': rv += 2; break;- default:- if (data[i] <= 0x1F) {- rv += 6;- } else {- rv += 1;- }- break;- }- }- return rv;-}--extern "C" void bw_append_json_escaped(BufferWriter* bw, size_t size, const unsigned char* data) {- BW_ENSURE_CAPACITY(bw, 2 + size * 6, count_escaped_json_length(size, data));-- unsigned char* dest = bw->end;- *dest++ = '\"';-- size_t i = 0;- while (i < size) {- switch (data[i]) {- case '\n': *dest++ = '\\'; *dest++ = 'n'; break;- case '\r': *dest++ = '\\'; *dest++ = 'r'; break;- case '\t': *dest++ = '\\'; *dest++ = 't'; break;- case '\\': *dest++ = '\\'; *dest++ = '\\'; break;- case '\"': *dest++ = '\\'; *dest++ = '\"'; break;- default:- unsigned char d = data[i];- if (d <= 0x1F) {- *dest++ = '\\';- *dest++ = 'u';- *dest++ = '0';- *dest++ = '0';- *dest++ = DEC2HEX[d >> 4];- *dest++ = DEC2HEX[d & 0xF];- } else {- *dest++ = d;- }- break;- }- ++i;- }-- *dest++ = '\"';- bw->end = dest;-}--inline size_t count_decimal_signed_int_length(int64_t i) {- char buf[32]; // enough- return i64toa_branchlut(i, buf);-}--extern "C" void bw_append_decimal_signed_int(BufferWriter* bw, int64_t i) {- BW_ENSURE_CAPACITY(bw, 32, count_decimal_signed_int_length(i)); // enough-- unsigned used = i64toa_branchlut(i, reinterpret_cast<char*>(bw->end));- bw->end += used;-}--inline size_t count_decimal_double_length(double d) {- char buf[318];- return sprintf(buf, "%f", d);-}--extern "C" void bw_append_decimal_double(BufferWriter* bw, double d) {- BW_ENSURE_CAPACITY(bw, 318, count_decimal_double_length(d)); // sprintf("%f", -DBL_MAX);-- size_t used = sprintf(reinterpret_cast<char*>(bw->end), "%f", d);- bw->end += used;-}--// From <https://github.com/bos/text/blob/f74427c954fb4479f9db5025f27775e29ace125f/cbits/cbits.c#L234>-extern "C" void bw_encode_utf8(uint8_t **destp, const uint16_t *src, size_t srcoff, size_t srclen) {- const uint16_t *srcend;- uint8_t *dest = *destp;-- src += srcoff;- srcend = src + srclen;-- ascii:-#if defined(__x86_64__)- while (srcend - src >= 4) {- uint64_t w = *((uint64_t *) src);-- if (w & 0xFF80FF80FF80FF80ULL) {- if (!(w & 0x000000000000FF80ULL)) {- *dest++ = w & 0xFFFF;- src++;- if (!(w & 0x00000000FF800000ULL)) {- *dest++ = (w >> 16) & 0xFFFF;- src++;- if (!(w & 0x0000FF8000000000ULL)) {- *dest++ = (w >> 32) & 0xFFFF;- src++;- }- }- }- break;- }- *dest++ = w & 0xFFFF;- *dest++ = (w >> 16) & 0xFFFF;- *dest++ = (w >> 32) & 0xFFFF;- *dest++ = w >> 48;- src += 4;- }-#endif--#if defined(__i386__)- while (srcend - src >= 2) {- uint32_t w = *((uint32_t *) src);-- if (w & 0xFF80FF80)- break;- *dest++ = w & 0xFFFF;- *dest++ = w >> 16;- src += 2;- }-#endif-- while (src < srcend) {- uint16_t w = *src++;-- if (w <= 0x7F) {- *dest++ = w;- /* An ASCII byte is likely to begin a run of ASCII bytes.- Falling back into the fast path really helps performance. */- goto ascii;- }- else if (w <= 0x7FF) {- *dest++ = (w >> 6) | 0xC0;- *dest++ = (w & 0x3f) | 0x80;- }- else if (w < 0xD800 || w > 0xDBFF) {- *dest++ = (w >> 12) | 0xE0;- *dest++ = ((w >> 6) & 0x3F) | 0x80;- *dest++ = (w & 0x3F) | 0x80;- } else {- uint32_t c = ((((uint32_t) w) - 0xD800) << 10) +- (((uint32_t) *src++) - 0xDC00) + 0x10000;- *dest++ = (c >> 18) | 0xF0;- *dest++ = ((c >> 12) & 0x3F) | 0x80;- *dest++ = ((c >> 6) & 0x3F) | 0x80;- *dest++ = (c & 0x3F) | 0x80;- }- }-- *destp = dest;-}--extern "C" void bw_append_json_escaped_utf16(BufferWriter* bw, size_t size, unsigned short* words) {- // TODO: handle malloc failure- // ideally no temp buffer would be required here.- unsigned char* utf8 = reinterpret_cast<unsigned char*>(malloc(size * 4));- assert(utf8);- unsigned char* utf8end = utf8;-- bw_encode_utf8(&utf8end, words, 0, size);-- bw_append_json_escaped(bw, utf8end - utf8, utf8);-- free(utf8);-}--static const unsigned char UNRESERVED[256] = {- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,1,1,0,- 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,-- 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,- 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1,- 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,- 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,1,0,-- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,-- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0-};--inline size_t count_url_encoded_length(size_t size, const unsigned char* data) {- size_t rv = 0;- for (size_t i = 0; i < size; ++i) {- if (UNRESERVED[data[i]]) {- rv += 1;- } else {- rv += 3;- }- }- return rv;-}--extern "C" void bw_append_url_encoded(BufferWriter* bw, size_t size, const unsigned char* data) {- // worst case- BW_ENSURE_CAPACITY(bw, size * 3, count_url_encoded_length(size, data));-- const unsigned char* src = data;- unsigned char* dst = bw->end;- while (size--) {- unsigned char c = *src++;- if (UNRESERVED[c]) {- *dst++ = c;- } else {- dst[0] = '%';- dst[1] = DEC2HEX[c >> 4];- dst[2] = DEC2HEX[c & 0xF];- dst += 3;- }- }-- bw->end = dst;-}
changelog.md view
@@ -1,3 +1,7 @@+0.2.4.7++* Remove any dependencies on C+++ 0.2.4.6 * Fix package compilation on GHC 7.8 and 7.10. (Thanks Xia Li-yao!)