diff --git a/tests/test_various.c b/tests/test_various.c index f9d723f..449b56c 100644 --- a/tests/test_various.c +++ b/tests/test_various.c @@ -198,11 +198,41 @@ void test_various_imported_tests() { // assert(tg_geom_intersects(b, a) == true); } +void tg_geom_setnoheap(struct tg_geom *geom); + +void test_various_noheap(void) { + struct tg_geom *g1 = tg_parse("POINT(1 1)", 10); + struct tg_geom *g2 = tg_geom_clone(g1); + + + size_t size = tg_geom_memsize(g1); + struct tg_geom *g3 = alloca(size); + memcpy(g3, g1, size); + tg_geom_setnoheap(g3); + struct tg_geom *g4 = tg_geom_clone(g3); + + + assert(tg_geom_equals(g1, g2)); + assert(tg_geom_equals(g2, g3)); + assert(tg_geom_equals(g3, g4)); + + assert(g1 == g2); + assert(g2 != g3); + assert(g3 != g4); + + tg_geom_free(g4); + tg_geom_free(g3); + tg_geom_free(g2); + tg_geom_free(g1); + +} + int main(int argc, char **argv) { do_test(test_various_imported_tests); do_test(test_various_issue_14); do_test(test_various_issue_369); do_test(test_various_unit_tests); + do_test(test_various_noheap); return 0; } diff --git a/tg.c b/tg.c index 5c2afaf..f4d017f 100644 --- a/tg.c +++ b/tg.c @@ -85,8 +85,9 @@ static void rc_add(rc_t *rc) { struct head { rc_t rc; - enum base base:8; - enum tg_geom_type type:8; + bool noheap; + enum base base:4; + enum tg_geom_type type:4; enum flags flags:8; }; @@ -1835,8 +1836,7 @@ struct tg_ring *tg_ring_new_ix(const struct tg_point *points, int npoints, /// @param ring Input ring /// @see RingFuncs void tg_ring_free(struct tg_ring *ring) { - if (!ring) return; - if (rc_sub(&ring->head.rc)) return; + if (!ring || ring->head.noheap || rc_sub(&ring->head.rc)) return; if (ring->ystripes) tg_free(ring->ystripes); tg_free(ring); } @@ -1859,7 +1859,9 @@ static size_t ring_alloc_size(const struct tg_ring *ring) { /// reference counter. /// @see RingFuncs struct tg_ring *tg_ring_clone(const struct tg_ring *ring) { - if (!ring) return NULL; + if (!ring || ring->head.noheap) { + return tg_ring_copy(ring); + } struct tg_ring *ring_mut = (struct tg_ring*)ring; rc_add(&ring_mut->head.rc); return ring_mut; @@ -3352,7 +3354,7 @@ void tg_poly_free(struct tg_poly *poly) { tg_ring_free((struct tg_ring*)poly); return; } - if (rc_sub(&poly->head.rc)) return; + if (poly->head.noheap || rc_sub(&poly->head.rc)) return; if (poly->exterior) tg_ring_free(poly->exterior); if (poly->holes) { for (int i = 0; i < poly->nholes; i++) { @@ -3371,13 +3373,14 @@ void tg_poly_free(struct tg_poly *poly) { /// reference counter. /// @see PolyFuncs struct tg_poly *tg_poly_clone(const struct tg_poly *poly) { - if (!poly) return NULL; + if (!poly || poly->head.noheap) { + return tg_poly_copy(poly); + } struct tg_poly *poly_mut = (struct tg_poly*)poly; rc_add(&poly_mut->head.rc); return poly_mut; } - /// Returns the exterior ring. /// @param poly Input polygon /// @return Exterior ring @@ -3868,7 +3871,7 @@ struct tg_geom *tg_geom_new_point(struct tg_point point) { } static void boxed_point_free(struct boxed_point *point) { - if (rc_sub(&point->head.rc)) return; + if (point->head.noheap || rc_sub(&point->head.rc)) return; tg_free(point); } @@ -4618,14 +4621,16 @@ struct tg_geom *tg_geom_new_multipolygon_zm( /// reference counter. /// @see GeometryConstructors struct tg_geom *tg_geom_clone(const struct tg_geom *geom) { - if (!geom) return NULL; + if (!geom || geom->head.noheap) { + return tg_geom_copy(geom); + } struct tg_geom *geom_mut = (struct tg_geom*)geom; rc_add(&geom_mut->head.rc); return geom_mut; } static void geom_free(struct tg_geom *geom) { - if (rc_sub(&geom->head.rc)) return; + if (geom->head.noheap || rc_sub(&geom->head.rc)) return; switch (geom->head.type) { case TG_POINT: break; @@ -14002,6 +14007,7 @@ struct tg_ring *tg_ring_copy(const struct tg_ring *ring) { } memcpy(ring2, ring, size); ring2->head.rc = 0; + ring2->head.noheap = 0; if (ring->ystripes) { ring2->ystripes = tg_malloc(ring->ystripes->memsz); if (!ring2->ystripes) { @@ -14045,6 +14051,7 @@ struct tg_poly *tg_poly_copy(const struct tg_poly *poly) { memset(poly2, 0, sizeof(struct tg_poly)); memcpy(&poly2->head, &poly->head, sizeof(struct head)); poly2->head.rc = 0; + poly2->head.noheap = 0; poly2->exterior = tg_ring_copy(poly->exterior); if (!poly2->exterior) { goto fail; @@ -14077,6 +14084,7 @@ static struct tg_geom *geom_copy(const struct tg_geom *geom) { memset(geom2, 0, sizeof(struct tg_geom)); memcpy(&geom2->head, &geom->head, sizeof(struct head)); geom2->head.rc = 0; + geom2->head.noheap = 0; switch (geom->head.type) { case TG_POINT: geom2->point.x = geom->point.x; @@ -14173,6 +14181,7 @@ static struct boxed_point *boxed_point_copy(const struct boxed_point *point) { } memcpy(point2, point, sizeof(struct boxed_point)); point2->head.rc = 0; + point2->head.noheap = 0; return point2; } @@ -14361,3 +14370,10 @@ struct tg_geom *tg_parse_ix(const void *data, size_t len, enum tg_index ix) { struct tg_geom *tg_geom_new_error(const char *error) { return error?make_parse_error("%s", error):0; } + +/// Set the noheap property to true and the reference counter to zero. +/// _undocumented_ +void tg_geom_setnoheap(struct tg_geom *geom) { + geom->head.rc = 0; + geom->head.noheap = 1; +}