From cd7a6448180d1671e9910d7bee80f2aae96ef662 Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Tue, 21 Apr 2015 11:12:07 +0200 Subject: [PATCH] Drop a memory copy in pc_patch_to_string (#74) --- lib/pc_patch_uncompressed.c | 47 +++++++++++++++++++++---------------- lib/stringbuffer.c | 18 ++++++++++++-- lib/stringbuffer.h | 2 ++ 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/lib/pc_patch_uncompressed.c b/lib/pc_patch_uncompressed.c index 3ef218b..be6be30 100644 --- a/lib/pc_patch_uncompressed.c +++ b/lib/pc_patch_uncompressed.c @@ -13,39 +13,36 @@ #include "pc_api_internal.h" #include "stringbuffer.h" - -char * -pc_patch_uncompressed_to_string(const PCPATCH_UNCOMPRESSED *patch) +/* TODO: expose to API ? Would require also exposing stringbuffer + * See https://github.com/pgpointcloud/pointcloud/issues/74 + */ +static int +pc_patch_uncompressed_to_stringbuffer(const PCPATCH_UNCOMPRESSED *patch, stringbuffer_t *sb) { - /* { "pcid":1, "points":[[, , , ],[, , , ]] }*/ - stringbuffer_t *sb = stringbuffer_create(); PCPOINTLIST *pl; - char *str; int i, j; + /* { "pcid":1, "points":[[, , , ],[, , , ]] }*/ + + /* TODO: reserve space in buffer ? */ + pl = pc_pointlist_from_uncompressed(patch); stringbuffer_aprintf(sb, "{\"pcid\":%d,\"pts\":[", patch->schema->pcid); for ( i = 0; i < pl->npoints; i++ ) { PCPOINT *pt = pc_pointlist_get_point(pl, i); - if ( i ) - { - stringbuffer_append(sb, ","); - } - stringbuffer_append(sb, "["); + if ( i ) stringbuffer_append(sb, ",["); + else stringbuffer_append(sb, "["); for ( j = 0; j < pt->schema->ndims; j++ ) { double d; if ( ! pc_point_get_double_by_index(pt, j, &d)) { pcerror("%s: unable to read double at index %d", __func__, j); - return NULL; + return PC_FAILURE; } - if ( j ) - { - stringbuffer_append(sb, ","); - } - stringbuffer_aprintf(sb, "%g", d); + if ( j ) stringbuffer_aprintf(sb, ",%g", d); + else stringbuffer_aprintf(sb, "%g", d); } stringbuffer_append(sb, "]"); } @@ -53,10 +50,20 @@ pc_patch_uncompressed_to_string(const PCPATCH_UNCOMPRESSED *patch) /* All done, copy and clean up */ pc_pointlist_free(pl); - str = stringbuffer_getstringcopy(sb); - stringbuffer_destroy(sb); - return str; + return PC_SUCCESS; +} + +char * +pc_patch_uncompressed_to_string(const PCPATCH_UNCOMPRESSED *patch) +{ + stringbuffer_t *sb = stringbuffer_create(); + char *str; + if ( PC_FAILURE == pc_patch_uncompressed_to_stringbuffer(patch, sb) ) + return NULL; + str = stringbuffer_release_string(sb); + stringbuffer_destroy(sb); + return str; } uint8_t * diff --git a/lib/stringbuffer.c b/lib/stringbuffer.c index 1ae3278..662a546 100644 --- a/lib/stringbuffer.c +++ b/lib/stringbuffer.c @@ -3,6 +3,7 @@ * * Copyright 2002 Thamer Alharbash * Copyright 2009 Paul Ramsey + * Copyright 2015 Sandro Santilli * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following @@ -95,8 +96,8 @@ stringbuffer_makeroom(stringbuffer_t *s, size_t size_to_add) size_t capacity = s->capacity; size_t required_size = current_size + size_to_add; - while (capacity < required_size) - capacity *= 2; + if ( ! capacity ) capacity = STRINGBUFFER_STARTSIZE; + else while (capacity < required_size) capacity *= 2; if ( capacity > s->capacity ) { @@ -142,6 +143,19 @@ stringbuffer_getstring(stringbuffer_t *s) return s->str_start; } +/** +* Transfer ownership of the internal string to caller, +* turning this buffer into an empty one +*/ +char* +stringbuffer_release_string(stringbuffer_t *s) +{ + char *ret = s->str_start; + s->str_start = s->str_end = NULL; + s->capacity = 0; + return ret; +} + /** * Returns a newly allocated string large enough to contain the * current state of the string. Caller is responsible for diff --git a/lib/stringbuffer.h b/lib/stringbuffer.h index 2a7a06e..29470cc 100644 --- a/lib/stringbuffer.h +++ b/lib/stringbuffer.h @@ -3,6 +3,7 @@ * * Copyright 2002 Thamer Alharbash * Copyright 2009 Paul Ramsey + * Copyright 2015 Sandro Santilli * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following @@ -70,6 +71,7 @@ extern void stringbuffer_append(stringbuffer_t *sb, const char *s); extern int stringbuffer_aprintf(stringbuffer_t *sb, const char *fmt, ...); extern const char *stringbuffer_getstring(stringbuffer_t *sb); extern char *stringbuffer_getstringcopy(stringbuffer_t *sb); +extern char *stringbuffer_release_string(stringbuffer_t *sb); extern int stringbuffer_getlength(stringbuffer_t *sb); extern char stringbuffer_lastchar(stringbuffer_t *s); extern int stringbuffer_trim_trailing_white(stringbuffer_t *s);