mruby-set: Simplify code with convenience macros and cleanup

Add convenience macros to reduce code duplication and improve readability:

- kset_is_uninitialized(s) for checking uninitialized sets
- kset_is_empty(s) for checking empty sets
- KSET_FOREACH(s, k) for iterating over set elements

Replace repetitive manual checks and for-loops throughout the codebase
with these macros.

Implemented by: Rovo Dev
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-06-25 11:08:33 +09:00
parent a82911b35f
commit 0d1c22150e
+56 -54
View File
@@ -31,9 +31,9 @@ static const uint8_t kset_empty_mask[] = {0x02, 0x08, 0x20, 0x80};
static const uint8_t kset_del_mask[] = {0x01, 0x04, 0x10, 0x40};
static const uint8_t kset_either_mask[] = {0x03, 0x0c, 0x30, 0xc0};
#define kset_is_empty(flags, i) (flags[(i)/4] & kset_empty_mask[(i)%4])
#define kset_is_del(flags, i) (flags[(i)/4] & kset_del_mask[(i)%4])
#define kset_is_either(flags, i) (flags[(i)/4] & kset_either_mask[(i)%4])
#define KSET_IS_EMPTY(flags, i) (flags[(i)/4] & kset_empty_mask[(i)%4])
#define KSET_IS_DEL(flags, i) (flags[(i)/4] & kset_del_mask[(i)%4])
#define KSET_IS_EITHER(flags, i) (flags[(i)/4] & kset_either_mask[(i)%4])
#define kset_power2(v) do { \
v--; \
@@ -74,6 +74,15 @@ static kset_t* kset_init_size(mrb_state *mrb, kset_int_t size);
static kset_iter_t kset_put(mrb_state *mrb, kset_t *s, mrb_value key);
static kset_iter_t kset_put2(mrb_state *mrb, kset_t *s, mrb_value key, int *ret);
/* Convenience macros for common operations */
#define kset_is_uninitialized(s) (!(s)->data)
#define kset_is_empty(s) (!(s)->data || (s)->size == 0)
/* Macro for iterating over all elements in a kset */
#define KSET_FOREACH(s, k) \
for (kset_iter_t k = 0; k != kset_end(s); k++) \
if (kset_exist(s, k))
/* Hash function for mrb_value */
static inline kset_int_t
kset_hash_value(mrb_state *mrb, mrb_value key)
@@ -152,8 +161,8 @@ kset_get(mrb_state *mrb, kset_t *s, mrb_value key)
uint8_t *flags = kset_flags(s);
mrb_value *keys = kset_keys(s);
while (!kset_is_empty(flags, k)) {
if (!kset_is_del(flags, k)) {
while (!KSET_IS_EMPTY(flags, k)) {
if (!KSET_IS_DEL(flags, k)) {
if (kset_equal_value(mrb, keys[k], key)) {
return k;
}
@@ -190,7 +199,7 @@ kset_resize(mrb_state *mrb, kset_t *s, kset_int_t new_n_buckets)
/* Rehash old elements */
for (kset_int_t i = 0; i < old_n_buckets; i++) {
if (!kset_is_either(old_flags, i)) {
if (!KSET_IS_EITHER(old_flags, i)) {
kset_put(mrb, s, old_keys[i]);
}
}
@@ -222,8 +231,8 @@ kset_put2(mrb_state *mrb, kset_t *s, mrb_value key, int *ret)
uint8_t *flags = kset_flags(s);
mrb_value *keys = kset_keys(s);
while (!kset_is_empty(flags, k)) {
if (!kset_is_del(flags, k)) {
while (!KSET_IS_EMPTY(flags, k)) {
if (!KSET_IS_DEL(flags, k)) {
if (kset_equal_value(mrb, keys[k], key)) {
if (ret) *ret = 0; /* Key already exists */
return k;
@@ -258,7 +267,7 @@ static void
kset_del(mrb_state *mrb, kset_t *s, kset_iter_t x)
{
(void)mrb;
mrb_assert(x != s->n_buckets && !kset_is_either(kset_flags(s), x));
mrb_assert(x != s->n_buckets && !KSET_IS_EITHER(kset_flags(s), x));
kset_flags(s)[x/4] |= kset_del_mask[x%4];
s->size--;
}
@@ -267,7 +276,7 @@ kset_del(mrb_state *mrb, kset_t *s, kset_iter_t x)
static inline mrb_bool
kset_exist(kset_t *s, kset_iter_t x)
{
return !kset_is_either(kset_flags(s), x);
return !KSET_IS_EITHER(kset_flags(s), x);
}
/* Get key at iterator */
@@ -318,11 +327,9 @@ kset_copy_elements(mrb_state *mrb, kset_t *target, kset_t *source)
if (!source || !target) return;
int ai = mrb_gc_arena_save(mrb);
for (kset_iter_t k = 0; k != kset_end(source); k++) {
if (kset_exist(source, k)) {
kset_put(mrb, target, kset_key(source, k));
mrb_gc_arena_restore(mrb, ai);
}
KSET_FOREACH(source, k) {
kset_put(mrb, target, kset_key(source, k));
mrb_gc_arena_restore(mrb, ai);
}
}
@@ -357,12 +364,10 @@ mrb_gc_mark_set(mrb_state *mrb, struct RBasic *obj)
{
struct RSet *s = (struct RSet*)obj;
kset_t *set = &s->set;
if (!set->data) return 0;
if (kset_is_empty(set)) return 0;
for (kset_iter_t k = 0; k != kset_end(set); k++) {
if (kset_exist(set, k)) {
mrb_gc_mark_value(mrb, kset_key(set, k));
}
KSET_FOREACH(set, k) {
mrb_gc_mark_value(mrb, kset_key(set, k));
}
return set->size;
}
@@ -429,7 +434,7 @@ set_init_copy(mrb_state *mrb, mrb_value self)
}
kset_t *orig_set = set_get_kset(mrb, orig);
if (!orig_set->data) {
if (kset_is_uninitialized(orig_set)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid Set object");
}
@@ -451,7 +456,7 @@ static mrb_value
set_size(mrb_state *mrb, mrb_value self)
{
kset_t *set = set_get_kset(mrb, self);
if (!set->data) return mrb_fixnum_value(0);
if (kset_is_empty(set)) return mrb_fixnum_value(0);
return mrb_fixnum_value(set->size);
}
@@ -465,8 +470,7 @@ static mrb_value
set_empty_p(mrb_state *mrb, mrb_value self)
{
kset_t *set = set_get_kset(mrb, self);
if (!set->data) return mrb_true_value();
return mrb_bool_value(set->size == 0);
return mrb_bool_value(kset_is_empty(set));
}
/*
@@ -479,7 +483,7 @@ static mrb_value
set_clear(mrb_state *mrb, mrb_value self)
{
kset_t *set = set_get_kset(mrb, self);
if (set->data) {
if (!kset_is_empty(set)) {
kset_clear(mrb, set);
}
return self;
@@ -496,16 +500,14 @@ set_to_a(mrb_state *mrb, mrb_value self)
{
kset_t *set = set_get_kset(mrb, self);
if (!set->data) return mrb_ary_new(mrb);
if (kset_is_empty(set)) return mrb_ary_new(mrb);
mrb_value ary = mrb_ary_new_capa(mrb, set->size);
int ai = mrb_gc_arena_save(mrb);
for (kset_iter_t k = 0; k != kset_end(set); k++) {
if (kset_exist(set, k)) {
mrb_ary_push(mrb, ary, kset_key(set, k));
mrb_gc_arena_restore(mrb, ai);
}
KSET_FOREACH(set, k) {
mrb_ary_push(mrb, ary, kset_key(set, k));
mrb_gc_arena_restore(mrb, ai);
}
return ary;
@@ -524,7 +526,7 @@ set_include_p(mrb_state *mrb, mrb_value self)
{
mrb_value obj = mrb_get_arg1(mrb);
kset_t *set = set_get_kset(mrb, self);
if (!set->data) return mrb_false_value();
if (kset_is_empty(set)) return mrb_false_value();
kset_iter_t k = kset_get(mrb, set, obj);
return mrb_bool_value(k != kset_end(set));
@@ -542,7 +544,7 @@ set_add(mrb_state *mrb, mrb_value self)
{
mrb_value obj = mrb_get_arg1(mrb);
kset_t *set = set_get_kset(mrb, self);
if (!set->data) {
if (kset_is_uninitialized(set)) {
mrb_raise(mrb, E_RUNTIME_ERROR, "uninitialized Set");
}
@@ -562,7 +564,7 @@ set_add_p(mrb_state *mrb, mrb_value self)
{
mrb_value obj = mrb_get_arg1(mrb);
kset_t *set = set_get_kset(mrb, self);
if (!set->data) {
if (kset_is_uninitialized(set)) {
mrb_raise(mrb, E_RUNTIME_ERROR, "uninitialized Set");
}
@@ -589,7 +591,7 @@ set_delete(mrb_state *mrb, mrb_value self)
{
mrb_value obj = mrb_get_arg1(mrb);
kset_t *set = set_get_kset(mrb, self);
if (!set->data) return self;
if (kset_is_empty(set)) return self;
kset_iter_t k = kset_get(mrb, set, obj);
if (k != kset_end(set)) {
@@ -610,7 +612,7 @@ set_delete_p(mrb_state *mrb, mrb_value self)
{
mrb_value obj = mrb_get_arg1(mrb);
kset_t *set = set_get_kset(mrb, self);
if (!set->data) return mrb_nil_value();
if (kset_is_empty(set)) return mrb_nil_value();
kset_iter_t k = kset_get(mrb, set, obj);
if (k != kset_end(set)) {
@@ -632,12 +634,12 @@ set_core_merge(mrb_state *mrb, mrb_value self)
mrb_value other = mrb_get_arg1(mrb);
kset_t *self_set = set_get_kset(mrb, self);
if (!self_set->data) {
if (kset_is_uninitialized(self_set)) {
mrb_raise(mrb, E_RUNTIME_ERROR, "uninitialized Set");
}
kset_t *other_set = set_get_kset(mrb, other);
if (!other_set->data) return self;
if (kset_is_empty(other_set)) return self;
/* Add all elements from other set */
kset_copy_elements(mrb, self_set, other_set);
@@ -655,10 +657,10 @@ set_core_subtract(mrb_state *mrb, mrb_value self)
mrb_value other = mrb_get_arg1(mrb);
kset_t *self_set = set_get_kset(mrb, self);
if (!self_set->data) return self;
if (kset_is_empty(self_set)) return self;
kset_t *other_set = set_get_kset(mrb, other);
if (!other_set->data) return self;
if (kset_is_empty(other_set)) return self;
/* Remove all elements that are in other set */
for (kset_iter_t k = 0; k != kset_end(other_set); k++) {
@@ -781,7 +783,7 @@ set_core_xor(mrb_state *mrb, mrb_value self)
kset_t *self_kh = set_get_kset(mrb, self);
kset_t *other_kh = set_get_kset(mrb, other);
if (!self_kh->data || self_kh->size == 0) {
if (kset_is_empty(self_kh)) {
/* If self is empty, return a copy of other */
if (other_kh->data) {
kset_copy_elements(mrb, result_kh, other_kh);
@@ -789,7 +791,7 @@ set_core_xor(mrb_state *mrb, mrb_value self)
return result_set;
}
if (!other_kh->data || other_kh->size == 0) {
if (kset_is_empty(other_kh)) {
/* If other is empty, return a copy of self */
kset_copy_elements(mrb, result_kh, self_kh);
return result_set;
@@ -937,7 +939,7 @@ set_superset_p(mrb_state *mrb, mrb_value self)
kset_t *other_kh = set_get_kset(mrb, other);
/* Handle empty sets */
if (!other_kh->data || other_kh->size == 0) {
if (kset_is_empty(other_kh)) {
return mrb_true_value(); /* Empty set is a subset of any set */
}
@@ -982,7 +984,7 @@ set_proper_superset_p(mrb_state *mrb, mrb_value self)
kset_t *other_kh = set_get_kset(mrb, other);
/* Handle empty sets */
if (!other_kh->data || other_kh->size == 0) {
if (kset_is_empty(other_kh)) {
/* Empty set is a proper subset of any non-empty set */
return self_kh->data && self_kh->size > 0 ? mrb_true_value() : mrb_false_value();
}
@@ -1028,7 +1030,7 @@ set_subset_p(mrb_state *mrb, mrb_value self)
kset_t *other_kh = set_get_kset(mrb, other);
/* Handle empty sets */
if (!self_kh->data || self_kh->size == 0) {
if (kset_is_empty(self_kh)) {
return mrb_true_value(); /* Empty set is a subset of any set */
}
@@ -1073,7 +1075,7 @@ set_proper_subset_p(mrb_state *mrb, mrb_value self)
kset_t *other_kh = set_get_kset(mrb, other);
/* Handle empty sets */
if (!self_kh->data || self_kh->size == 0) {
if (kset_is_empty(self_kh)) {
/* Empty set is a proper subset of any non-empty set */
return other_kh->data && other_kh->size > 0 ? mrb_true_value() : mrb_false_value();
}
@@ -1118,7 +1120,7 @@ set_intersect_p(mrb_state *mrb, mrb_value self)
kset_t *other_kh = set_get_kset(mrb, other);
/* Handle empty sets */
if (!self_kh->data || !other_kh->data || self_kh->size == 0 || other_kh->size == 0) {
if (kset_is_empty(self_kh) || kset_is_empty(other_kh)) {
return mrb_false_value(); /* Empty sets have no elements in common */
}
@@ -1182,14 +1184,14 @@ set_cmp(mrb_state *mrb, mrb_value self)
kset_t *other_kh = set_get_kset(mrb, other);
/* Handle empty sets */
if (!self_kh->data || self_kh->size == 0) {
if (!other_kh->data || other_kh->size == 0) {
if (kset_is_empty(self_kh)) {
if (kset_is_empty(other_kh)) {
return mrb_fixnum_value(0); /* Both empty, they're equal */
}
return mrb_fixnum_value(-1); /* Empty set is a proper subset of any non-empty set */
}
if (!other_kh->data || other_kh->size == 0) {
if (kset_is_empty(other_kh)) {
return mrb_fixnum_value(1); /* Any non-empty set is a proper superset of an empty set */
}
@@ -1265,7 +1267,7 @@ set_join(mrb_state *mrb, mrb_value self)
mrb_get_args(mrb, "|S", &separator);
kset_t *kh = set_get_kset(mrb, self);
if (!kh->data || kh->size == 0) {
if (kset_is_empty(kh)) {
return mrb_str_new_lit(mrb, "");
}
@@ -1320,7 +1322,7 @@ set_inspect(mrb_state *mrb, mrb_value self)
kset_t *kh = set_get_kset(mrb, self);
/* Handle empty set */
if (!kh->data || kh->size == 0) {
if (kset_is_empty(kh)) {
return mrb_format(mrb, "%s[]", classname);
}
@@ -1490,7 +1492,7 @@ set_flatten(mrb_state *mrb, mrb_value self)
kset_t *self_kh = set_get_kset(mrb, self);
/* Fast path for empty sets */
if (!self_kh->data || self_kh->size == 0) {
if (kset_is_empty(self_kh)) {
return mrb_obj_new(mrb, mrb_obj_class(mrb, self), 0, NULL);
}
@@ -1538,7 +1540,7 @@ set_flatten_bang(mrb_state *mrb, mrb_value self)
mrb_check_frozen_value(mrb, self);
kset_t *self_kh = set_get_kset(mrb, self);
if (!self_kh->data || self_kh->size == 0) {
if (kset_is_empty(self_kh)) {
return mrb_nil_value(); /* No changes needed for empty set */
}