diff --git a/libc3/bool.c b/libc3/bool.c
index 6eea312..1823d46 100644
--- a/libc3/bool.c
+++ b/libc3/bool.c
@@ -33,7 +33,8 @@ bool * bool_init_cast (bool *b, const s_sym * const *type,
case TAG_CHARACTER: *b = (bool) tag->data.character; return b;
case TAG_COMPLEX: *b = ! complex_is_zero(tag->data.complex);
return b;
- case TAG_COW: return bool_init_cast(b, type, cow_rw(tag->data.cow));
+ case TAG_COW:
+ return bool_init_cast(b, type, cow_read_only(tag->data.cow));
case TAG_F32: *b = (bool) tag->data.f32; return b;
case TAG_F64: *b = (bool) tag->data.f64; return b;
case TAG_F128: *b = (bool) tag->data.f128; return b;
diff --git a/libc3/buf_inspect.c b/libc3/buf_inspect.c
index 3b08e8c..5a5d060 100644
--- a/libc3/buf_inspect.c
+++ b/libc3/buf_inspect.c
@@ -917,7 +917,7 @@ sw buf_inspect_cow (s_buf *buf, const s_cow *cow)
buf_save_init(buf, &save);
if ((r = buf_write_1(buf, "cow ")) < 0)
goto restore;
- if ((r = buf_inspect_tag(buf, cow_ro(cow))) < 0)
+ if ((r = buf_inspect_tag(buf, cow_read_only(cow))) < 0)
goto restore;
result += r;
r = result;
@@ -934,7 +934,7 @@ sw buf_inspect_cow_size (const s_cow *cow)
sw r;
sw result;
result = strlen("cow ");
- if ((r = buf_inspect_tag_size(cow_ro(cow))) < 0)
+ if ((r = buf_inspect_tag_size(cow_read_only(cow))) < 0)
return r;
result += r;
return result;
diff --git a/libc3/buf_parse.c b/libc3/buf_parse.c
index 8923827..ded5e55 100644
--- a/libc3/buf_parse.c
+++ b/libc3/buf_parse.c
@@ -1201,7 +1201,7 @@ sw buf_parse_cow (s_buf *buf, s_cow *cow)
if ((r = buf_ignore_spaces(buf)) <= 0)
goto restore;
result += r;
- if ((r = buf_parse_tag(buf, &tmp.r)) <= 0)
+ if ((r = buf_parse_tag(buf, cow_read_write(&tmp))) <= 0)
goto clean;
result += r;
*cow = tmp;
diff --git a/libc3/compare.c b/libc3/compare.c
index 16a2eea..f168b78 100644
--- a/libc3/compare.c
+++ b/libc3/compare.c
@@ -151,9 +151,8 @@ s8 compare_complex (const s_complex *a, const s_complex *b)
u8 compare_cow (const s_cow *a, const s_cow *b)
{
u8 r;
- if ((r = compare_tag(&a->r, &b->r)) ||
- (r = compare_bool(a->w_is_set, b->w_is_set)) ||
- (r = compare_tag(&a->w, &b->w)))
+ if ((r = compare_sym(a->type, b->type)) ||
+ (r = compare_list(a->list, b->list)))
return r;
return 0;
}
diff --git a/libc3/cow.c b/libc3/cow.c
index 376befa..0e6fe35 100644
--- a/libc3/cow.c
+++ b/libc3/cow.c
@@ -13,13 +13,13 @@
#include "assert.h"
#include "alloc.h"
#include "cow.h"
+#include "list.h"
#include "tag.h"
void cow_clean (s_cow *cow)
{
assert(cow);
- tag_clean(&cow->r);
- tag_clean(&cow->w);
+ list_delete_all(cow->list);
}
void cow_delete (s_cow *cow)
@@ -31,75 +31,108 @@ void cow_delete (s_cow *cow)
s_cow * cow_freeze (s_cow *cow)
{
+ s_list *tmp;
assert(cow);
- if (cow->w_is_set) {
- tag_clean(&cow->r);
- tag_init_copy(&cow->r, &cow->w);
- cow->w_is_set = false;
- tag_clean(&cow->w);
- }
+ assert(cow->list);
+ tmp = list_new_tag_copy(&cow->list->tag, cow->list);
+ if (! tmp)
+ return NULL;
+ cow->list = tmp;
return cow;
}
-s_cow * cow_freeze_tag (s_cow *cow, const s_tag *src)
+s_cow * cow_freeze_copy (s_cow *cow, const s_tag *src)
{
+ s_list *tmp;
assert(cow);
- assert(src);
- cow->w_is_set = false;
- tag_clean(&cow->w);
- tag_clean(&cow->r);
- if (! tag_init_copy(&cow->r, src))
+ assert(cow->list);
+ tmp = list_new_tag_copy(src, list_next(cow->list));
+ if (! tmp)
return NULL;
+ cow->list->next.type = TAG_LIST;
+ cow->list->next.data.list = tmp;
return cow;
}
-s_cow * cow_init (s_cow *cow)
+s_cow * cow_init (s_cow *cow, const s_sym *type)
{
s_cow tmp = {0};
assert(cow);
+ assert(type);
+ tmp.type = type;
+ tmp.list = list_new(NULL);
*cow = tmp;
return cow;
}
s_cow * cow_init_1 (s_cow *cow, const char *utf8)
{
- assert(cow);
- assert(utf8);
- (void) cow;
- (void) utf8;
- err_puts("cow_init_1: FIXME: not implemented");
- assert(! "cow_init_1: FIXME: not implemented");
- return NULL;
+ s_buf buf;
+ uw len;
+ sw r;
+ len = strlen(p);
+ buf_init(&buf, false, len, (char *) p); // buf is read-only
+ buf.wpos = len;
+ r = buf_parse_cow(&buf, cow);
+ if (r < 0 || (uw) r != len) {
+ err_write_1("invalid cow: \"");
+ err_write_1(p);
+ err_write_1("\", ");
+ err_inspect_uw(&len);
+ err_write_1(" != ");
+ err_inspect_sw(&r);
+ assert(! "invalid cow");
+ return NULL;
+ }
+ return tag;
}
s_cow * cow_init_cast (s_cow *cow, const s_sym * const *type,
const s_tag *tag)
{
- assert(cow);
- assert(type);
+ void *data;
+ s_tag tmp;
assert(tag);
- (void) type;
- if (tag->type == TAG_COW)
- return cow_init_copy(cow, tag->data.cow);
- return cow_freeze_tag(cow, tag);
+ assert(type);
+ assert(src);
+ if (*type == &g_sym_Cow) {
+ err_puts("cow_init_cast: cannot cast to Cow");
+ assert(! "cow_init_cast: cannot cast to Cow");
+ return NULL;
+ }
+ if (! sym_to_tag_type(*type, &tmp.type))
+ return NULL;
+ if (! tag_to_pointer(&tmp.list->tag, *type, &data))
+ return NULL;
+ if (! data_init_cast(data, type, src))
+ return NULL;
+ *tag = tmp;
+ return tag;
}
s_cow * cow_init_copy (s_cow *cow, const s_cow *src)
{
+ s_cow tmp = {0};
assert(cow);
assert(src);
- if (! tag_init_copy(&cow->r, &src->r) ||
- ! tag_init_copy(&cow->w, &src->w))
+ tmp.type = src->type;
+ tmp.list = list_new_copy(src->list);
+ if (! tmp.list)
return NULL;
+ *cow = tmp;
return cow;
}
-
+
s_cow * cow_init_tag_copy (s_cow *cow, const s_tag *src)
{
+ assert(cow);
+ assert(src);
s_cow tmp = {0};
assert(cow);
assert(src);
- if (! tag_init_copy(&tmp.r, src))
+ tmp.type = src->type;
+ tmp.list = list_new_tag_copy(src);
+ if (! tmp.list)
return NULL;
*cow = tmp;
return cow;
@@ -107,13 +140,22 @@ s_cow * cow_init_tag_copy (s_cow *cow, const s_tag *src)
s_str * cow_inspect (const s_cow *cow, s_str *dest)
{
- assert(cow);
+ s_buf buf;
+ sw size;
+ assert(tag);
assert(dest);
- (void) cow;
- (void) dest;
- err_puts("cow_inspect: FIXME: not implemented");
- assert(! "cow_inspect: FIXME: not implemented");
- return NULL;
+ if ((size = buf_inspect_cow_size(cow)) < 0) {
+ err_puts("tag_inspect: size error");
+ assert(! "tag_inspect: size error");
+ return NULL;
+ }
+ buf_init_alloc(&buf, size);
+ if (buf_inspect_cow(&buf, cow) != size) {
+ err_puts("tag_inspect: inspect error");
+ assert(! "tag_inspect: inspect error");
+ return NULL;
+ }
+ return buf_to_str(&buf, dest);
}
s_cow * cow_new (void)
@@ -122,15 +164,29 @@ s_cow * cow_new (void)
cow = alloc(sizeof(s_cow));
if (! cow)
return NULL;
- cow_init(cow);
+ if (! cow_init(cow)) {
+ free(cow);
+ return NULL;
+ }
+ return cow;
+}
+
+s_cow * cow_new_1 (const char *utf8)
+{
+ s_cow *cow;
+ cow = alloc(sizeof(s_cow));
+ if (! cow)
+ return NULL;
+ if (! cow_init_1(cow, utf8)) {
+ free(cow);
+ return NULL;
+ }
return cow;
}
s_cow * cow_new_cast (const s_sym * const *type, const s_tag *tag)
{
s_cow *cow;
- assert(type);
- assert(tag);
cow = alloc(sizeof(s_cow));
if (! cow)
return NULL;
@@ -144,7 +200,6 @@ s_cow * cow_new_cast (const s_sym * const *type, const s_tag *tag)
s_cow * cow_new_copy (const s_cow *src)
{
s_cow *cow;
- assert(src);
cow = alloc(sizeof(s_cow));
if (! cow)
return NULL;
@@ -155,41 +210,50 @@ s_cow * cow_new_copy (const s_cow *src)
return cow;
}
-const s_tag * cow_ro (const s_cow *cow)
+const s_tag * cow_read_only (const s_cow *cow)
{
assert(cow);
- if (cow->w_is_set) {
- // FIXME: get a read lock ?
- return &cow->w;
- }
- return &cow->r;
+ assert(cow->list);
+ if (! list_next(cow->list))
+ if (! cow_freeze(cow))
+ return NULL;
+ return &list_next(cow->list)->tag;
}
-s_tag * cow_rw (s_cow *cow)
+s_tag * cow_read_write (s_cow *cow)
{
- if (! cow->w_is_set &&
- ! cow_thaw(cow))
- return NULL;
- return &cow->w;
+ assert(cow);
+ assert(cow->list);
+ return &cow->list->tag;
}
s_cow * cow_thaw (s_cow *cow)
{
+ s_tag tmp;
assert(cow);
- tag_clean(&cow->w);
- if (! tag_init_copy(&cow->w, &cow->r))
+ assert(cow->list);
+ assert(list_next(cow->list));
+ if (! list_next(cow->list)) {
+ err_puts("cow_thaw: nothing to thaw");
+ assert(! "cow_thaw: nothing to thaw");
+ return NULL;
+ }
+ if (! tag_init_copy(&tmp, &list_next(cow->list)->tag))
return NULL;
- cow->w_is_set = true;
+ tag_clean(&cow->list->tag);
+ cow->list->tag = tmp;
return cow;
}
-s_cow * cow_thaw_tag (s_cow *cow, const s_tag *src)
+s_cow * cow_thaw_copy (s_cow *cow, const s_tag *src)
{
+ s_tag tmp;
assert(cow);
+ assert(cow->list);
assert(src);
- tag_clean(&cow->w);
- if (! tag_init_copy(&cow->w, src))
+ if (! tag_init_copy(&tmp, src))
return NULL;
- cow->w_is_set = true;
+ tag_clean(&cow->list->tag);
+ cow->list->tag = tmp;
return cow;
}
diff --git a/libc3/cow.h b/libc3/cow.h
index 173b9ba..4d4b92a 100644
--- a/libc3/cow.h
+++ b/libc3/cow.h
@@ -14,16 +14,14 @@
* @file cow.h
* @brief Copy on write is a software technique that allows you to have
* read-only access to some memory but still be able to modify it. The
- * read-only data is copied to newly allocated memory when modified.
+ * read-only data is copied to a writable memory area to allow for
+ * modification and can then be turned into read-only memory.
*
- * You can cow_freeze the writable version into read-only memory which
- * cleans the previous read-only value and you must be sure to not
- * access it anymore.
- *
- * Call cow_thaw to restore the writable memory to a copy of the
- * read-only version.
- *
- * Call cow_rw to get a writable s_tag pointer.
+ * Usage :
+ * - cow_init()
+ * - cow_rw() returns a writable tag pointer
+ * - cow_freeze() freeze the writable memory area into a read-only one
+ * - cow_ro() returns the last read-only version that was frozen
*/
#ifndef LIBC3_COW_H
#define LIBC3_COW_H
@@ -42,17 +40,19 @@ s_cow * cow_init_tag_copy (s_cow *cow, const s_tag *src);
/* Heap-allocation functions. Call cow_delete after use. */
void cow_delete (s_cow *cow);
s_cow * cow_new (void);
+s_cow * cow_new_1 (const char *utf8);
s_cow * cow_new_cast (const s_sym * const *type, const s_tag *tag);
s_cow * cow_new_copy (const s_cow *src);
/* Observers. */
s_str * cow_inspect (const s_cow *cow, s_str *dest);
-const s_tag * cow_ro (const s_cow *cow);
+const s_tag * cow_read_only (const s_cow *cow);
+s_tag * cow_read_write (s_cow *cow);
/* Operators. */
s_cow * cow_freeze (s_cow *cow);
s_cow * cow_freeze_copy (s_cow *cow, const s_tag *src);
-s_tag * cow_rw (s_cow *cow);
s_cow * cow_thaw (s_cow *cow);
+s_cow * cow_thaw_copy (s_cow *cow, const s_tag *src);
#endif /* LIBC3_COW_H */
diff --git a/libc3/types.h b/libc3/types.h
index 5b8bc11..0463fcf 100644
--- a/libc3/types.h
+++ b/libc3/types.h
@@ -224,6 +224,11 @@ struct buf_save {
uw wpos;
};
+struct cow {
+ const s_sym *type;
+ s_list *list;
+};
+
struct fact {
const s_tag *subject;
const s_tag *predicate;
@@ -505,12 +510,6 @@ struct complex {
s_tag y;
};
-struct cow {
- s_tag r;
- s_tag w;
- bool w_is_set;
-};
-
struct error_handler
{
s_list *backtrace;