diff --git a/src/data/case.c b/src/data/case.c index dc40292..c577543 100644 --- a/src/data/case.c +++ b/src/data/case.c @@ -30,6 +30,25 @@ #include "minmax.h" #include "xalloc.h" +/* + Enable this flag to copy cases instead of ref counting them. + This is sometimes helpful in debugging situations. +*/ +#define DEBUG_CASEREFS 0 + +#if DEBUG_CASEREFS +#warning Caseref debug enabled. CASES ARE NOT BEING SHARED!! +#endif + +struct ccase + { + struct caseproto *proto; /* Case prototype. */ +#if ! DEBUG_CASEREFS + size_t ref_cnt; /* Reference count. */ +#endif + union value values[1]; /* Values. */ + }; + static size_t case_size (const struct caseproto *); static bool variable_matches_case (const struct ccase *, const struct variable *); @@ -65,7 +84,9 @@ case_try_create (const struct caseproto *proto) if (caseproto_try_init_values (proto, c->values)) { c->proto = caseproto_ref (proto); +#if ! DEBUG_CASEREFS c->ref_cnt = 1; +#endif return c; } free (c); @@ -73,6 +94,53 @@ case_try_create (const struct caseproto *proto) return NULL; } +/* Increments case C's reference count and returns C. Afterward, + case C is shared among its reference count holders. */ +struct ccase * +case_ref (const struct ccase *c_) +{ +#if DEBUG_CASEREFS + return case_unshare__ (CONST_CAST (struct ccase *,c_)); +#else + struct ccase *c = CONST_CAST (struct ccase *, c_); + c->ref_cnt++; + return c; +#endif +} + +/* Decrements case C's reference count. Frees C if its + reference count drops to 0. + + If C is a null pointer, this function has no effect. */ +void +case_unref (struct ccase *c) +{ + if (c != NULL) +#if ! DEBUG_CASEREFS + if (!--c->ref_cnt) +#endif + case_unref__ (c); +} + + +/* Returns true if case C is shared. A case that is shared + cannot be modified directly. Instead, an unshared copy must + first be made with case_unshare(). */ +#if DEBUG_CASEREFS +bool +case_is_shared (const struct ccase *c UNUSED) +{ + return false; +} +#else +bool +case_is_shared (const struct ccase *c) +{ + return c->ref_cnt > 1; +} +#endif + + /* Creates and returns an unshared copy of case C. */ struct ccase * case_clone (const struct ccase *c) @@ -148,7 +216,9 @@ case_unshare_and_resize (struct ccase *c, const struct caseproto *proto) size_t old_n_values = caseproto_get_n_widths (c->proto); size_t new_n_values = caseproto_get_n_widths (proto); case_copy (new, 0, c, 0, MIN (old_n_values, new_n_values)); +#if ! DEBUG_CASEREFS c->ref_cnt--; +#endif return new; } } @@ -420,7 +490,9 @@ case_unshare__ (struct ccase *old) { struct ccase *new = case_create (old->proto); case_copy (new, 0, old, 0, caseproto_get_n_widths (new->proto)); +#if ! DEBUG_CASEREFS --old->ref_cnt; +#endif return new; } @@ -481,3 +553,17 @@ copy_backward (struct ccase *dst, size_t dst_idx, caseproto_get_width (dst->proto, dst_idx + i)); } +/* Returns the number of union values in C. */ +size_t +case_get_value_cnt (const struct ccase *c) +{ + return caseproto_get_n_widths (c->proto); +} + +/* Returns the prototype that describes the format of case C. + The caller must not unref the returned prototype. */ +const struct caseproto * +case_get_proto (const struct ccase *c) +{ + return c->proto; +} diff --git a/src/data/case.h b/src/data/case.h index d00c2ad..5908564 100644 --- a/src/data/case.h +++ b/src/data/case.h @@ -49,24 +49,19 @@ typedef long int casenumber; case, this is undesirable behavior. The case_unshare function provides a solution, by making a new, unshared copy of a shared case. */ -struct ccase - { - struct caseproto *proto; /* Case prototype. */ - size_t ref_cnt; /* Reference count. */ - union value values[1]; /* Values. */ - }; +struct ccase; struct ccase *case_create (const struct caseproto *) MALLOC_LIKE; struct ccase *case_try_create (const struct caseproto *) MALLOC_LIKE; struct ccase *case_clone (const struct ccase *) MALLOC_LIKE; static inline struct ccase *case_unshare (struct ccase *) WARN_UNUSED_RESULT; -static inline struct ccase *case_ref (const struct ccase *); -static inline void case_unref (struct ccase *); -static inline bool case_is_shared (const struct ccase *); +struct ccase *case_ref (const struct ccase *) WARN_UNUSED_RESULT; +void case_unref (struct ccase *); +bool case_is_shared (const struct ccase *); -static inline size_t case_get_value_cnt (const struct ccase *); -static inline const struct caseproto *case_get_proto (const struct ccase *); +size_t case_get_value_cnt (const struct ccase *); +const struct caseproto *case_get_proto (const struct ccase *); size_t case_get_cost (const struct caseproto *); @@ -130,49 +125,7 @@ case_unshare (struct ccase *c) return c; } -/* Increments case C's reference count and returns C. Afterward, - case C is shared among its reference count holders. */ -static inline struct ccase * -case_ref (const struct ccase *c_) -{ - struct ccase *c = CONST_CAST (struct ccase *, c_); - c->ref_cnt++; - return c; -} -/* Decrements case C's reference count. Frees C if its - reference count drops to 0. - If C is a null pointer, this function has no effect. */ -static inline void -case_unref (struct ccase *c) -{ - if (c != NULL && !--c->ref_cnt) - case_unref__ (c); -} - -/* Returns true if case C is shared. A case that is shared - cannot be modified directly. Instead, an unshared copy must - first be made with case_unshare(). */ -static inline bool -case_is_shared (const struct ccase *c) -{ - return c->ref_cnt > 1; -} - -/* Returns the number of union values in C. */ -static inline size_t -case_get_value_cnt (const struct ccase *c) -{ - return caseproto_get_n_widths (c->proto); -} - -/* Returns the prototype that describes the format of case C. - The caller must not unref the returned prototype. */ -static inline const struct caseproto * -case_get_proto (const struct ccase *c) -{ - return c->proto; -} #endif /* data/case.h */