- for (node = (gl_list_node_t) list->table[index];
- node != NULL;
- node = (gl_list_node_t) node->h.hash_next)
- if (node->h.hashcode == hashcode
- && (equals != NULL
- ? equals (elt, node->value)
- : elt == node->value))
- {
- if (first_match == NULL)
- first_match = node;
- else
- {
- multiple_matches = true;
- break;
- }
- }
- if (!multiple_matches)
- return first_match;
- else
- {
- /* We need the match with the smallest index. But we don't have
- a fast mapping node -> index. So we have to walk the list. */
- for (node = list->root.next; node != &list->root; node = node->next)
- if (node->h.hashcode == hashcode
- && (equals != NULL
- ? equals (elt, node->value)
- : elt == node->value))
- return node;
- /* We know there are at least two matches. */
- abort ();
- }
- }
+ if (!(start_index <= end_index && end_index <= count))
+ /* Invalid arguments. */
+ abort ();
+ {
+#if WITH_HASHTABLE
+ size_t hashcode =
+ (list->base.hashcode_fn != NULL
+ ? list->base.hashcode_fn (elt)
+ : (size_t)(uintptr_t) elt);
+ size_t bucket = hashcode % list->table_size;
+ gl_listelement_equals_fn equals = list->base.equals_fn;
+
+ if (!list->base.allow_duplicates)
+ {
+ /* Look for the first match in the hash bucket. */
+ gl_list_node_t found = NULL;
+ gl_list_node_t node;
+
+ for (node = (gl_list_node_t) list->table[bucket];
+ node != NULL;
+ node = (gl_list_node_t) node->h.hash_next)
+ if (node->h.hashcode == hashcode
+ && (equals != NULL
+ ? equals (elt, node->value)
+ : elt == node->value))
+ {
+ found = node;
+ break;
+ }
+ if (start_index > 0)
+ /* Look whether found's index is < start_index. */
+ for (node = list->root.next; ; node = node->next)
+ {
+ if (node == found)
+ return NULL;
+ if (--start_index == 0)
+ break;
+ }
+ if (end_index < count)
+ /* Look whether found's index is >= end_index. */
+ {
+ end_index = count - end_index;
+ for (node = list->root.prev; ; node = node->prev)
+ {
+ if (node == found)
+ return NULL;
+ if (--end_index == 0)
+ break;
+ }
+ }
+ return found;
+ }
+ else
+ {
+ /* Look whether there is more than one match in the hash bucket. */
+ bool multiple_matches = false;
+ gl_list_node_t first_match = NULL;
+ gl_list_node_t node;
+
+ for (node = (gl_list_node_t) list->table[bucket];
+ node != NULL;
+ node = (gl_list_node_t) node->h.hash_next)
+ if (node->h.hashcode == hashcode
+ && (equals != NULL
+ ? equals (elt, node->value)
+ : elt == node->value))
+ {
+ if (first_match == NULL)
+ first_match = node;
+ else
+ {
+ multiple_matches = true;
+ break;
+ }
+ }
+ if (multiple_matches)
+ {
+ /* We need the match with the smallest index. But we don't have
+ a fast mapping node -> index. So we have to walk the list. */
+ end_index -= start_index;
+ node = list->root.next;
+ for (; start_index > 0; start_index--)
+ node = node->next;
+
+ for (;
+ end_index > 0;
+ node = node->next, end_index--)
+ if (node->h.hashcode == hashcode
+ && (equals != NULL
+ ? equals (elt, node->value)
+ : elt == node->value))
+ return node;
+ /* The matches must have all been at indices < start_index or
+ >= end_index. */
+ return NULL;
+ }
+ else
+ {
+ if (start_index > 0)
+ /* Look whether first_match's index is < start_index. */
+ for (node = list->root.next; node != &list->root; node = node->next)
+ {
+ if (node == first_match)
+ return NULL;
+ if (--start_index == 0)
+ break;
+ }
+ if (end_index < list->count)
+ /* Look whether first_match's index is >= end_index. */
+ {
+ end_index = list->count - end_index;
+ for (node = list->root.prev; ; node = node->prev)
+ {
+ if (node == first_match)
+ return NULL;
+ if (--end_index == 0)
+ break;
+ }
+ }
+ return first_match;
+ }
+ }