return a;
#undef _a_at
}
+
+int _darr_search_floor(const void *a, size_t esize, const void *key, bool *equal,
+ darr_search_cmpf cmpf)
+{
+ struct darr_metadata *dm;
+
+ if (equal)
+ *equal = false;
+
+ if (!a)
+ return -1;
+
+ dm = (struct darr_metadata *)a - 1;
+
+ int len = dm->len;
+ int low = 0, high = len - 1;
+ int floor = -1;
+
+#define _a_at(i) ((void *)((char *)a + ((i)*esize)))
+ while (low <= high) {
+ int mid = low + (high - low) / 2;
+ int cmp = cmpf(_a_at(mid), key);
+
+ if (!cmp) {
+ if (equal)
+ *equal = true;
+ return mid;
+ } else if (cmp < 0) {
+ floor = mid;
+ low = mid + 1;
+ } else {
+ high = mid - 1;
+ }
+ }
+
+ return floor;
+#undef _a_at
+}
+
+int _darr_search(const void *a, size_t esize, const void *key, darr_search_cmpf cmpf)
+{
+ bool equal;
+ int i;
+
+ i = _darr_search_floor(a, esize, key, &equal, cmpf);
+ if (!equal)
+ return -1;
+ return i;
+}
+
+uint _darr_search_ceil(const void *a, size_t esize, const void *key, bool *equal,
+ darr_search_cmpf cmpf)
+{
+ uint i;
+
+ i = _darr_search_floor(a, esize, key, equal, cmpf);
+ if (*equal)
+ return i;
+ return i + 1;
+}
+
+int darr_strings_cmp(const char **a, const char *key)
+{
+ return strcmp(*a, key);
+}
* - darr_strlen
* - darr_strlen_fixup
* - darr_strnul
+ * - darr_str_search
+ * - darr_str_search_ceil
+ * - darr_str_search_floor
* - darr_sprintf, darr_vsprintf
*/
/*
d; \
})
+/*
+ * darr_search_{floor,ceil}() functions - search for key in sorted arrays
+ */
+typedef int (*darr_search_cmpf)(const void *ep, const void *key);
+extern int darr_strings_cmp(const char **a, const char *key);
+extern int _darr_search(const void *a, size_t esize, const void *key, darr_search_cmpf cmpf);
+extern uint _darr_search_ceil(const void *a, size_t esize, const void *key, bool *equal,
+ darr_search_cmpf cmpf);
+extern int _darr_search_floor(const void *a, size_t esize, const void *key, bool *equal,
+ darr_search_cmpf cmpf);
+
+/**
+ * darr_str_search() - Find exact key in array of strings.
+ *
+ * Args:
+ * A: array of string pointers
+ * K: key string
+ *
+ * Return:
+ * The index of the string which matches the key or -1 for no match.
+ */
+#define darr_str_search(A, K) \
+ _darr_search((A), _darr_esize(A), (K), (darr_search_cmpf)darr_strings_cmp)
+
+/**
+ * darr_str_search_ceil() - Find least elm greater than or equal to the key
+ *
+ * Args:
+ * A: array of string pointers
+ * K: key string
+ * E: Ptr to bool, set to true if element matching key is found
+ *
+ * Return:
+ * The index of the least element that is greater than or equal to the @K
+ * string. @E is set to true if equal otherwise false. The return value can
+ * be passed directly to darr_insert().
+ */
+#define darr_str_search_ceil(A, K, E) \
+ _darr_search_ceil((A), _darr_esize(A), (K), (E), (darr_search_cmpf)darr_strings_cmp)
+
+/**
+ * darr_str_search_floor() - Find greatest elm less than or equal to the key
+ *
+ * Args:
+ * A: array of string pointers
+ * K: key string
+ * E: Ptr to bool, set to true if element matching key is found
+ *
+ * Return:
+ * The index of the greatest element that is less than or equal to the @K
+ * string. @E is set to true if equal otherwise false. If used with
+ * darr_insert() then the index should be passed +1 because darr_insert()
+ * inserts *before* the given index.
+ */
+#define darr_str_search_floor(A, K, E) \
+ _darr_search_floor((A), _darr_esize(A), (K), (E), (darr_search_cmpf)darr_strings_cmp)
+
/**
* Iterate over array `A` using a pointer to each element in `P`.
*
* [x] - darr_strlen
* [x] - darr_strlen_fixup
* [x] - darr_strnul
+ * [x] - darr_str_search
+ * [x] - darr_str_search_ceil
+ * [x] - darr_str_search_floor
* [ ] - darr_vsprintf
*/
const char **strings = NULL;
uint sum = 0;
uint i;
+ bool b;
+ int idx;
i = darr_strlen(da1);
assert(i == 0);
darr_free_free(strings);
assert(strings == NULL);
+
+ add = darr_strdup("5");
+ i = darr_str_search_ceil(strings, add, &b);
+ assert(!b);
+ *darr_insert(strings, i) = add;
+
+ add = darr_strdup("2");
+ i = darr_str_search_ceil(strings, add, &b);
+ assert(!b);
+ *darr_insert(strings, i) = add;
+
+ add = darr_strdup("9");
+ i = darr_str_search_ceil(strings, add, &b);
+ assert(!b);
+ *darr_insert(strings, i) = add;
+
+ add = darr_strdup("3");
+ i = darr_str_search_ceil(strings, add, &b);
+ assert(!b);
+ *darr_insert(strings, i) = add;
+
+ i = darr_str_search_ceil(strings, "0", &b);
+ assert(!b);
+ assert(i == 0);
+ i = darr_str_search_ceil(strings, "1", &b);
+ assert(!b);
+ assert(i == 0);
+ i = darr_str_search_ceil(strings, "2", &b);
+ assert(b);
+ assert(i == 0);
+ i = darr_str_search_ceil(strings, "3", &b);
+ assert(b);
+ assert(i == 1);
+ i = darr_str_search_ceil(strings, "4", &b);
+ assert(!b);
+ assert(i == 2);
+ i = darr_str_search_ceil(strings, "5", &b);
+ assert(b);
+ assert(i == 2);
+ i = darr_str_search_ceil(strings, "6", &b);
+ assert(!b);
+ assert(i == 3);
+ i = darr_str_search_ceil(strings, "7", &b);
+ assert(!b);
+ assert(i == 3);
+ i = darr_str_search_ceil(strings, "8", &b);
+ assert(!b);
+ assert(i == 3);
+ i = darr_str_search_ceil(strings, "9", &b);
+ assert(b);
+ assert(i == 3);
+ i = darr_str_search_ceil(strings, "X", &b);
+ assert(!b);
+ assert(i == 4);
+
+ assert(!strcmp(strings[0], "2"));
+ assert(!strcmp(strings[1], "3"));
+ assert(!strcmp(strings[2], "5"));
+ assert(!strcmp(strings[3], "9"));
+
+ darr_free_free(strings);
+ assert(strings == NULL);
+
+ /* -------------------- */
+ /* Test sorted prefixes */
+ /* -------------------- */
+
+ add = darr_strdup("/foo");
+ i = darr_str_search_ceil(strings, add, &b);
+ assert(!b);
+ *darr_insert(strings, i) = add;
+
+ add = darr_strdup("/bar");
+ i = darr_str_search_ceil(strings, add, &b);
+ assert(!b);
+ *darr_insert(strings, i) = add;
+
+ add = darr_strdup("/abc");
+ i = darr_str_search_ceil(strings, add, &b);
+ assert(!b);
+ *darr_insert(strings, i) = add;
+
+ add = darr_strdup("/xyz/abc");
+ i = darr_str_search_ceil(strings, add, &b);
+ assert(!b);
+ *darr_insert(strings, i) = add;
+
+ add = darr_strdup("/foo/bar");
+ i = darr_str_search_ceil(strings, add, &b);
+ assert(!b);
+ *darr_insert(strings, i) = add;
+
+ i = darr_str_search_ceil(strings, "/abc", &b);
+ assert(i == 0 && b);
+ i = darr_str_search_ceil(strings, "/bar", &b);
+ assert(i == 1 && b);
+ i = darr_str_search_ceil(strings, "/foo", &b);
+ assert(i == 2 && b);
+ i = darr_str_search_ceil(strings, "/foo/bar", &b);
+ assert(i == 3 && b);
+ i = darr_str_search_ceil(strings, "/xyz/abc", &b);
+ assert(i == 4 && b);
+
+ idx = darr_str_search(strings, "/abc");
+ assert(idx == 0);
+ idx = darr_str_search(strings, "/abc/123");
+ assert(idx == -1);
+ idx = darr_str_search(strings, "/xyz");
+ assert(idx == -1);
+ idx = darr_str_search(strings, "/xyz/abc");
+ assert(idx == 4);
+
+ assert(!strcmp(strings[0], "/abc"));
+ assert(!strcmp(strings[1], "/bar"));
+ assert(!strcmp(strings[2], "/foo"));
+ assert(!strcmp(strings[3], "/foo/bar"));
+ assert(!strcmp(strings[4], "/xyz/abc"));
+
+ darr_free_free(strings);
+ assert(strings == NULL);
}
int main(int argc, char **argv)