src/hash_map.c

changeset 551
2946e13c89a4
parent 550
89b2a83728b1
child 554
fd3d843b839d
     1.1 --- a/src/hash_map.c	Thu May 19 14:30:20 2022 +0200
     1.2 +++ b/src/hash_map.c	Sat May 21 11:22:47 2022 +0200
     1.3 @@ -175,6 +175,25 @@
     1.4      return 0;
     1.5  }
     1.6  
     1.7 +static void cx_hash_map_unlink(
     1.8 +        struct cx_hash_map_s *hash_map,
     1.9 +        size_t slot,
    1.10 +        struct cx_hash_map_element_s *prev,
    1.11 +        struct cx_hash_map_element_s *elm
    1.12 +) {
    1.13 +    // unlink
    1.14 +    if (prev == NULL) {
    1.15 +        hash_map->buckets[slot] = elm->next;
    1.16 +    } else {
    1.17 +        prev->next = elm->next;
    1.18 +    }
    1.19 +    // free element
    1.20 +    cxFree(hash_map->base.allocator, elm->key.data);
    1.21 +    cxFree(hash_map->base.allocator, elm);
    1.22 +    // decrease size
    1.23 +    hash_map->base.size--;
    1.24 +}
    1.25 +
    1.26  /**
    1.27   * Helper function to avoid code duplication.
    1.28   *
    1.29 @@ -200,17 +219,7 @@
    1.30              if (memcmp(elm->key.data, key.data, key.len) == 0) {
    1.31                  void *data = elm->data;
    1.32                  if (remove) {
    1.33 -                    // unlink
    1.34 -                    if (prev) {
    1.35 -                        prev->next = elm->next;
    1.36 -                    } else {
    1.37 -                        hash_map->buckets[slot] = elm->next;
    1.38 -                    }
    1.39 -                    // free element
    1.40 -                    cxFree(map->allocator, elm->key.data);
    1.41 -                    cxFree(map->allocator, elm);
    1.42 -                    // decrease size
    1.43 -                    map->size--;
    1.44 +                    cx_hash_map_unlink(hash_map, slot, prev, elm);
    1.45                  }
    1.46                  return data;
    1.47              }
    1.48 @@ -237,21 +246,120 @@
    1.49      return cx_hash_map_get_remove(map, key, true);
    1.50  }
    1.51  
    1.52 -static CxIterator cx_hash_map_iterator(CxMap const *map) {
    1.53 +static void *cx_hash_map_iter_current_entry(CxIterator const *iter) {
    1.54 +    // struct has to have a compatible signature
    1.55 +    struct cx_map_entry_s *entry = (struct cx_map_entry_s *) &(iter->kv_data);
    1.56 +    return entry;
    1.57 +}
    1.58 +
    1.59 +static void *cx_hash_map_iter_current_key(CxIterator const *iter) {
    1.60 +    struct cx_hash_map_element_s *elm = iter->elem_handle;
    1.61 +    return &elm->key;
    1.62 +}
    1.63 +
    1.64 +static void *cx_hash_map_iter_current_value(CxIterator const *iter) {
    1.65 +    struct cx_hash_map_element_s *elm = iter->elem_handle;
    1.66 +    // TODO: return a pointer to data if this map is storing copies
    1.67 +    return elm->data;
    1.68 +}
    1.69 +
    1.70 +static bool cx_hash_map_iter_valid(CxIterator const *iter) {
    1.71 +    return iter->elem_handle != NULL;
    1.72 +}
    1.73 +
    1.74 +static void cx_hash_map_iter_next(CxIterator *iter) {
    1.75 +    struct cx_hash_map_s *map = iter->src_handle;
    1.76 +    struct cx_hash_map_element_s *elm = iter->elem_handle;
    1.77 +
    1.78 +    // remove current element, if asked
    1.79 +    if (iter->remove) {
    1.80 +        // clear the flag
    1.81 +        iter->remove = false;
    1.82 +
    1.83 +        // determine the next element
    1.84 +        struct cx_hash_map_element_s *next = elm->next;
    1.85 +
    1.86 +        // search the previous element
    1.87 +        struct cx_hash_map_element_s *prev = NULL;
    1.88 +        if (map->buckets[iter->slot] != elm) {
    1.89 +            prev = map->buckets[iter->slot];
    1.90 +            while (prev->next != elm) {
    1.91 +                prev = prev->next;
    1.92 +            }
    1.93 +        }
    1.94 +
    1.95 +        // unlink
    1.96 +        cx_hash_map_unlink(map, iter->slot, prev, elm);
    1.97 +
    1.98 +        // advance
    1.99 +        elm = next;
   1.100 +    } else {
   1.101 +        // just advance
   1.102 +        elm = elm->next;
   1.103 +    }
   1.104 +
   1.105 +    // do we leave the bucket?
   1.106 +    if (elm == NULL) {
   1.107 +        // search the next bucket
   1.108 +        for (; elm == NULL && iter->slot < map->bucket_count; iter->slot++) {
   1.109 +            elm = map->buckets[iter->slot];
   1.110 +        }
   1.111 +    }
   1.112 +
   1.113 +    // advance the index in any case
   1.114 +    iter->index++;
   1.115 +
   1.116 +    // fill the struct with the current element
   1.117 +    iter->elem_handle = elm;
   1.118 +    if (elm == NULL) {
   1.119 +        iter->kv_data.key = NULL;
   1.120 +        iter->kv_data.value = NULL;
   1.121 +    } else {
   1.122 +        iter->kv_data.key = &elm->key;
   1.123 +        // TODO: pointer to data if this map is storing copies
   1.124 +        iter->kv_data.value = elm->data;
   1.125 +    }
   1.126 +}
   1.127 +
   1.128 +static CxIterator cx_hash_map_iterator(CxMap *map) {
   1.129      CxIterator iter;
   1.130 -    // TODO: initialize iter
   1.131 +
   1.132 +    iter.src_handle = map;
   1.133 +    iter.valid = cx_hash_map_iter_valid;
   1.134 +    iter.next = cx_hash_map_iter_next;
   1.135 +    iter.current = cx_hash_map_iter_current_entry;
   1.136 +
   1.137 +    iter.slot = 0;
   1.138 +    iter.index = 0;
   1.139 +    iter.remove = false;
   1.140 +
   1.141 +    if (map->size > 0) {
   1.142 +        struct cx_hash_map_s *hash_map = (struct cx_hash_map_s *) map;
   1.143 +        struct cx_hash_map_element_s *elem = NULL;
   1.144 +        for (; elem == NULL; iter.slot++) {
   1.145 +            elem = hash_map->buckets[iter.slot];
   1.146 +        }
   1.147 +        iter.elem_handle = elem;
   1.148 +        iter.kv_data.key = NULL;
   1.149 +        iter.kv_data.value = NULL;
   1.150 +    } else {
   1.151 +        iter.elem_handle = NULL;
   1.152 +        iter.kv_data.key = NULL;
   1.153 +        iter.kv_data.value = NULL;
   1.154 +    }
   1.155 +
   1.156      return iter;
   1.157  }
   1.158  
   1.159 -static CxIterator cx_hash_map_iterator_keys(CxMap const *map) {
   1.160 -    CxIterator iter;
   1.161 -    // TODO: initialize iter
   1.162 +static CxIterator cx_hash_map_iterator_keys(CxMap *map) {
   1.163 +    CxIterator iter = cx_hash_map_iterator(map);
   1.164 +    iter.current = cx_hash_map_iter_current_key;
   1.165      return iter;
   1.166  }
   1.167  
   1.168 -static CxIterator cx_hash_map_iterator_values(CxMap const *map) {
   1.169 -    CxIterator iter;
   1.170 -    // TODO: initialize iter
   1.171 +static CxIterator cx_hash_map_iterator_values(CxMap *map) {
   1.172 +    CxIterator iter = cx_hash_map_iterator(map);
   1.173 +    iter.current = cx_hash_map_iter_current_value;
   1.174      return iter;
   1.175  }
   1.176  

mercurial