[RFC2 Patch 2/5] lib: private string map (associative array) API
authorDavid Bremner <david@tethera.net>
Mon, 30 May 2016 11:49:56 +0000 (08:49 +2100)
committerW. Trevor King <wking@tremily.us>
Sat, 20 Aug 2016 23:21:54 +0000 (16:21 -0700)
3d/1c1119659ef0dfbbfa6ef64848ffaed4a00309 [new file with mode: 0644]

diff --git a/3d/1c1119659ef0dfbbfa6ef64848ffaed4a00309 b/3d/1c1119659ef0dfbbfa6ef64848ffaed4a00309
new file mode 100644 (file)
index 0000000..0b24162
--- /dev/null
@@ -0,0 +1,255 @@
+Return-Path: <bremner@tethera.net>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by arlo.cworth.org (Postfix) with ESMTP id 9A09E6DE01D0\r
+ for <notmuch@notmuchmail.org>; Mon, 30 May 2016 04:50:20 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at cworth.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -0.012\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-0.012 tagged_above=-999 required=5\r
+ tests=[AWL=-0.001, SPF_PASS=-0.001, T_RP_MATCHES_RCVD=-0.01]\r
+ autolearn=disabled\r
+Received: from arlo.cworth.org ([127.0.0.1])\r
+ by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id 3L7Li1OgWIgs for <notmuch@notmuchmail.org>;\r
+ Mon, 30 May 2016 04:50:11 -0700 (PDT)\r
+Received: from fethera.tethera.net (fethera.tethera.net [198.245.60.197])\r
+ by arlo.cworth.org (Postfix) with ESMTPS id 842D16DE0261\r
+ for <notmuch@notmuchmail.org>; Mon, 30 May 2016 04:50:11 -0700 (PDT)\r
+Received: from remotemail by fethera.tethera.net with local (Exim 4.84)\r
+ (envelope-from <bremner@tethera.net>)\r
+ id 1b7Lhn-0000Oz-VM; Mon, 30 May 2016 07:50:00 -0400\r
+Received: (nullmailer pid 14850 invoked by uid 1000);\r
+ Mon, 30 May 2016 11:50:06 -0000\r
+From: David Bremner <david@tethera.net>\r
+To: notmuch@notmuchmail.org\r
+Subject: [RFC2 Patch 2/5] lib: private string map (associative array) API\r
+Date: Mon, 30 May 2016 08:49:56 -0300\r
+Message-Id: <1464608999-14774-3-git-send-email-david@tethera.net>\r
+X-Mailer: git-send-email 2.8.1\r
+In-Reply-To: <1464608999-14774-1-git-send-email-david@tethera.net>\r
+References: <1463927339-5441-1-git-send-email-david@tethera.net>\r
+ <1464608999-14774-1-git-send-email-david@tethera.net>\r
+MIME-Version: 1.0\r
+Content-Type: text/plain; charset=UTF-8\r
+Content-Transfer-Encoding: 8bit\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.20\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <https://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch/>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <https://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Mon, 30 May 2016 11:50:20 -0000\r
+\r
+The choice of array implementation is deliberate, for future iterator support\r
+---\r
+ lib/Makefile.local    |   1 +\r
+ lib/notmuch-private.h |  11 ++++\r
+ lib/string-map.c      | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++\r
+ 3 files changed, 165 insertions(+)\r
+ create mode 100644 lib/string-map.c\r
+\r
+diff --git a/lib/Makefile.local b/lib/Makefile.local\r
+index beb9635..9280880 100644\r
+--- a/lib/Makefile.local\r
++++ b/lib/Makefile.local\r
+@@ -40,6 +40,7 @@ libnotmuch_c_srcs =          \\r
+       $(dir)/messages.c       \\r
+       $(dir)/sha1.c           \\r
+       $(dir)/built-with.c     \\r
++      $(dir)/string-map.c    \\r
+       $(dir)/tags.c\r
\r
+ libnotmuch_cxx_srcs =         \\r
+diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h\r
+index 6f9af91..531b82f 100644\r
+--- a/lib/notmuch-private.h\r
++++ b/lib/notmuch-private.h\r
+@@ -540,6 +540,17 @@ _notmuch_string_list_sort (notmuch_string_list_t *list);\r
+ /* string-map.c */\r
+ typedef struct _notmuch_string_map  notmuch_string_map_t;\r
\r
++notmuch_string_map_t *\r
++_notmuch_string_map_create (const void *ctx);\r
++\r
++void\r
++_notmuch_string_map_append (notmuch_string_map_t *map,\r
++                          const char *key,\r
++                          const char *value);\r
++\r
++const char *\r
++_notmuch_string_map_get (notmuch_string_map_t *map, const char *key);\r
++\r
+ /* tags.c */\r
\r
+ notmuch_tags_t *\r
+diff --git a/lib/string-map.c b/lib/string-map.c\r
+new file mode 100644\r
+index 0000000..0491a10\r
+--- /dev/null\r
++++ b/lib/string-map.c\r
+@@ -0,0 +1,153 @@\r
++/* string-map.c - associative arrays of strings\r
++ *\r
++ *\r
++ * Copyright © 2016 David Bremner\r
++ *\r
++ * This program is free software: you can redistribute it and/or modify\r
++ * it under the terms of the GNU General Public License as published by\r
++ * the Free Software Foundation, either version 3 of the License, or\r
++ * (at your option) any later version.\r
++ *\r
++ * This program is distributed in the hope that it will be useful,\r
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
++ * GNU General Public License for more details.\r
++ *\r
++ * You should have received a copy of the GNU General Public License\r
++ * along with this program.  If not, see http://www.gnu.org/licenses/ .\r
++ *\r
++ * Author: David Bremner <david@tethera.net>\r
++ */\r
++\r
++#include "notmuch-private.h"\r
++\r
++/* Create a new notmuch_string_map_t object, with 'ctx' as its\r
++ * talloc owner.\r
++ *\r
++ * This function can return NULL in case of out-of-memory.\r
++ */\r
++\r
++typedef struct _notmuch_string_pair_t {\r
++    char *key;\r
++    char *value;\r
++} notmuch_string_pair_t;\r
++\r
++struct _notmuch_string_map {\r
++    notmuch_bool_t sorted;\r
++    size_t length;\r
++    notmuch_string_pair_t *pairs;\r
++};\r
++\r
++notmuch_string_map_t *\r
++_notmuch_string_map_create (const void *ctx)\r
++{\r
++    notmuch_string_map_t *map;\r
++\r
++    map = talloc (ctx, notmuch_string_map_t);\r
++    if (unlikely (map == NULL))\r
++      return NULL;\r
++\r
++    map->length = 0;\r
++    map->pairs = NULL;\r
++    map->sorted = TRUE;\r
++\r
++    return map;\r
++}\r
++\r
++void\r
++_notmuch_string_map_append (notmuch_string_map_t *map,\r
++                          const char *key,\r
++                          const char *value)\r
++{\r
++\r
++    map->length++;\r
++    map->sorted = FALSE;\r
++\r
++    if (map->pairs)\r
++      map->pairs = talloc_realloc (map, map->pairs, notmuch_string_pair_t, map->length + 1);\r
++    else\r
++      map->pairs = talloc_array (map, notmuch_string_pair_t, map->length + 1);\r
++\r
++    map->pairs[map->length - 1].key = talloc_strdup (map, key);\r
++    map->pairs[map->length - 1].value = talloc_strdup (map, value);\r
++\r
++    /* Add sentinel */\r
++    map->pairs[map->length].key = NULL;\r
++    map->pairs[map->length].value = NULL;\r
++\r
++}\r
++\r
++static int\r
++cmppair (const void *pa, const void *pb)\r
++{\r
++    notmuch_string_pair_t *a = (notmuch_string_pair_t *) pa;\r
++    notmuch_string_pair_t *b = (notmuch_string_pair_t *) pb;\r
++\r
++    return strcmp (a->key, b->key);\r
++}\r
++\r
++static void\r
++_notmuch_string_map_sort (notmuch_string_map_t *map)\r
++{\r
++    if (map->length == 0)\r
++      return;\r
++\r
++    if (map->sorted)\r
++      return;\r
++\r
++    qsort (map->pairs, map->length, sizeof (notmuch_string_pair_t), cmppair);\r
++\r
++    map->sorted = TRUE;\r
++}\r
++\r
++static notmuch_bool_t\r
++string_cmp (const char *a, const char *b, notmuch_bool_t exact)\r
++{\r
++    if (exact)\r
++      return (strcmp (a, b));\r
++    else\r
++      return (strncmp (a, b, strlen (a)));\r
++}\r
++\r
++static notmuch_string_pair_t *\r
++bsearch_first (notmuch_string_pair_t *array, size_t len, const char *key, notmuch_bool_t exact)\r
++{\r
++    size_t first = 0;\r
++    size_t last = len - 1;\r
++    size_t mid;\r
++\r
++    if (len <= 0)\r
++      return NULL;\r
++\r
++    while (last > first) {\r
++      mid = (first + last) / 2;\r
++      int sign = string_cmp (key, array[mid].key, exact);\r
++\r
++      if (sign <= 0)\r
++          last = mid;\r
++      else\r
++          first = mid + 1;\r
++    }\r
++\r
++\r
++    if (string_cmp (key, array[first].key, exact) == 0)\r
++      return array + first;\r
++    else\r
++      return NULL;\r
++\r
++}\r
++\r
++const char *\r
++_notmuch_string_map_get (notmuch_string_map_t *map, const char *key)\r
++{\r
++    notmuch_string_pair_t *pair;\r
++\r
++    /* this means that calling append invalidates iterators */\r
++    _notmuch_string_map_sort (map);\r
++\r
++    pair = bsearch_first (map->pairs, map->length, key, TRUE);\r
++    if (! pair)\r
++      return NULL;\r
++\r
++    return pair->value;\r
++}\r
+-- \r
+2.8.1\r
+\r