Currently, the HASHMAP iterators stop at the first NULL entry in a
hashmap. This is non-obvious and breaks users like sd-device, which
legitimately store NULL values in a hashmap.
Fix all the iterators by taking a pointer to the value storage, instead of
returning it. The iterators now return a boolean that tells whether the
end of the list was reached.
Current users of HASHMAP_FOREACH() are *NOT* changed to explicitly check
for NULL. If it turns out, there were users that inserted NULL into
hashmaps, but didn't properly check for it during iteration, then we
really want to find those and fix them.
track->modified = false;
track->iterator = ITERATOR_FIRST;
track->modified = false;
track->iterator = ITERATOR_FIRST;
- hashmap_iterate(track->names, &track->iterator, (const void**) &n);
+ hashmap_iterate(track->names, &track->iterator, NULL, (const void**) &n);
if (track->modified)
return NULL;
if (track->modified)
return NULL;
- hashmap_iterate(track->names, &track->iterator, (const void**) &n);
+ hashmap_iterate(track->names, &track->iterator, NULL, (const void**) &n);
}
_public_ const char *sd_device_get_tag_first(sd_device *device) {
}
_public_ const char *sd_device_get_tag_first(sd_device *device) {
assert_return(device, NULL);
(void) device_read_db(device);
assert_return(device, NULL);
(void) device_read_db(device);
device->tags_iterator_generation = device->tags_generation;
device->tags_iterator = ITERATOR_FIRST;
device->tags_iterator_generation = device->tags_generation;
device->tags_iterator = ITERATOR_FIRST;
- return set_iterate(device->tags, &device->tags_iterator);
+ set_iterate(device->tags, &device->tags_iterator, &v);
+ return v;
}
_public_ const char *sd_device_get_tag_next(sd_device *device) {
}
_public_ const char *sd_device_get_tag_next(sd_device *device) {
assert_return(device, NULL);
(void) device_read_db(device);
assert_return(device, NULL);
(void) device_read_db(device);
if (device->tags_iterator_generation != device->tags_generation)
return NULL;
if (device->tags_iterator_generation != device->tags_generation)
return NULL;
- return set_iterate(device->tags, &device->tags_iterator);
+ set_iterate(device->tags, &device->tags_iterator, &v);
+ return v;
}
_public_ const char *sd_device_get_devlink_first(sd_device *device) {
}
_public_ const char *sd_device_get_devlink_first(sd_device *device) {
assert_return(device, NULL);
(void) device_read_db(device);
assert_return(device, NULL);
(void) device_read_db(device);
device->devlinks_iterator_generation = device->devlinks_generation;
device->devlinks_iterator = ITERATOR_FIRST;
device->devlinks_iterator_generation = device->devlinks_generation;
device->devlinks_iterator = ITERATOR_FIRST;
- return set_iterate(device->devlinks, &device->devlinks_iterator);
+ set_iterate(device->devlinks, &device->devlinks_iterator, &v);
+ return v;
}
_public_ const char *sd_device_get_devlink_next(sd_device *device) {
}
_public_ const char *sd_device_get_devlink_next(sd_device *device) {
assert_return(device, NULL);
(void) device_read_db(device);
assert_return(device, NULL);
(void) device_read_db(device);
if (device->devlinks_iterator_generation != device->devlinks_generation)
return NULL;
if (device->devlinks_iterator_generation != device->devlinks_generation)
return NULL;
- return set_iterate(device->devlinks, &device->devlinks_iterator);
+ set_iterate(device->devlinks, &device->devlinks_iterator, &v);
+ return v;
}
static int device_properties_prepare(sd_device *device) {
}
static int device_properties_prepare(sd_device *device) {
device->properties_iterator_generation = device->properties_generation;
device->properties_iterator = ITERATOR_FIRST;
device->properties_iterator_generation = device->properties_generation;
device->properties_iterator = ITERATOR_FIRST;
- value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
+ ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
if (_value)
*_value = value;
if (_value)
*_value = value;
if (device->properties_iterator_generation != device->properties_generation)
return NULL;
if (device->properties_iterator_generation != device->properties_generation)
return NULL;
- value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
+ ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
if (_value)
*_value = value;
if (_value)
*_value = value;
}
_public_ const char *sd_device_get_sysattr_first(sd_device *device) {
}
_public_ const char *sd_device_get_sysattr_first(sd_device *device) {
int r;
assert_return(device, NULL);
int r;
assert_return(device, NULL);
device->sysattrs_iterator = ITERATOR_FIRST;
device->sysattrs_iterator = ITERATOR_FIRST;
- return set_iterate(device->sysattrs, &device->sysattrs_iterator);
+ set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
+ return v;
}
_public_ const char *sd_device_get_sysattr_next(sd_device *device) {
}
_public_ const char *sd_device_get_sysattr_next(sd_device *device) {
assert_return(device, NULL);
if (!device->sysattrs_read)
return NULL;
assert_return(device, NULL);
if (!device->sysattrs_read)
return NULL;
- return set_iterate(device->sysattrs, &device->sysattrs_iterator);
+ set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
+ return v;
}
_public_ int sd_device_has_tag(sd_device *device, const char *tag) {
}
_public_ int sd_device_has_tag(sd_device *device, const char *tag) {
}
_public_ int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value) {
}
_public_ int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value) {
+ const void *k;
+ void *v;
assert_return(hwdb, -EINVAL);
assert_return(key, -EINVAL);
assert_return(hwdb, -EINVAL);
assert_return(key, -EINVAL);
if (hwdb->properties_modified)
return -EAGAIN;
if (hwdb->properties_modified)
return -EAGAIN;
- v = ordered_hashmap_iterate(hwdb->properties, &hwdb->properties_iterator, &k);
+ ordered_hashmap_iterate(hwdb->properties, &hwdb->properties_iterator, &v, &k);
int fdset_iterate(FDSet *s, Iterator *i) {
void *p;
int fdset_iterate(FDSet *s, Iterator *i) {
void *p;
- p = set_iterate(MAKE_SET(s), i);
- if (!p)
+ if (!set_iterate(MAKE_SET(s), i, &p))
return -ENOENT;
return PTR_TO_FD(p);
return -ENOENT;
return PTR_TO_FD(p);
: hashmap_iterate_in_internal_order(h, i);
}
: hashmap_iterate_in_internal_order(h, i);
}
-void *internal_hashmap_iterate(HashmapBase *h, Iterator *i, const void **key) {
+bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) {
struct hashmap_base_entry *e;
void *data;
unsigned idx;
idx = hashmap_iterate_entry(h, i);
if (idx == IDX_NIL) {
struct hashmap_base_entry *e;
void *data;
unsigned idx;
idx = hashmap_iterate_entry(h, i);
if (idx == IDX_NIL) {
+ if (value)
+ *value = NULL;
}
e = bucket_at(h, idx);
data = entry_value(h, e);
}
e = bucket_at(h, idx);
data = entry_value(h, e);
+ if (value)
+ *value = data;
-void *set_iterate(Set *s, Iterator *i) {
- return internal_hashmap_iterate(HASHMAP_BASE(s), i, NULL);
+bool set_iterate(Set *s, Iterator *i, void **value) {
+ return internal_hashmap_iterate(HASHMAP_BASE(s), i, value, NULL);
}
#define HASHMAP_FOREACH_IDX(idx, h, i) \
}
#define HASHMAP_FOREACH_IDX(idx, h, i) \
} Iterator;
#define _IDX_ITERATOR_FIRST (UINT_MAX - 1)
} Iterator;
#define _IDX_ITERATOR_FIRST (UINT_MAX - 1)
+#define _IDX_ITERATOR_NIL (UINT_MAX)
#define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL })
typedef unsigned long (*hash_func_t)(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]);
#define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL })
typedef unsigned long (*hash_func_t)(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]);
return internal_hashmap_buckets(HASHMAP_BASE(h));
}
return internal_hashmap_buckets(HASHMAP_BASE(h));
}
-void *internal_hashmap_iterate(HashmapBase *h, Iterator *i, const void **key);
-static inline void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) {
- return internal_hashmap_iterate(HASHMAP_BASE(h), i, key);
+bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key);
+static inline bool hashmap_iterate(Hashmap *h, Iterator *i, void **value, const void **key) {
+ return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
-static inline void *ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, const void **key) {
- return internal_hashmap_iterate(HASHMAP_BASE(h), i, key);
+static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void **value, const void **key) {
+ return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
}
void internal_hashmap_clear(HashmapBase *h);
}
void internal_hashmap_clear(HashmapBase *h);
* It is safe to remove the current entry.
*/
#define HASHMAP_FOREACH(e, h, i) \
* It is safe to remove the current entry.
*/
#define HASHMAP_FOREACH(e, h, i) \
- for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); \
- (e); \
- (e) = hashmap_iterate((h), &(i), NULL))
+ for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), NULL); )
#define ORDERED_HASHMAP_FOREACH(e, h, i) \
#define ORDERED_HASHMAP_FOREACH(e, h, i) \
- for ((i) = ITERATOR_FIRST, (e) = ordered_hashmap_iterate((h), &(i), NULL); \
- (e); \
- (e) = ordered_hashmap_iterate((h), &(i), NULL))
+ for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), NULL); )
#define HASHMAP_FOREACH_KEY(e, k, h, i) \
#define HASHMAP_FOREACH_KEY(e, k, h, i) \
- for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), (const void**) &(k)); \
- (e); \
- (e) = hashmap_iterate((h), &(i), (const void**) &(k)))
+ for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); )
#define ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \
#define ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \
- for ((i) = ITERATOR_FIRST, (e) = ordered_hashmap_iterate((h), &(i), (const void**) &(k)); \
- (e); \
- (e) = ordered_hashmap_iterate((h), &(i), (const void**) &(k)))
+ for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); )
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free);
return internal_hashmap_buckets(HASHMAP_BASE(s));
}
return internal_hashmap_buckets(HASHMAP_BASE(s));
}
-void *set_iterate(Set *s, Iterator *i);
+bool set_iterate(Set *s, Iterator *i, void **value);
static inline void set_clear(Set *s) {
internal_hashmap_clear(HASHMAP_BASE(s));
static inline void set_clear(Set *s) {
internal_hashmap_clear(HASHMAP_BASE(s));
int set_put_strdupv(Set *s, char **l);
#define SET_FOREACH(e, s, i) \
int set_put_strdupv(Set *s, char **l);
#define SET_FOREACH(e, s, i) \
- for ((i) = ITERATOR_FIRST, (e) = set_iterate((s), &(i)); (e); (e) = set_iterate((s), &(i)))
+ for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); )
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);