From d42115cb6a19043a5b3d233dc97dcb837dfa389e Mon Sep 17 00:00:00 2001 From: Maxim Date: Mon, 15 Aug 2022 19:39:35 +0300 Subject: [PATCH] "str_auto" type added. --- README.md | 14 ++++++++++---- str.c | 7 +++++++ str.h | 5 +++++ str_test.c | 17 ++++++----------- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 500e990..dca568e 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,9 @@ store or release the object. When in doubt pass such an object via `str_ref`. `str_assign` function instead. In fact, this function can assign to any string object, owning or not, so it can be used everywhere, just to avoid any doubt. * There is no automatic memory management in C, so every owning object must be released at -some point using either `str_free` or `str_clear` function. +some point using either `str_free` or `str_clear` function. String objects on the stack +can also be declared as `str_auto` (or `const str_auto`) for automatic cleanup when the variable +goes out of scope. * An owning object can be moved to another location by using `str_move` function. The function resets its source object to an empty string. * An owning object can be passed over to another location by using `str_pass` function. The @@ -152,7 +154,8 @@ of failure (including `ENOMEM` on memory allocation error). Just to make things more clear, here is the same code as in the example above, but with comments: ```C -// declare a variable and initialise it with an empty string +// declare a variable and initialise it with an empty string; could also be declared as "str_auto" +// to avoid explicit call to str_free() below. str s = str_null; // join the given string literals around the separator (second parameter), @@ -243,8 +246,11 @@ original string, and then returns the saved object. #### String Deallocation `void str_free(const str s)`
-Deallocates any memory held by the owning string object. No-op for references. After this function -the object is in unknown and unusable state. +Deallocates any memory held by the owning string object. No-op for references. After a call to +this function the string object is in unknown and unusable state. + +String objects on the stack can also be declared as `str_auto` instead of `str` to deallocate +any memory held by the string when the variable goes out of scope. #### String Modification diff --git a/str.c b/str.c index dc36ad1..398afe3 100644 --- a/str.c +++ b/str.c @@ -68,6 +68,13 @@ void str_free(const str s) str_mem_free((void*)s.ptr); } +// version of str_free() for str_auto macro +void _str_free(const str* const ps) +{ + if(ps) + str_free(*ps); +} + // memory allocation helpers #define ALLOC(n) \ ({ \ diff --git a/str.h b/str.h index 441bcf1..63fb497 100644 --- a/str.h +++ b/str.h @@ -87,6 +87,11 @@ bool str_is_ref(const str s) { return !str_is_owner(s); } // free memory allocated for the string void str_free(const str s); +// automatic cleanup +void _str_free(const str* const ps); + +#define str_auto str __attribute__((cleanup(_str_free))) + // string movements ----------------------------------------------------------------------- // free target string, then assign the new value to it static inline diff --git a/str_test.c b/str_test.c index 677bd7c..4cac8ce 100644 --- a/str_test.c +++ b/str_test.c @@ -66,7 +66,7 @@ void test_str_lit(void) static void test_str_cpy(void) { - str s = str_null; + str_auto s = str_null; assert(str_cpy(&s, str_lit("ZZZ")) == 0); @@ -76,7 +76,6 @@ void test_str_cpy(void) assert(str_eq(s, str_lit("ZZZ"))); assert(*str_end(s) == 0); - str_free(s); passed; } @@ -163,7 +162,7 @@ void test_str_ref(void) static void test_str_cmp(void) { - const str s = str_lit("zzz"); + const str_auto s = str_lit("zzz"); assert(str_cmp(s, s) == 0); assert(str_cmp(s, str_lit("zzz")) == 0); @@ -200,13 +199,12 @@ void test_str_cmp_ci(void) static void test_str_acquire(void) { - str s = str_acquire(strdup("ZZZ")); + str_auto s = str_acquire(strdup("ZZZ")); assert(str_is_owner(s)); assert(str_eq(s, str_lit("ZZZ"))); assert(*str_end(s) == 0); - str_free(s); passed; } @@ -275,7 +273,7 @@ void test_str_join(void) static void test_composition(void) { - str s = str_lit(", "); + str_auto s = str_lit(", "); assert(str_join(&s, s, str_lit("Here"), str_lit("there"), str_lit("and everywhere")) == 0); assert(str_cat(&s, s, str_lit("...")) == 0); @@ -284,7 +282,6 @@ void test_composition(void) assert(str_is_owner(s)); assert(*str_end(s) == 0); - str_free(s); passed; } @@ -680,7 +677,7 @@ void test_unique_range(void) static void test_from_file(void) { - str fname = str_null; + str_auto fname = str_null; assert(str_cat(&fname, str_lit("tmp_"), str_ref_chars(__func__, sizeof(__func__) - 1)) == 0); @@ -690,7 +687,7 @@ void test_from_file(void) assert(str_join(stream, str_lit(" "), str_lit("aaa"), str_lit("bbb"), str_lit("ccc")) == 0); assert(fclose(stream) == 0); - str res = str_null; + str_auto res = str_null; assert(str_from_file(&res, str_ptr(fname)) == 0); unlink(str_ptr(fname)); @@ -702,8 +699,6 @@ void test_from_file(void) assert(str_from_file(&res, "/dev/null") == EOPNOTSUPP); assert(str_from_file(&res, "does-not-exist") == ENOENT); - str_free(res); - str_free(fname); passed; }