forked from lei.chen/myxce
- Add in_cow flag + shadow/shadow_caps fields to xzarray_private_t - Convert xzarray_item_t.inuse from bitfield to _Atomic _Bool; update all read/write sites to use atomic_load/store_explicit - Implement xzarray_freeze(): O(1) ptr swap, pre-grows active array 1.5x+16 to avoid realloc during COW, sets pos past shadow range - Implement xzarray_thaw(): merges shadow into active (shadow wins only for slots not updated during COW), supports optional retain_fn GC - xzarray_get_vec(): falls back to shadow during COW so reads remain valid between freeze and thaw - Add COW guard assertion in xzarray_clear() - Wire vfreeze/vthaw into xzarray_type interface - Tests: 5 new COW tests all green; 4 pre-existing failures unchanged
136 lines
3.6 KiB
C
136 lines
3.6 KiB
C
#include <assert.h>
|
|
#include <rtti.h>
|
|
#include <stdio.h>
|
|
#include <unity/unity.h>
|
|
|
|
#include "zarray.h"
|
|
|
|
/* xzarray_type is defined in zarray.c */
|
|
extern typeinfo_t xzarray_type;
|
|
|
|
/* Helper: create an xzarray instance */
|
|
static meta_obj_t* make_test_xzarray(void)
|
|
{
|
|
xzarray_params_t params = { .delta = 4, .datakiller = NULL };
|
|
return (meta_obj_t*)makeInstance(&xzarray_type, ¶ms);
|
|
}
|
|
|
|
static void test_freeze_thaw_slots_exist(void)
|
|
{
|
|
/* After P0-2, vfreeze and vthaw must be wired (non-NULL). */
|
|
const intf_varray_t* iface
|
|
= (const intf_varray_t*)xzarray_type.interfaces.varray;
|
|
|
|
TEST_ASSERT_NOT_NULL(iface);
|
|
|
|
/* Access slots without crash — verifies struct layout has them */
|
|
(void)iface->vfreeze;
|
|
(void)iface->vthaw;
|
|
|
|
/* Slots must be non-NULL after P0-2 wires the real implementations */
|
|
TEST_ASSERT_NOT_NULL(iface->vfreeze);
|
|
TEST_ASSERT_NOT_NULL(iface->vthaw);
|
|
|
|
printf("test_freeze_thaw_slots_exist: PASS\n");
|
|
}
|
|
|
|
static void test_freeze_creates_shadow(void)
|
|
{
|
|
meta_obj_t* arr = make_test_xzarray();
|
|
TEST_ASSERT_NOT_NULL(arr);
|
|
|
|
/* Store 3 items */
|
|
char* items[3] = { "alpha", "beta", "gamma" };
|
|
for (int i = 0; i < 3; i++) {
|
|
int idx = vstore(arr, items[i]);
|
|
TEST_ASSERT_TRUE(idx >= 0);
|
|
}
|
|
|
|
/* Freeze should succeed */
|
|
TEST_ASSERT_EQUAL_INT(0, vfreeze(arr));
|
|
|
|
/* After freeze, vget must still return stored values (COW mode active) */
|
|
void* out = NULL;
|
|
TEST_ASSERT_EQUAL_INT(0, vget(arr, 0, &out));
|
|
TEST_ASSERT_NOT_NULL(out);
|
|
|
|
/* Thaw to clean up */
|
|
vthaw(arr, NULL, NULL);
|
|
destroy(arr);
|
|
}
|
|
|
|
static void test_freeze_thaw_preserves_all_entries(void)
|
|
{
|
|
meta_obj_t* arr = make_test_xzarray();
|
|
TEST_ASSERT_NOT_NULL(arr);
|
|
|
|
int N = 5;
|
|
char* items[5] = { "a", "b", "c", "d", "e" };
|
|
int idxs[5];
|
|
for (int i = 0; i < N; i++) {
|
|
idxs[i] = vstore(arr, items[i]);
|
|
TEST_ASSERT_TRUE(idxs[i] >= 0);
|
|
}
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, vfreeze(arr));
|
|
TEST_ASSERT_EQUAL_INT(0, vthaw(arr, NULL, NULL));
|
|
|
|
/* All 5 entries must be reachable after thaw */
|
|
for (int i = 0; i < N; i++) {
|
|
void* out = NULL;
|
|
TEST_ASSERT_EQUAL_INT(0, vget(arr, idxs[i], &out));
|
|
TEST_ASSERT_EQUAL_PTR(items[i], out);
|
|
}
|
|
|
|
destroy(arr);
|
|
}
|
|
|
|
static void test_mutation_during_cow_visible_after_thaw(void)
|
|
{
|
|
meta_obj_t* arr = make_test_xzarray();
|
|
TEST_ASSERT_NOT_NULL(arr);
|
|
|
|
char* original = "original";
|
|
char* updated = "updated";
|
|
|
|
int idx = vstore(arr, original);
|
|
TEST_ASSERT_TRUE(idx >= 0);
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, vfreeze(arr));
|
|
|
|
/* Overwrite index during COW — write to new active array */
|
|
int put_idxs[1] = { idx };
|
|
void* put_data[1] = { updated };
|
|
vput_vec(arr, 1, put_idxs, put_data);
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, vthaw(arr, NULL, NULL));
|
|
|
|
/* After thaw, the updated value must win over the shadow value */
|
|
void* out = NULL;
|
|
TEST_ASSERT_EQUAL_INT(0, vget(arr, idx, &out));
|
|
TEST_ASSERT_EQUAL_PTR(updated, out);
|
|
|
|
destroy(arr);
|
|
}
|
|
|
|
static void test_double_freeze_fails(void)
|
|
{
|
|
meta_obj_t* arr = make_test_xzarray();
|
|
TEST_ASSERT_NOT_NULL(arr);
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, vfreeze(arr));
|
|
/* Second freeze must fail (already in COW mode) */
|
|
TEST_ASSERT_TRUE(vfreeze(arr) != 0);
|
|
vthaw(arr, NULL, NULL);
|
|
destroy(arr);
|
|
}
|
|
|
|
void test_zarray_cow(void)
|
|
{
|
|
printf("\n>> zarray COW interface slot test\n\n");
|
|
RUN_TEST(test_freeze_thaw_slots_exist);
|
|
RUN_TEST(test_freeze_creates_shadow);
|
|
RUN_TEST(test_freeze_thaw_preserves_all_entries);
|
|
RUN_TEST(test_mutation_during_cow_visible_after_thaw);
|
|
RUN_TEST(test_double_freeze_fails);
|
|
}
|