#define _POSIX_C_SOURCE 200809L #include "runtime.h" #include #include #include #include #include extern long long dever_test_allocations(void); #ifndef WIRE_TEXT_KEY #define WIRE_TEXT_KEY "text" #endif #ifndef WIRE_NUMBER_KEY #define WIRE_NUMBER_KEY "number" #endif #ifndef WIRE_RECORD #define WIRE_RECORD 0 #endif typedef struct { void *text; int64_t rows; } Payload; #if WIRE_RECORD != 2 static const DeverRtWireName fields[] = { {(const uint8_t *)WIRE_TEXT_KEY, sizeof(WIRE_TEXT_KEY) - 1}, {(const uint8_t *)WIRE_NUMBER_KEY, sizeof(WIRE_NUMBER_KEY) - 1} }; #endif static void payload_clone(const void *source, void *destination) { const Payload *input = source; Payload *output = destination; *output = *input; output->text = dever_rt_v1_text_retain(input->text); } static void payload_drop(void *value) { Payload *payload = value; dever_rt_v1_text_release(payload->text); payload->text = NULL; } static uint8_t payload_equal(const void *left, const void *right) { const Payload *first = left; const Payload *second = right; return first->rows == second->rows && dever_rt_v1_text_equal(first->text, second->text); } static const DeverRtType payload_type = { sizeof(Payload), _Alignof(Payload), payload_clone, payload_drop, payload_equal, NULL }; #if WIRE_RECORD == 2 static const DeverRtWireName prefixes[] = { {(const uint8_t *)"\"" WIRE_TEXT_KEY "\":", sizeof("\"" WIRE_TEXT_KEY "\":") - 1}, {(const uint8_t *)",\"" WIRE_NUMBER_KEY "\":", sizeof(",\"" WIRE_NUMBER_KEY "\":") - 1} }; static uint32_t encode_fields(const void *value, void *writer, DeverRtBuffer *error) { const Payload *payload = value; uint32_t status = dever_rt_v1_wire_encoder_compiled_key(writer, &prefixes[0], error); if (status == 0) status = dever_rt_v1_wire_encoder_text(writer, payload->text, error); if (status == 0) status = dever_rt_v1_wire_encoder_compiled_key(writer, &prefixes[1], error); if (status == 0) status = dever_rt_v1_wire_encoder_int(writer, INT64_C(9007199254740993), error); return status; } #elif WIRE_RECORD static uint32_t encode_field(uint64_t index, const void *value, void *writer, DeverRtBuffer *error) { const Payload *payload = value; if (index == 0) return dever_rt_v1_wire_encoder_text(writer, payload->text, error); if (index == 1) return dever_rt_v1_wire_encoder_int(writer, INT64_C(9007199254740993), error); return 2; } #endif static uint32_t encode(const void *value, void *writer, DeverRtBuffer *error) { const Payload *payload = value; uint32_t status = dever_rt_v1_wire_encoder_begin_array(writer, error); for (int64_t index = 0; index < payload->rows && status == 0; ++index) { #if WIRE_RECORD == 2 status = dever_rt_v1_wire_encoder_compiled_record(writer, value, &payload_type, 2, encode_fields, error); #elif WIRE_RECORD status = dever_rt_v1_wire_encoder_record(writer, value, &payload_type, fields, 2, encode_field, error); #else status = dever_rt_v1_wire_encoder_begin_object(writer, error); if (status == 0) status = dever_rt_v1_wire_encoder_key(writer, &fields[0], error); if (status == 0) status = dever_rt_v1_wire_encoder_text(writer, payload->text, error); if (status == 0) status = dever_rt_v1_wire_encoder_key(writer, &fields[1], error); if (status == 0) status = dever_rt_v1_wire_encoder_int(writer, INT64_C(9007199254740993), error); if (status == 0) status = dever_rt_v1_wire_encoder_end(writer, error); #endif } if (status == 0) status = dever_rt_v1_wire_encoder_end(writer, error); return status; } int dever_test_run(void) { const char *configured = getenv("DEVER_WIRE_BENCH_ROWS"); int64_t rows = configured == NULL ? 128 : strtoll(configured, NULL, 10); if (rows != 4 && rows != 128) return 1; const char *text = "Unicode 雪😀 and newline\n"; const char *row = "{\"" WIRE_TEXT_KEY "\":\"Unicode 雪😀 and newline\\n\",\"" WIRE_NUMBER_KEY "\":9007199254740993}"; Payload payload = {NULL, rows}; DeverRtBuffer error = {0}; if (dever_rt_v1_text_new((const uint8_t *)text, strlen(text), &payload.text, &error)) return 2; void *output = NULL; if (dever_rt_v1_wire_encode(&payload, &payload_type, encode, &output, &error)) return 3; DeverRtBuffer bytes = {0}; if (dever_rt_v1_text_export(output, &bytes)) return 4; size_t row_length = strlen(row); if (bytes.len != 1 + (row_length + 1) * (size_t)rows || bytes.ptr[0] != '[' || bytes.ptr[bytes.len - 1] != ']') return 5; for (int64_t index = 0; index < rows; ++index) { if (memcmp(bytes.ptr + 1 + (size_t)index * (row_length + 1), row, row_length) != 0) return 6; } dever_rt_v1_buffer_free(bytes.ptr, bytes.len); dever_rt_v1_text_release(output); struct timespec started, finished; if (clock_gettime(CLOCK_MONOTONIC, &started)) return 7; long long allocations = dever_test_allocations(); const int64_t iterations = 500; for (int64_t iteration = 0; iteration < iterations; ++iteration) { if (dever_rt_v1_wire_encode(&payload, &payload_type, encode, &output, &error)) return 8; dever_rt_v1_text_release(output); } allocations = dever_test_allocations() - allocations; if (clock_gettime(CLOCK_MONOTONIC, &finished)) return 9; int64_t elapsed = (int64_t)(finished.tv_sec - started.tv_sec) * INT64_C(1000000000) + finished.tv_nsec - started.tv_nsec; payload_drop(&payload); printf("{\"rows\":%lld,\"iterations\":%lld,\"elapsed_ns\":%lld,\"allocations\":%lld}\n", (long long)rows, (long long)iterations, (long long)elapsed, allocations); return 0; }