From patchwork Fri Nov 6 00:24:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885549 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id AC264C55178 for ; Fri, 6 Nov 2020 00:25:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 40A9F2083B for ; Fri, 6 Nov 2020 00:25:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mYwGJ0Zw" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732789AbgKFAZD (ORCPT ); Thu, 5 Nov 2020 19:25:03 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53058 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732396AbgKFAZC (ORCPT ); Thu, 5 Nov 2020 19:25:02 -0500 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8304DC0613D2 for ; Thu, 5 Nov 2020 16:25:02 -0800 (PST) Received: by mail-wr1-x444.google.com with SMTP id e6so3767791wro.1 for ; Thu, 05 Nov 2020 16:25:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=oFAswi3o4d7CVNEpLSnDCYqFONh+d8GGqoJ1wyK3dI8=; b=mYwGJ0ZwfFKVimvvq5UpLu6mIjbEIb2f8fh5C5mzpNE98Lk7G77AunQUrp+4Z1+DYz wQuG/uc4WdSjxBCr7LZox37p0TtI0hmVy2++6ETJrBQDoEF92Ct0xhJA0mSQzsht8SVZ qtya+C+we0TBfUtUd7xv7CXOpTs6GI1kAvdpgmchVTWwzDFXMQDHntYtLumrmGNCpAO0 +loZZrS6a9Kzp2Xrfdv/KKEjh3vT+1Uwbcj68+F6ywVqsUWfMVkPQmPEZeoAKjaCkTl5 sU5aKIQBR3NMVf8dFrzHdAaVH4ImDjjz0mECuo3x6EEwT2rWY/wI+ep+3CUysvtL1P1p eKdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=oFAswi3o4d7CVNEpLSnDCYqFONh+d8GGqoJ1wyK3dI8=; b=FLsyP0Ek/GTjpvtiZE+mDkEt3Ao4IQPWQ2D8YRgAqCKk6VYSMj6kOG+CJzDMoKqvWP srvYqOebhNROj5s4WYzsPVqZJyaPEyMWSHOmfoQU2Eq/wcmwQv2FaqbDuC/xF8ECq8EB d8pvULhvJxV1X8uKTN6ltLt2T11Us3zpd69T+2tFTTdHANwl8LJTcKmXHWjdtOjYNX92 P3LIMYlkwi8zn+1VghXqCaOdygAybGRTB58Cca4x4T+DX2F6kQMSaYGNgjy9ZMbAGGu2 IlFmizRn7qs153x5QOxrqG1XCVyhjPt9rXiE5iTdWKZkeAJI2cpf63HVD9sdDK7+eVVl 9WjA== X-Gm-Message-State: AOAM5309aWV0+w+V0NzmzkRhCnAd4I1VGVpj6CZ/mk7jmqjJJG3HdLEF /M8pG/nXuJrRVbACxLeME+Ef+hEVO1g= X-Google-Smtp-Source: ABdhPJwQi8tlL/q9Im4PfLcQeihcetuRcjstsBDUGkLS/1TL1iczxBNZqrOO0zz6N3OR+QoAcP2Ilw== X-Received: by 2002:adf:e751:: with SMTP id c17mr5898978wrn.345.1604622301135; Thu, 05 Nov 2020 16:25:01 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id m22sm5656437wrb.97.2020.11.05.16.25.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:00 -0800 (PST) Message-Id: In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:44 +0000 Subject: [PATCH v5 01/15] hashmap: add usage documentation explaining hashmap_free[_entries]() Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren The existence of hashmap_free() and hashmap_free_entries() confused me, and the docs weren't clear enough. We are dealing with a map table, entries in that table, and possibly also things each of those entries point to. I had to consult other source code examples and the implementation. Add a brief note to clarify the differences. This will become even more important once we introduce a new hashmap_partial_clear() function which will add the question of whether the table itself has been freed. Signed-off-by: Elijah Newren --- hashmap.h | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/hashmap.h b/hashmap.h index b011b394fe..2994dc7a9c 100644 --- a/hashmap.h +++ b/hashmap.h @@ -236,13 +236,40 @@ void hashmap_init(struct hashmap *map, void hashmap_free_(struct hashmap *map, ssize_t offset); /* - * Frees a hashmap structure and allocated memory, leaves entries undisturbed + * Frees a hashmap structure and allocated memory for the table, but does not + * free the entries nor anything they point to. + * + * Usage note: + * + * Many callers will need to iterate over all entries and free the data each + * entry points to; in such a case, they can free the entry itself while at it. + * Thus, you might see: + * + * hashmap_for_each_entry(map, hashmap_iter, e, hashmap_entry_name) { + * free(e->somefield); + * free(e); + * } + * hashmap_free(map); + * + * instead of + * + * hashmap_for_each_entry(map, hashmap_iter, e, hashmap_entry_name) { + * free(e->somefield); + * } + * hashmap_free_entries(map, struct my_entry_struct, hashmap_entry_name); + * + * to avoid the implicit extra loop over the entries. However, if there are + * no special fields in your entry that need to be freed beyond the entry + * itself, it is probably simpler to avoid the explicit loop and just call + * hashmap_free_entries(). */ #define hashmap_free(map) hashmap_free_(map, -1) /* * Frees @map and all entries. @type is the struct type of the entry - * where @member is the hashmap_entry struct used to associate with @map + * where @member is the hashmap_entry struct used to associate with @map. + * + * See usage note above hashmap_free(). */ #define hashmap_free_entries(map, type, member) \ hashmap_free_(map, offsetof(type, member)); From patchwork Fri Nov 6 00:24:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885543 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8631CC5517A for ; Fri, 6 Nov 2020 00:25:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 33EB32083B for ; Fri, 6 Nov 2020 00:25:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="OJEqD/yj" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732794AbgKFAZF (ORCPT ); Thu, 5 Nov 2020 19:25:05 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53062 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732396AbgKFAZE (ORCPT ); Thu, 5 Nov 2020 19:25:04 -0500 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5BABBC0613CF for ; Thu, 5 Nov 2020 16:25:03 -0800 (PST) Received: by mail-wr1-x42b.google.com with SMTP id g12so3743065wrp.10 for ; Thu, 05 Nov 2020 16:25:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=lfeFxSmzBLKnFekm6mzwPvSqu+S1DEbaBDz97hV1DAw=; b=OJEqD/yjCmF+RcF79pwEw5AuMPpwXC9Yy62gLygc6CoqMHTea1FHEd/RR0hnf0lFBN WDIedTLWxUUe2K55en71gREEJtwjrjHb9UTX4sm8FVtn1ZQW2aIfiTvmIOg1tiEveHQH V70y5C60839Q1pSjmYf3VYWwsqYOsbxbqVzu+PJ736EstoTjwrQTzbT7+MZgxbqHd83J Pc6Dk/jyP3Mu5QzWt7TLPZ7y0Mxyf3RkX7gQJlo+Ms4nC3PIFuFtQiV+PvrybNicaZtS ZAkx/O5WiDzatuYcvufTdP3EWCjIz/2NOQJd99SoLOoQz1azA6d1R8U9b0rDgMN9pFyP ej1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=lfeFxSmzBLKnFekm6mzwPvSqu+S1DEbaBDz97hV1DAw=; b=KbH/nbugABxRXcvol3gWBL5xNvCNih/LTb7KyDp7mbZNlzoi07bi4dUOOY+bTse5LI 4wP/MWTJTKnoeF1XkppF5oF4fKD+l4GmK8R99ASX9+GqPZfT3V7Jvp+GT920+DtRbG/L Pgxl/Vvrls8Lfc9cVuvyB+pttnW5sgJMM5e0yhEiytyXKyDQJkzBv41kbNagErIDKtLu ytABLVMMdWHSzYEf9Lg2rx0Y2/U5XJ6uXarvtLUIrF5cvTFkrM6E+Jz0r2A9uJpsNBae rS6y172kLKHDKd/cvaquu3z/qTc4LCcM15By49knqQm02gwGI9PT1R73ReE2uKOGNt30 R9ew== X-Gm-Message-State: AOAM533ISa2xwjj1k9LnY7McDAsyM/dAHGNK4ZoMArlzSLoG4hqPM9JU wdWrxi2rDmXTdV103gmOEw2YhvPixo8= X-Google-Smtp-Source: ABdhPJx9fVzMdvrhkKz4bZk3uYS7w82HqtMp3vtetKtIw9ilkTPu8q8tNGJnx4gitQbwuRvUg9RQNA== X-Received: by 2002:adf:84a5:: with SMTP id 34mr5640776wrg.8.1604622301932; Thu, 05 Nov 2020 16:25:01 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id z5sm5007927wrw.87.2020.11.05.16.25.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:01 -0800 (PST) Message-Id: <591161fd781b7666ddaa45694eb20610cc359741.1604622298.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:45 +0000 Subject: [PATCH v5 02/15] hashmap: adjust spacing to fix argument alignment Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren No actual code changes; just whitespace adjustments. Signed-off-by: Elijah Newren --- hashmap.c | 17 +++++++++-------- hashmap.h | 22 +++++++++++----------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/hashmap.c b/hashmap.c index 09813e1a46..e44d8a3e85 100644 --- a/hashmap.c +++ b/hashmap.c @@ -92,8 +92,9 @@ static void alloc_table(struct hashmap *map, unsigned int size) } static inline int entry_equals(const struct hashmap *map, - const struct hashmap_entry *e1, const struct hashmap_entry *e2, - const void *keydata) + const struct hashmap_entry *e1, + const struct hashmap_entry *e2, + const void *keydata) { return (e1 == e2) || (e1->hash == e2->hash && @@ -101,7 +102,7 @@ static inline int entry_equals(const struct hashmap *map, } static inline unsigned int bucket(const struct hashmap *map, - const struct hashmap_entry *key) + const struct hashmap_entry *key) { return key->hash & (map->tablesize - 1); } @@ -148,7 +149,7 @@ static int always_equal(const void *unused_cmp_data, } void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function, - const void *cmpfn_data, size_t initial_size) + const void *cmpfn_data, size_t initial_size) { unsigned int size = HASHMAP_INITIAL_SIZE; @@ -199,7 +200,7 @@ struct hashmap_entry *hashmap_get(const struct hashmap *map, } struct hashmap_entry *hashmap_get_next(const struct hashmap *map, - const struct hashmap_entry *entry) + const struct hashmap_entry *entry) { struct hashmap_entry *e = entry->next; for (; e; e = e->next) @@ -225,8 +226,8 @@ void hashmap_add(struct hashmap *map, struct hashmap_entry *entry) } struct hashmap_entry *hashmap_remove(struct hashmap *map, - const struct hashmap_entry *key, - const void *keydata) + const struct hashmap_entry *key, + const void *keydata) { struct hashmap_entry *old; struct hashmap_entry **e = find_entry_ptr(map, key, keydata); @@ -249,7 +250,7 @@ struct hashmap_entry *hashmap_remove(struct hashmap *map, } struct hashmap_entry *hashmap_put(struct hashmap *map, - struct hashmap_entry *entry) + struct hashmap_entry *entry) { struct hashmap_entry *old = hashmap_remove(map, entry, NULL); hashmap_add(map, entry); diff --git a/hashmap.h b/hashmap.h index 2994dc7a9c..904f61d6e1 100644 --- a/hashmap.h +++ b/hashmap.h @@ -228,9 +228,9 @@ struct hashmap { * prevent expensive resizing. If 0, the table is dynamically resized. */ void hashmap_init(struct hashmap *map, - hashmap_cmp_fn equals_function, - const void *equals_function_data, - size_t initial_size); + hashmap_cmp_fn equals_function, + const void *equals_function_data, + size_t initial_size); /* internal function for freeing hashmap */ void hashmap_free_(struct hashmap *map, ssize_t offset); @@ -288,7 +288,7 @@ void hashmap_free_(struct hashmap *map, ssize_t offset); * and if it is on stack, you can just let it go out of scope). */ static inline void hashmap_entry_init(struct hashmap_entry *e, - unsigned int hash) + unsigned int hash) { e->hash = hash; e->next = NULL; @@ -330,8 +330,8 @@ static inline unsigned int hashmap_get_size(struct hashmap *map) * to `hashmap_cmp_fn` to decide whether the entry matches the key. */ struct hashmap_entry *hashmap_get(const struct hashmap *map, - const struct hashmap_entry *key, - const void *keydata); + const struct hashmap_entry *key, + const void *keydata); /* * Returns the hashmap entry for the specified hash code and key data, @@ -364,7 +364,7 @@ static inline struct hashmap_entry *hashmap_get_from_hash( * call to `hashmap_get` or `hashmap_get_next`. */ struct hashmap_entry *hashmap_get_next(const struct hashmap *map, - const struct hashmap_entry *entry); + const struct hashmap_entry *entry); /* * Adds a hashmap entry. This allows to add duplicate entries (i.e. @@ -384,7 +384,7 @@ void hashmap_add(struct hashmap *map, struct hashmap_entry *entry); * Returns the replaced entry, or NULL if not found (i.e. the entry was added). */ struct hashmap_entry *hashmap_put(struct hashmap *map, - struct hashmap_entry *entry); + struct hashmap_entry *entry); /* * Adds or replaces a hashmap entry contained within @keyvar, @@ -406,8 +406,8 @@ struct hashmap_entry *hashmap_put(struct hashmap *map, * Argument explanation is the same as in `hashmap_get`. */ struct hashmap_entry *hashmap_remove(struct hashmap *map, - const struct hashmap_entry *key, - const void *keydata); + const struct hashmap_entry *key, + const void *keydata); /* * Removes a hashmap entry contained within @keyvar, @@ -449,7 +449,7 @@ struct hashmap_entry *hashmap_iter_next(struct hashmap_iter *iter); /* Initializes the iterator and returns the first entry, if any. */ static inline struct hashmap_entry *hashmap_iter_first(struct hashmap *map, - struct hashmap_iter *iter) + struct hashmap_iter *iter) { hashmap_iter_init(map, iter); return hashmap_iter_next(iter); From patchwork Fri Nov 6 00:24:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885545 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D5BFBC388F7 for ; Fri, 6 Nov 2020 00:25:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 79CEB2083B for ; Fri, 6 Nov 2020 00:25:10 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Da+FFGYi" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732844AbgKFAZH (ORCPT ); Thu, 5 Nov 2020 19:25:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53066 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732804AbgKFAZF (ORCPT ); Thu, 5 Nov 2020 19:25:05 -0500 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2D82AC0613D2 for ; Thu, 5 Nov 2020 16:25:04 -0800 (PST) Received: by mail-wm1-x342.google.com with SMTP id d142so3270678wmd.4 for ; Thu, 05 Nov 2020 16:25:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=IEPGTilWFeb/gYnUiQHEDPP0R8dCTuzsEUTPxGrkZm8=; b=Da+FFGYiCtIv3sITIgLczTOuQ5UaD/PTJCYGnOoDM9I9xlpNBwSjslpDF1Pmxyta8O w6Ja0jCjvN0962ndyZS5EZxDPftrxNvmOLdmF0i+nd71myEfnrS0+f7h3ii/KYz1G9Rb 68Rmtc5nd6rxph+ajHUKU+kTsYh6euD1hSVuEp3y0lwhrN9g/4Ee6K67lBa4gtrffCto j8Wo32mcviGTxx+mp259RmbE7gB+qet48b1h3i9DqzUGoD5jT7FkpONjUx0tzJH9JPwy JR6p+QBuUROVL/xaAlxPB2SNfeVwDCu3TstD8yz5bk6Z9pGG2d2UceuCLPwrdEhT0rQD kNrg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=IEPGTilWFeb/gYnUiQHEDPP0R8dCTuzsEUTPxGrkZm8=; b=q8DjVDsJV6aEYaaIrzjaCtfA+hxNXr2xmn36m98iZaxZfH3qdxjb6P9Es5CNY+SVNp ORVI1Xt65nEGKECUvIP8ylVQCr5Ka39OveuuGFkaekihM71hZssf4QNDIaMFr3bR70uS y/h5PxsV9ufnqzxpuW6oW/A1p0sORCJ/t4gcRfuKntjgcstd5FPaEm1apDjZqiRItKu/ e86/BqsXqtDpbDmYGu43ugXnFem+GrZ3x1hvW+U3fo12rxY6f2X/eeCcATIaqtbGJhFe YSsazUKZzinj0VLrzVdrCzDERjOCRV5TzZlDYlIFsoV9hHzuif4j1N3krnOmmxeXk2ZF ZB/Q== X-Gm-Message-State: AOAM533F7E5+4775hb7GCyfqfsHr/D/9magnpXTFdI7RF5jqiVCvMoY8 +xNz6O9nl3lM/erGsRgtEFbL0UecZCc= X-Google-Smtp-Source: ABdhPJyGGSuTZQduJyIKqx5sOF2waYQ9xwClAUosCv8WDi8Bh8Q2fbsPXjDajNSQ0MdtXKS8loaSEg== X-Received: by 2002:a1c:acc1:: with SMTP id v184mr4939148wme.63.1604622302821; Thu, 05 Nov 2020 16:25:02 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id q2sm4698686wrw.40.2020.11.05.16.25.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:02 -0800 (PST) Message-Id: In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:46 +0000 Subject: [PATCH v5 03/15] hashmap: allow re-use after hashmap_free() Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Previously, once map->table had been freed, any calls to hashmap_put(), hashmap_get(), or hashmap_remove() would cause a NULL pointer dereference (since hashmap_free_() also zeros the memory; without that zeroing, calling these functions would cause a use-after-free problem). Modify these functions to check for a NULL table and automatically allocate as needed. Also add a HASHMAP_INIT(fn, data) macro for initializing hashmaps on the stack without calling hashmap_init(). Signed-off-by: Elijah Newren --- hashmap.c | 16 ++++++++++++++-- hashmap.h | 3 +++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/hashmap.c b/hashmap.c index e44d8a3e85..bb7c9979b8 100644 --- a/hashmap.c +++ b/hashmap.c @@ -114,6 +114,7 @@ int hashmap_bucket(const struct hashmap *map, unsigned int hash) static void rehash(struct hashmap *map, unsigned int newsize) { + /* map->table MUST NOT be NULL when this function is called */ unsigned int i, oldsize = map->tablesize; struct hashmap_entry **oldtable = map->table; @@ -134,6 +135,7 @@ static void rehash(struct hashmap *map, unsigned int newsize) static inline struct hashmap_entry **find_entry_ptr(const struct hashmap *map, const struct hashmap_entry *key, const void *keydata) { + /* map->table MUST NOT be NULL when this function is called */ struct hashmap_entry **e = &map->table[bucket(map, key)]; while (*e && !entry_equals(map, *e, key, keydata)) e = &(*e)->next; @@ -196,6 +198,8 @@ struct hashmap_entry *hashmap_get(const struct hashmap *map, const struct hashmap_entry *key, const void *keydata) { + if (!map->table) + return NULL; return *find_entry_ptr(map, key, keydata); } @@ -211,8 +215,12 @@ struct hashmap_entry *hashmap_get_next(const struct hashmap *map, void hashmap_add(struct hashmap *map, struct hashmap_entry *entry) { - unsigned int b = bucket(map, entry); + unsigned int b; + + if (!map->table) + alloc_table(map, HASHMAP_INITIAL_SIZE); + b = bucket(map, entry); /* add entry */ entry->next = map->table[b]; map->table[b] = entry; @@ -230,7 +238,11 @@ struct hashmap_entry *hashmap_remove(struct hashmap *map, const void *keydata) { struct hashmap_entry *old; - struct hashmap_entry **e = find_entry_ptr(map, key, keydata); + struct hashmap_entry **e; + + if (!map->table) + return NULL; + e = find_entry_ptr(map, key, keydata); if (!*e) return NULL; diff --git a/hashmap.h b/hashmap.h index 904f61d6e1..3b0f2bcade 100644 --- a/hashmap.h +++ b/hashmap.h @@ -210,6 +210,9 @@ struct hashmap { /* hashmap functions */ +#define HASHMAP_INIT(fn, data) { .cmpfn = fn, .cmpfn_data = data, \ + .do_count_items = 1 } + /* * Initializes a hashmap structure. * From patchwork Fri Nov 6 00:24:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885551 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D2778C5517A for ; Fri, 6 Nov 2020 00:25:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 630662083B for ; Fri, 6 Nov 2020 00:25:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="O0/BSWgQ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732880AbgKFAZL (ORCPT ); Thu, 5 Nov 2020 19:25:11 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53078 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732821AbgKFAZH (ORCPT ); Thu, 5 Nov 2020 19:25:07 -0500 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C283CC0613D2 for ; Thu, 5 Nov 2020 16:25:06 -0800 (PST) Received: by mail-wm1-x344.google.com with SMTP id d142so3270744wmd.4 for ; Thu, 05 Nov 2020 16:25:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=eD1ODDn8YazYa2TxKvej2ageSWRW9od1dWKHaSlyndc=; b=O0/BSWgQxb5fAsvkESA79/Hdyl+e2E2OB3MbtRLsXGB21J21fQ6suL+TRJBZBfZwDb ETteNGBWEwTdJvsWInS5QhwsZ/kJDClXnBPpgAZ9lTIx5tZ8xhkRF7ErdaihrYMM6Js5 nABiCWl5CSHoalk9cF3Osi69mPP9IBPDggfhRT2GR/vc3hFifKV7ivrW1ABcbfoplpQs BtAcZdHpuwzjkwstiIMVAt5Bri9JEfDNDpNRHgnaym2Y5qTpYXlMTI9SuryASLLaNuLB q2mXl7oEd/ZocrUfCSlqvLmFm9fMWMA5yG7g10ajosdBkKJGyeTYEGXN9fhXx87+O/bc 8KsA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=eD1ODDn8YazYa2TxKvej2ageSWRW9od1dWKHaSlyndc=; b=AvOGtSwn2onlF6Tt222ZtO/Mg4p75VJ7gGgkBGcy3Tk6d8SLMCGUF9+lDbN9KIsolu v+q5QTPtGLqWy//BChnPmtpTGo0FhXdO9SLWTV/yemxR504rEh+tfcCkBDl+ieyI3DqP jOKqmI0CUeK5pW2yD3dovYs+9r+B9WXYhmlEfJv0JFPTrhd3xVE4ECwczIS4LbTSh0VI ECGfrOCJJZCFkFDzR/e1eG8MRCPTISF2MUZ/e53c9IsjL0QSmcZXu5gfTgK+6yZf5uz6 JcwtDk2835JJfC9lEbg82OA/ZugO/liWk8WW82+WVT7onyAoc5I0sfohdQO/SkStEhiF z7OQ== X-Gm-Message-State: AOAM5312lubkh8JW9zzlbp0PzWvr1ROHOyKsftzHGISsMCF1IBVbX1GC o43IXeJzuBfuc/hil49mMRWmpwBTj/c= X-Google-Smtp-Source: ABdhPJwc5icTMLjDp7oP9PCxb9dWHqWXTGRqz2/7fyFG9t2mXIyFre2u55tGQVDw8R6DtnkeLPw3tw== X-Received: by 2002:a7b:c848:: with SMTP id c8mr5194114wml.86.1604622304445; Thu, 05 Nov 2020 16:25:04 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id b14sm3223592wrq.47.2020.11.05.16.25.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:03 -0800 (PST) Message-Id: <861e8d65ae8065595d9d4ccff5f70155fec408c9.1604622298.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:48 +0000 Subject: [PATCH v5 05/15] hashmap: provide deallocation function names Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren hashmap_free(), hashmap_free_entries(), and hashmap_free_() have existed for a while, but aren't necessarily the clearest names, especially with hashmap_partial_clear() being added to the mix and lazy-initialization now being supported. Peff suggested we adopt the following names[1]: - hashmap_clear() - remove all entries and de-allocate any hashmap-specific data, but be ready for reuse - hashmap_clear_and_free() - ditto, but free the entries themselves - hashmap_partial_clear() - remove all entries but don't deallocate table - hashmap_partial_clear_and_free() - ditto, but free the entries This patch provides the new names and converts all existing callers over to the new naming scheme. [1] https://lore.kernel.org/git/20201030125059.GA3277724@coredump.intra.peff.net/ Signed-off-by: Elijah Newren --- add-interactive.c | 2 +- blame.c | 2 +- bloom.c | 2 +- builtin/fetch.c | 6 +++--- builtin/shortlog.c | 2 +- config.c | 2 +- diff.c | 4 ++-- diffcore-rename.c | 2 +- dir.c | 8 ++++---- hashmap.c | 6 +++--- hashmap.h | 44 +++++++++++++++++++++++++---------------- merge-recursive.c | 6 +++--- name-hash.c | 4 ++-- object.c | 2 +- oidmap.c | 2 +- patch-ids.c | 2 +- range-diff.c | 2 +- ref-filter.c | 2 +- revision.c | 2 +- sequencer.c | 4 ++-- submodule-config.c | 4 ++-- t/helper/test-hashmap.c | 6 +++--- 22 files changed, 63 insertions(+), 53 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index 555c4abf32..a14c0feaa2 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -557,7 +557,7 @@ static int get_modified_files(struct repository *r, if (ps) clear_pathspec(&rev.prune_data); } - hashmap_free_entries(&s.file_map, struct pathname_entry, ent); + hashmap_clear_and_free(&s.file_map, struct pathname_entry, ent); if (unmerged_count) *unmerged_count = s.unmerged_count; if (binary_count) diff --git a/blame.c b/blame.c index 686845b2b4..229beb6452 100644 --- a/blame.c +++ b/blame.c @@ -435,7 +435,7 @@ static void get_fingerprint(struct fingerprint *result, static void free_fingerprint(struct fingerprint *f) { - hashmap_free(&f->map); + hashmap_clear(&f->map); free(f->entries); } diff --git a/bloom.c b/bloom.c index 68c73200a5..719c313a1c 100644 --- a/bloom.c +++ b/bloom.c @@ -287,7 +287,7 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r, } cleanup: - hashmap_free_entries(&pathmap, struct pathmap_hash_entry, entry); + hashmap_clear_and_free(&pathmap, struct pathmap_hash_entry, entry); } else { for (i = 0; i < diff_queued_diff.nr; i++) diff_free_filepair(diff_queued_diff.queue[i]); diff --git a/builtin/fetch.c b/builtin/fetch.c index f9c3c49f14..ecf8537605 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -393,7 +393,7 @@ static void find_non_local_tags(const struct ref *refs, item = refname_hash_add(&remote_refs, ref->name, &ref->old_oid); string_list_insert(&remote_refs_list, ref->name); } - hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent); + hashmap_clear_and_free(&existing_refs, struct refname_hash_entry, ent); /* * We may have a final lightweight tag that needs to be @@ -428,7 +428,7 @@ static void find_non_local_tags(const struct ref *refs, **tail = rm; *tail = &rm->next; } - hashmap_free_entries(&remote_refs, struct refname_hash_entry, ent); + hashmap_clear_and_free(&remote_refs, struct refname_hash_entry, ent); string_list_clear(&remote_refs_list, 0); oidset_clear(&fetch_oids); } @@ -573,7 +573,7 @@ static struct ref *get_ref_map(struct remote *remote, } } if (existing_refs_populated) - hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent); + hashmap_clear_and_free(&existing_refs, struct refname_hash_entry, ent); return ref_map; } diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 0a5c4968f6..83f0a739b4 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -220,7 +220,7 @@ static void strset_clear(struct strset *ss) { if (!ss->map.table) return; - hashmap_free_entries(&ss->map, struct strset_item, ent); + hashmap_clear_and_free(&ss->map, struct strset_item, ent); } static void insert_records_from_trailers(struct shortlog *log, diff --git a/config.c b/config.c index 2bdff4457b..8f324ed3a6 100644 --- a/config.c +++ b/config.c @@ -1963,7 +1963,7 @@ void git_configset_clear(struct config_set *cs) free(entry->key); string_list_clear(&entry->value_list, 1); } - hashmap_free_entries(&cs->config_hash, struct config_set_element, ent); + hashmap_clear_and_free(&cs->config_hash, struct config_set_element, ent); cs->hash_initialized = 0; free(cs->list.items); cs->list.nr = 0; diff --git a/diff.c b/diff.c index 2bb2f8f57e..8e0e59f5cf 100644 --- a/diff.c +++ b/diff.c @@ -6289,9 +6289,9 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o) if (o->color_moved == COLOR_MOVED_ZEBRA_DIM) dim_moved_lines(o); - hashmap_free_entries(&add_lines, struct moved_entry, + hashmap_clear_and_free(&add_lines, struct moved_entry, ent); - hashmap_free_entries(&del_lines, struct moved_entry, + hashmap_clear_and_free(&del_lines, struct moved_entry, ent); } diff --git a/diffcore-rename.c b/diffcore-rename.c index 99e63e90f8..d367a6d244 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -407,7 +407,7 @@ static int find_exact_renames(struct diff_options *options) renames += find_identical_files(&file_table, i, options); /* Free the hash data structure and entries */ - hashmap_free_entries(&file_table, struct file_similarity, entry); + hashmap_clear_and_free(&file_table, struct file_similarity, entry); return renames; } diff --git a/dir.c b/dir.c index 78387110e6..161dce121e 100644 --- a/dir.c +++ b/dir.c @@ -817,8 +817,8 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern clear_hashmaps: warning(_("disabling cone pattern matching")); - hashmap_free_entries(&pl->parent_hashmap, struct pattern_entry, ent); - hashmap_free_entries(&pl->recursive_hashmap, struct pattern_entry, ent); + hashmap_clear_and_free(&pl->parent_hashmap, struct pattern_entry, ent); + hashmap_clear_and_free(&pl->recursive_hashmap, struct pattern_entry, ent); pl->use_cone_patterns = 0; } @@ -921,8 +921,8 @@ void clear_pattern_list(struct pattern_list *pl) free(pl->patterns[i]); free(pl->patterns); free(pl->filebuf); - hashmap_free_entries(&pl->recursive_hashmap, struct pattern_entry, ent); - hashmap_free_entries(&pl->parent_hashmap, struct pattern_entry, ent); + hashmap_clear_and_free(&pl->recursive_hashmap, struct pattern_entry, ent); + hashmap_clear_and_free(&pl->parent_hashmap, struct pattern_entry, ent); memset(pl, 0, sizeof(*pl)); } diff --git a/hashmap.c b/hashmap.c index 922ed07954..5009471800 100644 --- a/hashmap.c +++ b/hashmap.c @@ -183,7 +183,7 @@ static void free_individual_entries(struct hashmap *map, ssize_t entry_offset) while ((e = hashmap_iter_next(&iter))) /* * like container_of, but using caller-calculated - * offset (caller being hashmap_free_entries) + * offset (caller being hashmap_clear_and_free) */ free((char *)e - entry_offset); } @@ -199,11 +199,11 @@ void hashmap_partial_clear_(struct hashmap *map, ssize_t entry_offset) map->private_size = 0; } -void hashmap_free_(struct hashmap *map, ssize_t entry_offset) +void hashmap_clear_(struct hashmap *map, ssize_t entry_offset) { if (!map || !map->table) return; - if (entry_offset >= 0) /* called by hashmap_free_entries */ + if (entry_offset >= 0) /* called by hashmap_clear_and_free */ free_individual_entries(map, entry_offset); free(map->table); memset(map, 0, sizeof(*map)); diff --git a/hashmap.h b/hashmap.h index e9430d582a..7251687d73 100644 --- a/hashmap.h +++ b/hashmap.h @@ -96,7 +96,7 @@ * } * * if (!strcmp("end", action)) { - * hashmap_free_entries(&map, struct long2string, ent); + * hashmap_clear_and_free(&map, struct long2string, ent); * break; * } * } @@ -237,7 +237,7 @@ void hashmap_init(struct hashmap *map, /* internal functions for clearing or freeing hashmap */ void hashmap_partial_clear_(struct hashmap *map, ssize_t offset); -void hashmap_free_(struct hashmap *map, ssize_t offset); +void hashmap_clear_(struct hashmap *map, ssize_t offset); /* * Frees a hashmap structure and allocated memory for the table, but does not @@ -253,40 +253,50 @@ void hashmap_free_(struct hashmap *map, ssize_t offset); * free(e->somefield); * free(e); * } - * hashmap_free(map); + * hashmap_clear(map); * * instead of * * hashmap_for_each_entry(map, hashmap_iter, e, hashmap_entry_name) { * free(e->somefield); * } - * hashmap_free_entries(map, struct my_entry_struct, hashmap_entry_name); + * hashmap_clear_and_free(map, struct my_entry_struct, hashmap_entry_name); * * to avoid the implicit extra loop over the entries. However, if there are * no special fields in your entry that need to be freed beyond the entry * itself, it is probably simpler to avoid the explicit loop and just call - * hashmap_free_entries(). + * hashmap_clear_and_free(). */ -#define hashmap_free(map) hashmap_free_(map, -1) +#define hashmap_clear(map) hashmap_clear_(map, -1) /* - * Basically the same as calling hashmap_free() followed by hashmap_init(), - * but doesn't incur the overhead of deallocating and reallocating - * map->table; it leaves map->table allocated and the same size but zeroes - * it out so it's ready for use again as an empty map. As with - * hashmap_free(), you may need to free the entries yourself before calling - * this function. + * Similar to hashmap_clear(), except that the table is no deallocated; it + * is merely zeroed out but left the same size as before. If the hashmap + * will be reused, this avoids the overhead of deallocating and + * reallocating map->table. As with hashmap_clear(), you may need to free + * the entries yourself before calling this function. */ #define hashmap_partial_clear(map) hashmap_partial_clear_(map, -1) /* - * Frees @map and all entries. @type is the struct type of the entry - * where @member is the hashmap_entry struct used to associate with @map. + * Similar to hashmap_clear() but also frees all entries. @type is the + * struct type of the entry where @member is the hashmap_entry struct used + * to associate with @map. * - * See usage note above hashmap_free(). + * See usage note above hashmap_clear(). */ -#define hashmap_free_entries(map, type, member) \ - hashmap_free_(map, offsetof(type, member)); +#define hashmap_clear_and_free(map, type, member) \ + hashmap_clear_(map, offsetof(type, member)) + +/* + * Similar to hashmap_partial_clear() but also frees all entries. @type is + * the struct type of the entry where @member is the hashmap_entry struct + * used to associate with @map. + * + * See usage note above hashmap_clear(). + */ +#define hashmap_partial_clear_and_free(map, type, member) \ + hashmap_partial_clear_(map, offsetof(type, member)) /* hashmap_entry functions */ diff --git a/merge-recursive.c b/merge-recursive.c index d0214335a7..f736a0f632 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -2651,7 +2651,7 @@ static struct string_list *get_renames(struct merge_options *opt, free(e->target_file); string_list_clear(&e->source_files, 0); } - hashmap_free_entries(&collisions, struct collision_entry, ent); + hashmap_clear_and_free(&collisions, struct collision_entry, ent); return renames; } @@ -2870,7 +2870,7 @@ static void initial_cleanup_rename(struct diff_queue_struct *pairs, strbuf_release(&e->new_dir); /* possible_new_dirs already cleared in get_directory_renames */ } - hashmap_free_entries(dir_renames, struct dir_rename_entry, ent); + hashmap_clear_and_free(dir_renames, struct dir_rename_entry, ent); free(dir_renames); free(pairs->queue); @@ -3497,7 +3497,7 @@ static int merge_trees_internal(struct merge_options *opt, string_list_clear(entries, 1); free(entries); - hashmap_free_entries(&opt->priv->current_file_dir_set, + hashmap_clear_and_free(&opt->priv->current_file_dir_set, struct path_hashmap_entry, e); if (clean < 0) { diff --git a/name-hash.c b/name-hash.c index fb526a3775..5d3c7b12c1 100644 --- a/name-hash.c +++ b/name-hash.c @@ -726,6 +726,6 @@ void free_name_hash(struct index_state *istate) return; istate->name_hash_initialized = 0; - hashmap_free(&istate->name_hash); - hashmap_free_entries(&istate->dir_hash, struct dir_entry, ent); + hashmap_clear(&istate->name_hash); + hashmap_clear_and_free(&istate->dir_hash, struct dir_entry, ent); } diff --git a/object.c b/object.c index 3257518656..b8406409d5 100644 --- a/object.c +++ b/object.c @@ -532,7 +532,7 @@ void raw_object_store_clear(struct raw_object_store *o) close_object_store(o); o->packed_git = NULL; - hashmap_free(&o->pack_map); + hashmap_clear(&o->pack_map); } void parsed_object_pool_clear(struct parsed_object_pool *o) diff --git a/oidmap.c b/oidmap.c index 423aa014a3..286a04a53c 100644 --- a/oidmap.c +++ b/oidmap.c @@ -27,7 +27,7 @@ void oidmap_free(struct oidmap *map, int free_entries) return; /* TODO: make oidmap itself not depend on struct layouts */ - hashmap_free_(&map->map, free_entries ? 0 : -1); + hashmap_clear_(&map->map, free_entries ? 0 : -1); } void *oidmap_get(const struct oidmap *map, const struct object_id *key) diff --git a/patch-ids.c b/patch-ids.c index 12aa6d494b..21973e4933 100644 --- a/patch-ids.c +++ b/patch-ids.c @@ -71,7 +71,7 @@ int init_patch_ids(struct repository *r, struct patch_ids *ids) int free_patch_ids(struct patch_ids *ids) { - hashmap_free_entries(&ids->patches, struct patch_id, ent); + hashmap_clear_and_free(&ids->patches, struct patch_id, ent); return 0; } diff --git a/range-diff.c b/range-diff.c index 24dc435e48..befeecae44 100644 --- a/range-diff.c +++ b/range-diff.c @@ -266,7 +266,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b) } } - hashmap_free(&map); + hashmap_clear(&map); } static void diffsize_consume(void *data, char *line, unsigned long len) diff --git a/ref-filter.c b/ref-filter.c index c62f6b4822..5e66b8cd76 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -2222,7 +2222,7 @@ void ref_array_clear(struct ref_array *array) used_atom_cnt = 0; if (ref_to_worktree_map.worktrees) { - hashmap_free_entries(&(ref_to_worktree_map.map), + hashmap_clear_and_free(&(ref_to_worktree_map.map), struct ref_to_worktree_entry, ent); free_worktrees(ref_to_worktree_map.worktrees); ref_to_worktree_map.worktrees = NULL; diff --git a/revision.c b/revision.c index aa62212040..f27649d45d 100644 --- a/revision.c +++ b/revision.c @@ -139,7 +139,7 @@ static void paths_and_oids_clear(struct hashmap *map) free(entry->path); } - hashmap_free_entries(map, struct path_and_oids_entry, ent); + hashmap_clear_and_free(map, struct path_and_oids_entry, ent); } static void paths_and_oids_insert(struct hashmap *map, diff --git a/sequencer.c b/sequencer.c index 00acb12496..23a09c3e7a 100644 --- a/sequencer.c +++ b/sequencer.c @@ -5058,7 +5058,7 @@ static int make_script_with_merges(struct pretty_print_context *pp, oidmap_free(&commit2todo, 1); oidmap_free(&state.commit2label, 1); - hashmap_free_entries(&state.labels, struct labels_entry, entry); + hashmap_clear_and_free(&state.labels, struct labels_entry, entry); strbuf_release(&state.buf); return 0; @@ -5577,7 +5577,7 @@ int todo_list_rearrange_squash(struct todo_list *todo_list) for (i = 0; i < todo_list->nr; i++) free(subjects[i]); free(subjects); - hashmap_free_entries(&subject2item, struct subject2item_entry, entry); + hashmap_clear_and_free(&subject2item, struct subject2item_entry, entry); clear_commit_todo_item(&commit_todo); diff --git a/submodule-config.c b/submodule-config.c index c569e22aa3..f502505566 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -103,8 +103,8 @@ static void submodule_cache_clear(struct submodule_cache *cache) ent /* member name */) free_one_config(entry); - hashmap_free_entries(&cache->for_path, struct submodule_entry, ent); - hashmap_free_entries(&cache->for_name, struct submodule_entry, ent); + hashmap_clear_and_free(&cache->for_path, struct submodule_entry, ent); + hashmap_clear_and_free(&cache->for_name, struct submodule_entry, ent); cache->initialized = 0; cache->gitmodules_read = 0; } diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index f38706216f..2475663b49 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -110,7 +110,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) hashmap_add(&map, &entries[i]->ent); } - hashmap_free(&map); + hashmap_clear(&map); } } else { /* test map lookups */ @@ -130,7 +130,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) } } - hashmap_free(&map); + hashmap_clear(&map); } } @@ -262,6 +262,6 @@ int cmd__hashmap(int argc, const char **argv) } strbuf_release(&line); - hashmap_free_entries(&map, struct test_entry, ent); + hashmap_clear_and_free(&map, struct test_entry, ent); return 0; } From patchwork Fri Nov 6 00:24:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885553 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 93048C388F7 for ; Fri, 6 Nov 2020 00:25:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 39A942083B for ; Fri, 6 Nov 2020 00:25:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="O/I6DhkZ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732869AbgKFAZK (ORCPT ); Thu, 5 Nov 2020 19:25:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53076 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732396AbgKFAZH (ORCPT ); Thu, 5 Nov 2020 19:25:07 -0500 Received: from mail-wr1-x441.google.com (mail-wr1-x441.google.com [IPv6:2a00:1450:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9E5DDC0613CF for ; Thu, 5 Nov 2020 16:25:06 -0800 (PST) Received: by mail-wr1-x441.google.com with SMTP id c17so3743407wrc.11 for ; Thu, 05 Nov 2020 16:25:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=oEYc2S4ksSfmtDUY2461bdvZotWwPmh9voOUaSelCBs=; b=O/I6DhkZUUjGLm9vynUHz3WCBZsqJCa8ObCgFBZY6CQNNxCdnLm1HAMtBs+4XI8W+Z pM5df0lb2RU2mZiLHrLaG4PrZKyCjJi91At1a6de2+eBePNRn9g3uQuMXeZO/BeoVpxk qLN5wE9eIpBTmgA6T/K8Ipy5CXCnLVrUqeiNWoZCQoBJ5BWg1011b5fmptlPI8mJLLcw bN8Wn+Pq4YgU2zElnaRp/PmoXlBZOPP58vJ+Dv1iQaXugImfaYgmGZbD+R8tLWLBy9yo yKv6A4CC9pQhRBhZQoF9Yq5AgFRF5NvpA2ruz5br3jXTSBs1KjjK8h2+gV/fQecxtV0R o7lw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=oEYc2S4ksSfmtDUY2461bdvZotWwPmh9voOUaSelCBs=; b=VdhBjWDO1mAkyyOLgpTJc/Cm0QZkScxSdq2ErHoaS7+lQMPgJlCtpD4m5rJNDCP6oz q59YkHpwk6VTVuDUXIbJdS8U6TM13RQnooV9EsA71OqrE3ukgumGNnwEtBMH9T/Jo2k6 ioh5MGZMo5Ea9/FU3JbEOO0Hd0JjWElzWtKU3YnBNIPLSt1hG9rGioRjZhD1qz1zENBf KmgPvixyeRlhzzg7WkZyacRbQjfcuF6TE5hn2LrXqcSDdpGkkfRsvqlgl72X6JNEfuDW LYxl1/1BxKVhxLe158lU47LuX7NRUKuZl3f/utLtkO/AyPX6F39mCWq0nASr5Qt3KjX0 Gspw== X-Gm-Message-State: AOAM532PWwzOSpwPT48QYC9lqeeokawdlpUlforeq2rgBruANgK6LXfR vTsc7VbBgCJYx8VcHpj5K2DerdHNMfA= X-Google-Smtp-Source: ABdhPJzjLi1ThWUYlq5YLD/4C20YMSNNf6H2iLiy7vOitwyK3N7mJIkbwtvRvlDO956mmd6wAeYMdQ== X-Received: by 2002:adf:ce01:: with SMTP id p1mr5349794wrn.33.1604622305248; Thu, 05 Nov 2020 16:25:05 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id g138sm4691677wme.39.2020.11.05.16.25.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:04 -0800 (PST) Message-Id: <448d3b219ffebbc0daa4ef033d78fd45693c5ccd.1604622299.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:49 +0000 Subject: [PATCH v5 06/15] strmap: new utility functions Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Add strmap as a new struct and associated utility functions, specifically for hashmaps that map strings to some value. The API is taken directly from Peff's proposal at https://lore.kernel.org/git/20180906191203.GA26184@sigill.intra.peff.net/ Note that similar string-list, I have a strdup_strings setting. However, unlike string-list, strmap_init() does not take a parameter for this setting and instead automatically sets it to 1; callers who want to control this detail need to instead call strmap_init_with_options(). (Future patches will add additional parameters to strmap_init_with_options()). Signed-off-by: Elijah Newren --- Makefile | 1 + strmap.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ strmap.h | 65 +++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 strmap.c create mode 100644 strmap.h diff --git a/Makefile b/Makefile index 95571ee3fc..777a34c01c 100644 --- a/Makefile +++ b/Makefile @@ -1000,6 +1000,7 @@ LIB_OBJS += stable-qsort.o LIB_OBJS += strbuf.o LIB_OBJS += streaming.o LIB_OBJS += string-list.o +LIB_OBJS += strmap.o LIB_OBJS += strvec.o LIB_OBJS += sub-process.o LIB_OBJS += submodule-config.o diff --git a/strmap.c b/strmap.c new file mode 100644 index 0000000000..53f284eb20 --- /dev/null +++ b/strmap.c @@ -0,0 +1,99 @@ +#include "git-compat-util.h" +#include "strmap.h" + +int cmp_strmap_entry(const void *hashmap_cmp_fn_data, + const struct hashmap_entry *entry1, + const struct hashmap_entry *entry2, + const void *keydata) +{ + const struct strmap_entry *e1, *e2; + + e1 = container_of(entry1, const struct strmap_entry, ent); + e2 = container_of(entry2, const struct strmap_entry, ent); + return strcmp(e1->key, e2->key); +} + +static struct strmap_entry *find_strmap_entry(struct strmap *map, + const char *str) +{ + struct strmap_entry entry; + hashmap_entry_init(&entry.ent, strhash(str)); + entry.key = str; + return hashmap_get_entry(&map->map, &entry, ent, NULL); +} + +void strmap_init(struct strmap *map) +{ + strmap_init_with_options(map, 1); +} + +void strmap_init_with_options(struct strmap *map, + int strdup_strings) +{ + hashmap_init(&map->map, cmp_strmap_entry, NULL, 0); + map->strdup_strings = strdup_strings; +} + +static void strmap_free_entries_(struct strmap *map, int free_values) +{ + struct hashmap_iter iter; + struct strmap_entry *e; + + if (!map) + return; + + /* + * We need to iterate over the hashmap entries and free + * e->key and e->value ourselves; hashmap has no API to + * take care of that for us. Since we're already iterating over + * the hashmap, though, might as well free e too and avoid the need + * to make some call into the hashmap API to do that. + */ + hashmap_for_each_entry(&map->map, &iter, e, ent) { + if (free_values) + free(e->value); + if (map->strdup_strings) + free((char*)e->key); + free(e); + } +} + +void strmap_clear(struct strmap *map, int free_values) +{ + strmap_free_entries_(map, free_values); + hashmap_clear(&map->map); +} + +void *strmap_put(struct strmap *map, const char *str, void *data) +{ + struct strmap_entry *entry = find_strmap_entry(map, str); + void *old = NULL; + + if (entry) { + old = entry->value; + entry->value = data; + } else { + const char *key = str; + + entry = xmalloc(sizeof(*entry)); + hashmap_entry_init(&entry->ent, strhash(str)); + + if (map->strdup_strings) + key = xstrdup(str); + entry->key = key; + entry->value = data; + hashmap_add(&map->map, &entry->ent); + } + return old; +} + +void *strmap_get(struct strmap *map, const char *str) +{ + struct strmap_entry *entry = find_strmap_entry(map, str); + return entry ? entry->value : NULL; +} + +int strmap_contains(struct strmap *map, const char *str) +{ + return find_strmap_entry(map, str) != NULL; +} diff --git a/strmap.h b/strmap.h new file mode 100644 index 0000000000..96888c23ad --- /dev/null +++ b/strmap.h @@ -0,0 +1,65 @@ +#ifndef STRMAP_H +#define STRMAP_H + +#include "hashmap.h" + +struct strmap { + struct hashmap map; + unsigned int strdup_strings:1; +}; + +struct strmap_entry { + struct hashmap_entry ent; + const char *key; + void *value; +}; + +int cmp_strmap_entry(const void *hashmap_cmp_fn_data, + const struct hashmap_entry *entry1, + const struct hashmap_entry *entry2, + const void *keydata); + +#define STRMAP_INIT { \ + .map = HASHMAP_INIT(cmp_strmap_entry, NULL), \ + .strdup_strings = 1, \ + } + +/* + * Initialize the members of the strmap. Any keys added to the strmap will + * be strdup'ed with their memory managed by the strmap. + */ +void strmap_init(struct strmap *map); + +/* + * Same as strmap_init, but for those who want to control the memory management + * carefully instead of using the default of strdup_strings=1. + */ +void strmap_init_with_options(struct strmap *map, + int strdup_strings); + +/* + * Remove all entries from the map, releasing any allocated resources. + */ +void strmap_clear(struct strmap *map, int free_values); + +/* + * Insert "str" into the map, pointing to "data". + * + * If an entry for "str" already exists, its data pointer is overwritten, and + * the original data pointer returned. Otherwise, returns NULL. + */ +void *strmap_put(struct strmap *map, const char *str, void *data); + +/* + * Return the data pointer mapped by "str", or NULL if the entry does not + * exist. + */ +void *strmap_get(struct strmap *map, const char *str); + +/* + * Return non-zero iff "str" is present in the map. This differs from + * strmap_get() in that it can distinguish entries with a NULL data pointer. + */ +int strmap_contains(struct strmap *map, const char *str); + +#endif /* STRMAP_H */ From patchwork Fri Nov 6 00:24:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885561 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A907BC388F7 for ; Fri, 6 Nov 2020 00:25:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5ADAE2083B for ; Fri, 6 Nov 2020 00:25:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Z6+fLeny" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732931AbgKFAZT (ORCPT ); Thu, 5 Nov 2020 19:25:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53082 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732848AbgKFAZJ (ORCPT ); Thu, 5 Nov 2020 19:25:09 -0500 Received: from mail-wm1-x341.google.com (mail-wm1-x341.google.com [IPv6:2a00:1450:4864:20::341]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8F43AC0613CF for ; Thu, 5 Nov 2020 16:25:07 -0800 (PST) Received: by mail-wm1-x341.google.com with SMTP id c18so3275467wme.2 for ; Thu, 05 Nov 2020 16:25:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=LohV9wz4XDfYNIAtf11Guo8xRjkzYRDWgPPI+0a6uSM=; b=Z6+fLenyd4rzOKeMIFqb9yQG1e5FPbTopvHGdkxdR0875kuHlEa5UWiVWM+YF0IX3k dyMPh2kjiY2IxcKrJd8+fU+XAtFpiFWpe6bg9FpLavC94iFqaS8MBZMQ9MIPjDW0QuBH zYjjFRwRTJLadsB8kGHCokRaBEzebAD7Ex8ADYW3B6NyoXAledSp5a9yZW8DJEQ8bUYR QxLZX8qePQAi1fYmj3IBmt1FBTYMjL8tu357oOerDyP1KjxKeAjfCTFKv2HyunQUgHCJ Qvg8g+JWsMjucDULGsPqz6RtaUkmnHOh99fUUQPqKhIJQi57YHmu5bB25A3DO6mBgxPe 217A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=LohV9wz4XDfYNIAtf11Guo8xRjkzYRDWgPPI+0a6uSM=; b=DfOSHV3uor2OgTeu9wkbbga8fNWgvbVPOh98ud51oLpzAoUpq7OE2FL4mcf89soVwn iTVpVdeJsZgF6n17zdmcnia6p0HwEEOCfRNXSGD/GfPoWKO+7cHW50T7nqgPcxdmhXPc twp6s+bh//ki44/vAs6KzosTm6BDi0fRUHRAk7TS+zjMS/NHAIrFU7gNlB54Qja/N45I M4EgwbTnkoOjK034Q5kvuCNykLCScS9gHI2mM4CxHAhqq/MylFjFqGHHLxjZpUStu8+z zckp1DKlP/D0fQ1b+PdHGUE/8n6Mf+eItQ5piDzUwS6iN4RdD1/2GlNR6TMDQgJ8Yrq8 WT6A== X-Gm-Message-State: AOAM531mCXFsOtmgLS/iFxyCTOsDjlRsdfGa66Ng/I97KstuTEh0b9is odiHNduHZ7rSCwKjy+OhEmml4Ijyi1o= X-Google-Smtp-Source: ABdhPJyt+fI1ijLIK89y4kSLxJoIrzOwhA5NdRpefGPZA+DlmRNu7T6tzk1ZhZl/8kbUub2oU3VDTw== X-Received: by 2002:a1c:f417:: with SMTP id z23mr5022672wma.57.1604622306110; Thu, 05 Nov 2020 16:25:06 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id o184sm4895321wmo.37.2020.11.05.16.25.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:05 -0800 (PST) Message-Id: <5e8004c728580589cdaf46d755f2c977feaffb34.1604622299.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:50 +0000 Subject: [PATCH v5 07/15] strmap: add more utility functions Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren This adds a number of additional convienence functions I want/need: * strmap_get_size() * strmap_empty() * strmap_remove() * strmap_for_each_entry() * strmap_get_entry() I suspect the first four are self-explanatory. strmap_get_entry() is similar to strmap_get() except that instead of just returning the void* value that the string maps to, it returns the strmap_entry that contains both the string and the void* value (or NULL if the string isn't in the map). This is helpful because it avoids multiple lookups, e.g. in some cases a caller would need to call: * strmap_contains() to check that the map has an entry for the string * strmap_get() to get the void* value * * strmap_put() to update/overwrite the value If the void* pointer returned really is a pointer, then the last step is unnecessary, but if the void* pointer is just cast to an integer then strmap_put() will be needed. In contrast, one can call strmap_get_entry() and then: * check if the string was in the map by whether the pointer is NULL * access the value via entry->value * directly update entry->value meaning that we can replace two or three hash table lookups with one. Signed-off-by: Elijah Newren --- strmap.c | 20 ++++++++++++++++++++ strmap.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/strmap.c b/strmap.c index 53f284eb20..829f1bc095 100644 --- a/strmap.c +++ b/strmap.c @@ -87,6 +87,11 @@ void *strmap_put(struct strmap *map, const char *str, void *data) return old; } +struct strmap_entry *strmap_get_entry(struct strmap *map, const char *str) +{ + return find_strmap_entry(map, str); +} + void *strmap_get(struct strmap *map, const char *str) { struct strmap_entry *entry = find_strmap_entry(map, str); @@ -97,3 +102,18 @@ int strmap_contains(struct strmap *map, const char *str) { return find_strmap_entry(map, str) != NULL; } + +void strmap_remove(struct strmap *map, const char *str, int free_value) +{ + struct strmap_entry entry, *ret; + hashmap_entry_init(&entry.ent, strhash(str)); + entry.key = str; + ret = hashmap_remove_entry(&map->map, &entry, ent, NULL); + if (!ret) + return; + if (free_value) + free(ret->value); + if (map->strdup_strings) + free((char*)ret->key); + free(ret); +} diff --git a/strmap.h b/strmap.h index 96888c23ad..f74bc582e4 100644 --- a/strmap.h +++ b/strmap.h @@ -50,6 +50,12 @@ void strmap_clear(struct strmap *map, int free_values); */ void *strmap_put(struct strmap *map, const char *str, void *data); +/* + * Return the strmap_entry mapped by "str", or NULL if there is not such + * an item in map. + */ +struct strmap_entry *strmap_get_entry(struct strmap *map, const char *str); + /* * Return the data pointer mapped by "str", or NULL if the entry does not * exist. @@ -62,4 +68,32 @@ void *strmap_get(struct strmap *map, const char *str); */ int strmap_contains(struct strmap *map, const char *str); +/* + * Remove the given entry from the strmap. If the string isn't in the + * strmap, the map is not altered. + */ +void strmap_remove(struct strmap *map, const char *str, int free_value); + +/* + * Return how many entries the strmap has. + */ +static inline unsigned int strmap_get_size(struct strmap *map) +{ + return hashmap_get_size(&map->map); +} + +/* + * Return whether the strmap is empty. + */ +static inline int strmap_empty(struct strmap *map) +{ + return strmap_get_size(map) == 0; +} + +/* + * iterate through @map using @iter, @var is a pointer to a type strmap_entry + */ +#define strmap_for_each_entry(mystrmap, iter, var) \ + hashmap_for_each_entry(&(mystrmap)->map, iter, var, ent) + #endif /* STRMAP_H */ From patchwork Fri Nov 6 00:24:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885547 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 19CACC56201 for ; Fri, 6 Nov 2020 00:25:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B8A332083B for ; Fri, 6 Nov 2020 00:25:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="PuJiC3nw" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732925AbgKFAZS (ORCPT ); Thu, 5 Nov 2020 19:25:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53086 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732854AbgKFAZJ (ORCPT ); Thu, 5 Nov 2020 19:25:09 -0500 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 61CE6C0613D2 for ; Thu, 5 Nov 2020 16:25:08 -0800 (PST) Received: by mail-wm1-x342.google.com with SMTP id v5so3272595wmh.1 for ; Thu, 05 Nov 2020 16:25:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=egrP2YxGIqUqE7lI0Iu1Sp/CnRg8F1CK39E/Ny45G70=; b=PuJiC3nwFGGkdnYhE0qqe1gdYhon0Jcc6K5vXWxQuo539dap7QFVH5MR23tis3Vczp XYVfib87B+kRS2KA0VlJC/mlZhttcUsZVDRSJ+P/Za4wyihL06zEEJdFMxT+A4UKmtMk Vk2D2W1WmwWIe8c/paybMjVFVqxDY5sgXtcgSo3wxGh8oryc8YzmL+Z9FYCRgIl23zen Ytx8cWFeqEztl4c4xdOdF0oa4kHaiw5B9aVUfMQSjaIo7EcAlI8VINcGDN8xxCo6FU6H RB3Z27Z+FfUNAi0FiUizAqWVVw3vo9pyTfmTygDx2UtcAn8bWL0/JwUbz9au3Wg83e59 /Big== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=egrP2YxGIqUqE7lI0Iu1Sp/CnRg8F1CK39E/Ny45G70=; b=ds4nGN0xKDV/lTlJuitFEXOD/bqPexFTIEEvWRFYKH2rNfOhQbtOpJhtMPLp5MVWop ROJgNGkkiJEMqgcuYwi/63fLQnoViWXxIQkMsFaBvGTwm5JeqytIGoDlPVtOkPMw1D3m lokKIw5rs7ipilb6Fa6tAoQZFLm2zClgW+gOx2dS2J96f5FxUm5r/6QG+R/A0UQ/ujAV 3v2RYwgVqKVe0CLULcI2VXnZRhEYlmD/+K5pn01En/BGifckHhIcNKNf/DwEbRiu4tZL km93ZvIPkosyD2TKNs148OxQ1CTHxV06HHkq0qmsuWFgTLoGupTmtgatt/GHHRd+7d8F VWhg== X-Gm-Message-State: AOAM5306xpqdmMQDHcnWvJbY/YUee4SUVEFnoQKp14aSJYScpiNgdv/v D2ZLmyMVx20ZDWYV6U8jDDCxNVzN2Lo= X-Google-Smtp-Source: ABdhPJybXMT7XgG4yBZPr82pw+BEmpG093RRWYJRYwb7fLCIc2bx5vParXBPaOy4JodcL4QJ6bqPDw== X-Received: by 2002:a7b:cc13:: with SMTP id f19mr5120627wmh.44.1604622306967; Thu, 05 Nov 2020 16:25:06 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id y10sm4889658wru.94.2020.11.05.16.25.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:06 -0800 (PST) Message-Id: In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:51 +0000 Subject: [PATCH v5 08/15] strmap: enable faster clearing and reusing of strmaps Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren When strmaps are used heavily, such as is done by my new merge-ort algorithm, and strmaps need to be cleared but then re-used (because of e.g. picking multiple commits to cherry-pick, or due to a recursive merge having several different merges while recursing), free-ing and reallocating map->table repeatedly can add up in time, especially since it will likely be reallocated to a much smaller size but the previous merge provides a good guide to the right size to use for the next merge. Introduce strmap_partial_clear() to take advantage of this type of situation; it will act similar to strmap_clear() except that map->table's entries are zeroed instead of map->table being free'd. Making use of this function reduced the cost of clear_or_reinit_internal_opts() by about 20% in mert-ort, and dropped the overall runtime of my rebase testcase by just under 2%. Signed-off-by: Elijah Newren --- strmap.c | 6 ++++++ strmap.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/strmap.c b/strmap.c index 829f1bc095..c410c5241a 100644 --- a/strmap.c +++ b/strmap.c @@ -64,6 +64,12 @@ void strmap_clear(struct strmap *map, int free_values) hashmap_clear(&map->map); } +void strmap_partial_clear(struct strmap *map, int free_values) +{ + strmap_free_entries_(map, free_values); + hashmap_partial_clear(&map->map); +} + void *strmap_put(struct strmap *map, const char *str, void *data) { struct strmap_entry *entry = find_strmap_entry(map, str); diff --git a/strmap.h b/strmap.h index f74bc582e4..c14fcee148 100644 --- a/strmap.h +++ b/strmap.h @@ -42,6 +42,12 @@ void strmap_init_with_options(struct strmap *map, */ void strmap_clear(struct strmap *map, int free_values); +/* + * Similar to strmap_clear() but leaves map->map->table allocated and + * pre-sized so that subsequent uses won't need as many rehashings. + */ +void strmap_partial_clear(struct strmap *map, int free_values); + /* * Insert "str" into the map, pointing to "data". * From patchwork Fri Nov 6 00:24:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885557 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DBFB6C55178 for ; Fri, 6 Nov 2020 00:25:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 81BA020885 for ; Fri, 6 Nov 2020 00:25:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="pRkOwLpb" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732920AbgKFAZR (ORCPT ); Thu, 5 Nov 2020 19:25:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53090 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732855AbgKFAZK (ORCPT ); Thu, 5 Nov 2020 19:25:10 -0500 Received: from mail-wr1-x442.google.com (mail-wr1-x442.google.com [IPv6:2a00:1450:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2F354C0613D3 for ; Thu, 5 Nov 2020 16:25:09 -0800 (PST) Received: by mail-wr1-x442.google.com with SMTP id y12so3756951wrp.6 for ; Thu, 05 Nov 2020 16:25:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=h5PnHyptBUWzu+AN7UGcuZ3DQJK/OQ/2tdMdIpZtNLg=; b=pRkOwLpbe4PqYuhJGprSdcjYpGoUHi94/JO9Hv5jjUhGuw59BPAO3i39OOeGP448WU aR5j4D0hBjC+s5fH270KaDwbMO+7tgSSZRRTzhOtCNefO36JKEIeieB1rRK1Dtl1BO9n RL1Rlk0zWu9+jflOqGrDi19S2M0YDswFsw2No1XuIpbELGT8rOzmcPImsheoBrYx2zH0 83k0g7INs7uPp13rvU3iVdkU57qVX9PuoUgJRbB5YjvfWDdZolUM48a1XBzpyx6l8T44 JgWCIdRrKUM6uJSlSSwdskoAGjgRJMxwTXLbUxSTGbJHca/qug4k7pnI4lws8loT8WzZ mc7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=h5PnHyptBUWzu+AN7UGcuZ3DQJK/OQ/2tdMdIpZtNLg=; b=YuN4LxF/uPHrCbxLxjqLUeS9J2gpsI0St23ed7Fk6visJjmhDW/ZVtsx+Q82baxu4v OmBqRPI62paktPyIKt3mFTC7Tzsh//Gn2B+X7Ra/m5oh26rwmpowGEPrZCXEGKN1WMW4 QFW1jZ8zFF7QxyHxXwdeqwzLjpzR1f7SHgZWsuykz8s5erBVl6xiTXcuQu6fB2QeCQB8 twJz8ExqqIUQtIth45In4tHSbhRp6HIZ7FFtbwNf+UsXS+pl8oGFZU08YCa+SqYBYzdg fy2Vtw9GfH1UvDezAQp2gCfIXtQbnz0OZzKkbYsvdQBkGChrmXL/kNzzNOHy3XtcbCeF gyrQ== X-Gm-Message-State: AOAM533QWNB8fferIIYffMy5X1/x8rPkStTSW4VFqdHFXrCKddMgVhay RPSLdUg0e+R6X+k3ftsPy02lO5DoXjM= X-Google-Smtp-Source: ABdhPJxwCDk08SpKWcbA0arnpWye4dAVRKwV+nw9a1yy6fbaODREsb+S/P5KTYw0qoRUiwUkivdlgg== X-Received: by 2002:adf:9d44:: with SMTP id o4mr6098017wre.229.1604622307821; Thu, 05 Nov 2020 16:25:07 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id g131sm4800917wma.35.2020.11.05.16.25.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:07 -0800 (PST) Message-Id: In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:52 +0000 Subject: [PATCH v5 09/15] strmap: add functions facilitating use as a string->int map Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Although strmap could be used as a string->int map, one either had to allocate an int for every entry and then deallocate later, or one had to do a bunch of casting between (void*) and (intptr_t). Add some special functions that do the casting. Also, rename put->set for such wrapper functions since 'put' implied there may be some deallocation needed if the string was already found in the map, which isn't the case when we're storing an int value directly in the void* slot instead of using the void* slot as a pointer to data. Signed-off-by: Elijah Newren --- strmap.c | 11 +++++++ strmap.h | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/strmap.c b/strmap.c index c410c5241a..0d10a884b5 100644 --- a/strmap.c +++ b/strmap.c @@ -123,3 +123,14 @@ void strmap_remove(struct strmap *map, const char *str, int free_value) free((char*)ret->key); free(ret); } + +void strintmap_incr(struct strintmap *map, const char *str, intptr_t amt) +{ + struct strmap_entry *entry = find_strmap_entry(&map->map, str); + if (entry) { + intptr_t *whence = (intptr_t*)&entry->value; + *whence += amt; + } + else + strintmap_set(map, str, map->default_value + amt); +} diff --git a/strmap.h b/strmap.h index c14fcee148..56a5cdb864 100644 --- a/strmap.h +++ b/strmap.h @@ -23,6 +23,10 @@ int cmp_strmap_entry(const void *hashmap_cmp_fn_data, .map = HASHMAP_INIT(cmp_strmap_entry, NULL), \ .strdup_strings = 1, \ } +#define STRINTMAP_INIT { \ + .map = STRMAP_INIT, \ + .default_value = 0, \ + } /* * Initialize the members of the strmap. Any keys added to the strmap will @@ -102,4 +106,94 @@ static inline int strmap_empty(struct strmap *map) #define strmap_for_each_entry(mystrmap, iter, var) \ hashmap_for_each_entry(&(mystrmap)->map, iter, var, ent) + +/* + * strintmap: + * A map of string -> int, typecasting the void* of strmap to an int. + * + * Primary differences: + * 1) Since the void* value is just an int in disguise, there is no value + * to free. (Thus one fewer argument to strintmap_clear) + * 2) strintmap_get() returns an int, or returns the default_value if the + * key is not found in the strintmap. + * 3) No strmap_put() equivalent; strintmap_set() and strintmap_incr() + * instead. + */ + +struct strintmap { + struct strmap map; + int default_value; +}; + +#define strintmap_for_each_entry(mystrmap, iter, var) \ + strmap_for_each_entry(&(mystrmap)->map, iter, var) + +static inline void strintmap_init(struct strintmap *map, int default_value) +{ + strmap_init(&map->map); + map->default_value = default_value; +} + +static inline void strintmap_init_with_options(struct strintmap *map, + int default_value, + int strdup_strings) +{ + strmap_init_with_options(&map->map, strdup_strings); + map->default_value = default_value; +} + +static inline void strintmap_clear(struct strintmap *map) +{ + strmap_clear(&map->map, 0); +} + +static inline void strintmap_partial_clear(struct strintmap *map) +{ + strmap_partial_clear(&map->map, 0); +} + +static inline int strintmap_contains(struct strintmap *map, const char *str) +{ + return strmap_contains(&map->map, str); +} + +static inline void strintmap_remove(struct strintmap *map, const char *str) +{ + return strmap_remove(&map->map, str, 0); +} + +static inline int strintmap_empty(struct strintmap *map) +{ + return strmap_empty(&map->map); +} + +static inline unsigned int strintmap_get_size(struct strintmap *map) +{ + return strmap_get_size(&map->map); +} + +/* + * Returns the value for str in the map. If str isn't found in the map, + * the map's default_value is returned. + */ +static inline int strintmap_get(struct strintmap *map, const char *str) +{ + struct strmap_entry *result = strmap_get_entry(&map->map, str); + if (!result) + return map->default_value; + return (intptr_t)result->value; +} + +static inline void strintmap_set(struct strintmap *map, const char *str, + intptr_t v) +{ + strmap_put(&map->map, str, (void *)v); +} + +/* + * Increment the value for str by amt. If str isn't in the map, add it and + * set its value to default_value + amt. + */ +void strintmap_incr(struct strintmap *map, const char *str, intptr_t amt); + #endif /* STRMAP_H */ From patchwork Fri Nov 6 00:24:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885555 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 76ED2C55178 for ; Fri, 6 Nov 2020 00:25:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2AAAC2083B for ; Fri, 6 Nov 2020 00:25:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="erNvoEI+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732896AbgKFAZM (ORCPT ); Thu, 5 Nov 2020 19:25:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53098 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732396AbgKFAZL (ORCPT ); Thu, 5 Nov 2020 19:25:11 -0500 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BE908C0613CF for ; Thu, 5 Nov 2020 16:25:10 -0800 (PST) Received: by mail-wm1-x344.google.com with SMTP id d142so3270849wmd.4 for ; Thu, 05 Nov 2020 16:25:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=SRd5zzuJ5YWrv3J1rtWTYj322wIQAFH2zDfaZkFQEEQ=; b=erNvoEI+sf1rUxUogd82wDyzsxBfBI443l4C4P2K2T0Ma1uAQwvdICCF1J0bIj9uOi KuoVlunzMlwMu9Wpt8o5AZhEqGzRGDD3d389/eC57FjPtX4kEx+qwtf6lMng94O/uYW3 lN2cMR/qvC8Yx5nSr7XwyUdyr5nfJ335WzSBQh5I4y9EhvpJ41hqpWPfGYws2FhQOHsz G6Mv5XJK04uMMIkLoeG/KOwS1Uohjl3Vqccj1Axgfc0luj18wxn2yf+foGP4/eXZQRhS P4rEfak20DESpxkDLxU8pvl8qxwpG48bpgcl7D0kaGkuK6k+WO0mbk4H/Aihq9l4q3+b qD+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=SRd5zzuJ5YWrv3J1rtWTYj322wIQAFH2zDfaZkFQEEQ=; b=Tz5orXYf4mW7z6FwYUyP35CooiuswM/C2N/FFlej/Jo7kI9Dc18Me6aAB5kx8WZSzq xh+JUoUpRNHLZhrygtX12u0CIqhjaf/VScx77kTfpWA2RKW8rC2o9ucSjD2I+qkrkRM0 AfOoregBXeLlV6R5SpDwqxiHdTkQrCAgAICvx4finYdHOczr5rxW2tYA/S0M/fZ3wz1C S0LD7V428wbNcZWUnPRh+RvRJDVCOHYFy01dO85cvHXZQTG5kQRRW1UeNBhChr87dK4C AJ1R0i12tDPNlbJz240U5l16YIJaF9VXfpCv1HgYRwkVWBaAh9OnRm5f6dIm6rDUR1+L +zew== X-Gm-Message-State: AOAM5321iykVHwXaHE8reKHNAsANH+p2Hym++uT+DtiehuB0KWBhhA72 5SMmWYStuveMq13HMuS65WiXd/HLLSI= X-Google-Smtp-Source: ABdhPJza6iRBa4B42Ib+OpjzByPN1x7eS4amCwXZRVjUmeI0v72vutbg6cBDDIsXAJDr0BsDSJOEjA== X-Received: by 2002:a7b:ce99:: with SMTP id q25mr1538922wmj.35.1604622309350; Thu, 05 Nov 2020 16:25:09 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id z2sm4552831wmf.45.2020.11.05.16.25.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:08 -0800 (PST) Message-Id: In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:54 +0000 Subject: [PATCH v5 11/15] strmap: add a strset sub-type Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Similar to adding strintmap for special-casing a string -> int mapping, add a strset type for cases where we really are only interested in using strmap for storing a set rather than a mapping. In this case, we'll always just store NULL for the value but the different struct type makes it clearer than code comments how a variable is intended to be used. The difference in usage also results in some differences in API: a few things that aren't necessary or meaningful are dropped (namely, the free_values argument to *_clear(), and the *_get() function), and strset_add() is chosen as the API instead of strset_put(). Signed-off-by: Elijah Newren --- strmap.c | 17 +++++++++++++++ strmap.h | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/strmap.c b/strmap.c index dc84c57c07..3784865745 100644 --- a/strmap.c +++ b/strmap.c @@ -143,3 +143,20 @@ void strintmap_incr(struct strintmap *map, const char *str, intptr_t amt) else strintmap_set(map, str, map->default_value + amt); } + +int strset_add(struct strset *set, const char *str) +{ + /* + * Cannot use strmap_put() because it'll return NULL in both cases: + * - cannot find str: NULL means "not found" + * - does find str: NULL is the value associated with str + */ + struct strmap_entry *entry = find_strmap_entry(&set->map, str); + + if (entry) + return 0; + + entry = create_entry(&set->map, str, NULL); + hashmap_add(&set->map.map, &entry->ent); + return 1; +} diff --git a/strmap.h b/strmap.h index 56a5cdb864..c8c4d7c932 100644 --- a/strmap.h +++ b/strmap.h @@ -27,6 +27,7 @@ int cmp_strmap_entry(const void *hashmap_cmp_fn_data, .map = STRMAP_INIT, \ .default_value = 0, \ } +#define STRSET_INIT { .map = STRMAP_INIT } /* * Initialize the members of the strmap. Any keys added to the strmap will @@ -196,4 +197,66 @@ static inline void strintmap_set(struct strintmap *map, const char *str, */ void strintmap_incr(struct strintmap *map, const char *str, intptr_t amt); +/* + * strset: + * A set of strings. + * + * Primary differences with strmap: + * 1) The value is always NULL, and ignored. As there is no value to free, + * there is one fewer argument to strset_clear + * 2) No strset_get() because there is no value. + * 3) No strset_put(); use strset_add() instead. + */ + +struct strset { + struct strmap map; +}; + +#define strset_for_each_entry(mystrset, iter, var) \ + strmap_for_each_entry(&(mystrset)->map, iter, var) + +static inline void strset_init(struct strset *set) +{ + strmap_init(&set->map); +} + +static inline void strset_init_with_options(struct strset *set, + int strdup_strings) +{ + strmap_init_with_options(&set->map, strdup_strings); +} + +static inline void strset_clear(struct strset *set) +{ + strmap_clear(&set->map, 0); +} + +static inline void strset_partial_clear(struct strset *set) +{ + strmap_partial_clear(&set->map, 0); +} + +static inline int strset_contains(struct strset *set, const char *str) +{ + return strmap_contains(&set->map, str); +} + +static inline void strset_remove(struct strset *set, const char *str) +{ + return strmap_remove(&set->map, str, 0); +} + +static inline int strset_empty(struct strset *set) +{ + return strmap_empty(&set->map); +} + +static inline unsigned int strset_get_size(struct strset *set) +{ + return strmap_get_size(&set->map); +} + +/* Returns 1 if str is added to the set; returns 0 if str was already in set */ +int strset_add(struct strset *set, const char *str); + #endif /* STRMAP_H */ From patchwork Fri Nov 6 00:24:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885559 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D3803C55ABD for ; Fri, 6 Nov 2020 00:25:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9BA1E2078E for ; Fri, 6 Nov 2020 00:25:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="IK1A76Jx" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732940AbgKFAZW (ORCPT ); Thu, 5 Nov 2020 19:25:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53102 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732415AbgKFAZN (ORCPT ); Thu, 5 Nov 2020 19:25:13 -0500 Received: from mail-wm1-x341.google.com (mail-wm1-x341.google.com [IPv6:2a00:1450:4864:20::341]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9054EC0613CF for ; Thu, 5 Nov 2020 16:25:11 -0800 (PST) Received: by mail-wm1-x341.google.com with SMTP id h62so3267865wme.3 for ; Thu, 05 Nov 2020 16:25:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=oDqAPiMSYogqfXkQP5TzwWmT+q+GHXhCnLOLobwDf/A=; b=IK1A76Jx92eKd4S+5UQvvEK/p8LMpqZ+Z8WOPoRsgXpk7+sDBwnI13sI3CRLf++8g6 +F3yUVuhJrX6rZkCmxoV+ynIzdduhzP5XP9IBHby1EZSWTDbq1j1AAQOaWpSpO6Dhwti 2/2lukye0UmcQ+Brh/Cxzh8ZzUopKTZnWfsguT2pELr8RIqpRlpzQ553iqorfqVxTZ5x Q86FPOVTON0yyeQI6hZOEUAzNNmXdKjIucCqUpy1E3XGejj/c+qzYxasJI4X5u2mBmtY 75KEX2ymPeITzDvI+8YHMLuY+h1jNGwqR/1bSmnXx+jZw4CA7zd2HVRw4xikgUXmONoM 5CJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=oDqAPiMSYogqfXkQP5TzwWmT+q+GHXhCnLOLobwDf/A=; b=Y1cow5PVhVzOnT7m0RVI8+GndAR2vuyrjn9qsQKwqlAvmVbFx91CyFHUOr16K0869Z JcidAUmGK8wvRuEoW4hNpHpexHQ3D1XkrpiAmEVlWryyXIeq4OD2g0Eabu/1n4tL3jmX yBFH9Eo4OA6oUKvNe16Rjc7acLyP2Uc3LGfkkLV4LZ/brOM6Yva+bK+IVRAZ1ISFVFny nFdAA9bQFyfnlupVpSJTVi9W9+4q2WOJnyDweY66kHwGYS45PG4AtFId0waahTnzyWrq y+XJgt5VNq7jqTLSseEGFan7cevtForxjtWBLgr56Hv/dYPmA1bFaFbYKe5jvsvhrtjC +lnA== X-Gm-Message-State: AOAM532PSp/FAmCWyFqJc7CKfx5S31DJAlRVaiuucrN9M8MfIsFQPEiB awCpWdw0ftG7J6qLXL74NF5DmV76Dqc= X-Google-Smtp-Source: ABdhPJwtGZXp53dEc2KGlFqM5+ZTAMGpA0BtyAvjCZ0HKiGcBvxoRtCWxZvZ84dWAbbUyku8tPLddQ== X-Received: by 2002:a1c:61d4:: with SMTP id v203mr5184335wmb.1.1604622310185; Thu, 05 Nov 2020 16:25:10 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id i33sm5031038wri.79.2020.11.05.16.25.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:09 -0800 (PST) Message-Id: <34f542d9dd846da5fd81274966ee2ebe0660dcef.1604622299.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:55 +0000 Subject: [PATCH v5 12/15] strmap: enable allocations to come from a mem_pool Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren For heavy users of strmaps, allowing the keys and entries to be allocated from a memory pool can provide significant overhead savings. Add an option to strmap_init_with_options() to specify a memory pool. Signed-off-by: Elijah Newren --- strmap.c | 31 ++++++++++++++++++++++--------- strmap.h | 11 ++++++++--- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/strmap.c b/strmap.c index 3784865745..139afb9d4b 100644 --- a/strmap.c +++ b/strmap.c @@ -1,5 +1,6 @@ #include "git-compat-util.h" #include "strmap.h" +#include "mem-pool.h" int cmp_strmap_entry(const void *hashmap_cmp_fn_data, const struct hashmap_entry *entry1, @@ -24,13 +25,15 @@ static struct strmap_entry *find_strmap_entry(struct strmap *map, void strmap_init(struct strmap *map) { - strmap_init_with_options(map, 1); + strmap_init_with_options(map, NULL, 1); } void strmap_init_with_options(struct strmap *map, + struct mem_pool *pool, int strdup_strings) { hashmap_init(&map->map, cmp_strmap_entry, NULL, 0); + map->pool = pool; map->strdup_strings = strdup_strings; } @@ -42,6 +45,10 @@ static void strmap_free_entries_(struct strmap *map, int free_values) if (!map) return; + if (!free_values && map->pool) + /* Memory other than util is owned by and freed with the pool */ + return; + /* * We need to iterate over the hashmap entries and free * e->key and e->value ourselves; hashmap has no API to @@ -52,9 +59,11 @@ static void strmap_free_entries_(struct strmap *map, int free_values) hashmap_for_each_entry(&map->map, &iter, e, ent) { if (free_values) free(e->value); - if (map->strdup_strings) - free((char*)e->key); - free(e); + if (!map->pool) { + if (map->strdup_strings) + free((char*)e->key); + free(e); + } } } @@ -77,11 +86,13 @@ static struct strmap_entry *create_entry(struct strmap *map, struct strmap_entry *entry; const char *key = str; - entry = xmalloc(sizeof(*entry)); + entry = map->pool ? mem_pool_alloc(map->pool, sizeof(*entry)) + : xmalloc(sizeof(*entry)); hashmap_entry_init(&entry->ent, strhash(str)); if (map->strdup_strings) - key = xstrdup(str); + key = map->pool ? mem_pool_strdup(map->pool, str) + : xstrdup(str); entry->key = key; entry->value = data; return entry; @@ -128,9 +139,11 @@ void strmap_remove(struct strmap *map, const char *str, int free_value) return; if (free_value) free(ret->value); - if (map->strdup_strings) - free((char*)ret->key); - free(ret); + if (!map->pool) { + if (map->strdup_strings) + free((char*)ret->key); + free(ret); + } } void strintmap_incr(struct strintmap *map, const char *str, intptr_t amt) diff --git a/strmap.h b/strmap.h index c8c4d7c932..dda928703d 100644 --- a/strmap.h +++ b/strmap.h @@ -3,8 +3,10 @@ #include "hashmap.h" +struct mempool; struct strmap { struct hashmap map; + struct mem_pool *pool; unsigned int strdup_strings:1; }; @@ -37,9 +39,10 @@ void strmap_init(struct strmap *map); /* * Same as strmap_init, but for those who want to control the memory management - * carefully instead of using the default of strdup_strings=1. + * carefully instead of using the default of strdup_strings=1 and pool=NULL. */ void strmap_init_with_options(struct strmap *map, + struct mem_pool *pool, int strdup_strings); /* @@ -137,9 +140,10 @@ static inline void strintmap_init(struct strintmap *map, int default_value) static inline void strintmap_init_with_options(struct strintmap *map, int default_value, + struct mem_pool *pool, int strdup_strings) { - strmap_init_with_options(&map->map, strdup_strings); + strmap_init_with_options(&map->map, pool, strdup_strings); map->default_value = default_value; } @@ -221,9 +225,10 @@ static inline void strset_init(struct strset *set) } static inline void strset_init_with_options(struct strset *set, + struct mem_pool *pool, int strdup_strings) { - strmap_init_with_options(&set->map, strdup_strings); + strmap_init_with_options(&set->map, pool, strdup_strings); } static inline void strset_clear(struct strset *set) From patchwork Fri Nov 6 00:24:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885537 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0F5A5C4742C for ; Fri, 6 Nov 2020 00:25:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AA1022083B for ; Fri, 6 Nov 2020 00:25:16 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="chuWo6pJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732897AbgKFAZP (ORCPT ); Thu, 5 Nov 2020 19:25:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53106 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732396AbgKFAZM (ORCPT ); Thu, 5 Nov 2020 19:25:12 -0500 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 60AF4C0613D2 for ; Thu, 5 Nov 2020 16:25:12 -0800 (PST) Received: by mail-wr1-x444.google.com with SMTP id w14so3743783wrs.9 for ; Thu, 05 Nov 2020 16:25:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=gDPxI4KbSCR3dgp72y0tDa6WsinTjNkrQA/6H8tPuC4=; b=chuWo6pJ75rHihub/fUxku3bcIUiOd4r598UqZfMM17/hY6l4d0Xw3Z2zlazjQWXRa CalVdEvA7WdzAbLd8zoD5GqXW3YB94NdlkjWqs8uxeJrZBGT4abEhElWDinV+ayPeGLM 63pjxn6wIjA9cwdLMi0U4xe6RKRnjmZW+5bMi/hZvWhqvG09FUr76jcMJFyUyPHfHbcM Tt6zRW5gKH1OKBGz+0cXZMiueWjkYSXEtjOJt2CjuEcuHoTlaoIHkaHw2K1XjxzeUitP aiOMfqWaPloL7uL4SgeQGQndB/AQnk79iGtP+asvXbznb/7kGzLJZf6ZYA6nhJaXn2Is CQMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=gDPxI4KbSCR3dgp72y0tDa6WsinTjNkrQA/6H8tPuC4=; b=bJRIQSLwTa22fKgCJP8Jr8TueE//g1W2JkRVhdGajocQQkPu83UGnl2VdQsnlbpnqG vEDfeqDC3BLvR4jmv7l1xXKaAoXbkWD0FoVb99uXOT07OPQe4mW9FwvTdqu928uvxwCD uIc7y3nKIXdXi39BoQKDox/uI8ojD/lDecr5Uhc4BSpxUs/HnK2t+k8zQsyrIHHnFIf3 fmvgg6lHOJdQ5Yy7mMxnQ6/6CsmoE0HyNibTmbuLCvmnclehvOBs1+NRi8Gk1xANHnHj 14qK3KRkNVZZzfvY3oNVRRO/6QM6WeC1Gcnd3nFQbLEnMjPkMhbyDAxq+b8wC0PGlBjM SntQ== X-Gm-Message-State: AOAM5338AP+aLQwz7GxtzSh6DNrU9O8s0J5yMp+FZUN7jTaFkP3onO4z Phocx9EChiXq4o/mH/oRK2aPSHL7MNQ= X-Google-Smtp-Source: ABdhPJzA9E/N9cv4fnUQSTmb5brZWjSyFX1EqtfgApA1hk/ozCulR/9ke4WgLP9xBb+d7w2/NeetyQ== X-Received: by 2002:adf:fd06:: with SMTP id e6mr5814330wrr.206.1604622311006; Thu, 05 Nov 2020 16:25:11 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id n8sm4363046wmc.11.2020.11.05.16.25.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:10 -0800 (PST) Message-Id: <39ec2fa4118636f4c994735ab11c1d312eb9771d.1604622299.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:56 +0000 Subject: [PATCH v5 13/15] strmap: take advantage of FLEXPTR_ALLOC_STR when relevant Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren By default, we do not use a mempool and strdup_strings is true; in this case, we can avoid both an extra allocation and an extra free by just over-allocating for the strmap_entry leaving enough space at the end to copy the key. FLEXPTR_ALLOC_STR exists for exactly this purpose, so make use of it. Also, adjust the case when we are using a memory pool and strdup_strings is true to just do one allocation from the memory pool instead of two so that the strmap_clear() and strmap_remove() code can just avoid freeing the key in all cases. Signed-off-by: Elijah Newren --- strmap.c | 35 +++++++++++++++++++---------------- strmap.h | 1 + 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/strmap.c b/strmap.c index 139afb9d4b..4fb9f6100e 100644 --- a/strmap.c +++ b/strmap.c @@ -59,11 +59,8 @@ static void strmap_free_entries_(struct strmap *map, int free_values) hashmap_for_each_entry(&map->map, &iter, e, ent) { if (free_values) free(e->value); - if (!map->pool) { - if (map->strdup_strings) - free((char*)e->key); + if (!map->pool) free(e); - } } } @@ -84,16 +81,25 @@ static struct strmap_entry *create_entry(struct strmap *map, void *data) { struct strmap_entry *entry; - const char *key = str; - entry = map->pool ? mem_pool_alloc(map->pool, sizeof(*entry)) - : xmalloc(sizeof(*entry)); + if (map->strdup_strings) { + if (!map->pool) { + FLEXPTR_ALLOC_STR(entry, key, str); + } else { + size_t len = st_add(strlen(str), 1); /* include NUL */ + entry = mem_pool_alloc(map->pool, + st_add(sizeof(*entry), len)); + memcpy(entry + 1, str, len); + entry->key = (void *)(entry + 1); + } + } else if (!map->pool) { + entry = xmalloc(sizeof(*entry)); + } else { + entry = mem_pool_alloc(map->pool, sizeof(*entry)); + } hashmap_entry_init(&entry->ent, strhash(str)); - - if (map->strdup_strings) - key = map->pool ? mem_pool_strdup(map->pool, str) - : xstrdup(str); - entry->key = key; + if (!map->strdup_strings) + entry->key = str; entry->value = data; return entry; } @@ -139,11 +145,8 @@ void strmap_remove(struct strmap *map, const char *str, int free_value) return; if (free_value) free(ret->value); - if (!map->pool) { - if (map->strdup_strings) - free((char*)ret->key); + if (!map->pool) free(ret); - } } void strintmap_incr(struct strintmap *map, const char *str, intptr_t amt) diff --git a/strmap.h b/strmap.h index dda928703d..a99011df25 100644 --- a/strmap.h +++ b/strmap.h @@ -14,6 +14,7 @@ struct strmap_entry { struct hashmap_entry ent; const char *key; void *value; + /* strmap_entry may be allocated extra space to store the key at end */ }; int cmp_strmap_entry(const void *hashmap_cmp_fn_data, From patchwork Fri Nov 6 00:24:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885565 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 68300C56201 for ; Fri, 6 Nov 2020 00:25:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 133722083B for ; Fri, 6 Nov 2020 00:25:27 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="YO21Ts64" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732914AbgKFAZZ (ORCPT ); Thu, 5 Nov 2020 19:25:25 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53110 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732898AbgKFAZN (ORCPT ); Thu, 5 Nov 2020 19:25:13 -0500 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 589B9C0613D2 for ; Thu, 5 Nov 2020 16:25:13 -0800 (PST) Received: by mail-wm1-x342.google.com with SMTP id c16so3275280wmd.2 for ; Thu, 05 Nov 2020 16:25:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=OA4wQ/JUZvjUd14KqKKplav5D5ohsMHFqJIjlPS/lz8=; b=YO21Ts64TBw74zUwIkLctDbzvCEJHrnzSrGjAUTqLb9AKSdTcShFv5aVODvaAlr7on ilPNI3fOnm7xfqBqNwVevWpCPfv2kfGAUPPx2fQKGhpR2/0pl3I0dSwrK5yE7CXgWRdP bYY6ngj4sFXdNJCksDlp8GAx1ANAqGZTZI9a/5qxoK0Tfp33nXyAigl4SGizKjX5UtZ3 bXDEprUDKClrxci2O32xnYe/mHCvnnkVEAYMJqPX5kXIluvW4Vd5Qu8B/7ZVfuvSz2CV PkBxK3xVidtkHHU8Lz1KlZJV/974KMKkb79YEJfI6mB1+YfALDBVENQHkb0xOKlkVNVT KhSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=OA4wQ/JUZvjUd14KqKKplav5D5ohsMHFqJIjlPS/lz8=; b=aTSDvwodIZFziwJWzw6Tj4I91skuRLY+1EJ0n5iZrzwL3kWQlURZfNl/l4fMPIzLA+ 3KUL8lCl/BxG8coYC84NZn/1fHIGkrg5Jy8aMzcUSS9PtzfFQEaH+deDEwgCPvH4x3Gj 26IO4qM1Cl8NQ9mH/WKj89qnwd6xnDUlMSPO37gOz5L2+rUtwGO8tXulECSNJzFHkJec VSDVl8XWg0trSsMHA+e/pZQ4uxVnf84FOrH8T164YDMWoxqJQ22zwd/GM/qzZa8iDtRM mUpKusMDlLbSJDoKReF1AFs48/i4sa45scPvOKQoOxrITqweVC2826tkXhE28JZUDc+M RPoQ== X-Gm-Message-State: AOAM530iZzWH0I42SF8MjogFVQDiPmYeWdmRol1weekd6YQ3oSOHYK5r NEk6K1bx0TfZkOEQgdQkmILthj/AbuM= X-Google-Smtp-Source: ABdhPJwA3ZF9n6VL3nUpsUrRHxtx01TJT24QSqOs4SlIy+cyPw6BYoz67SEQ6mIdXs/hFNcdrZ3fLA== X-Received: by 2002:a1c:4888:: with SMTP id v130mr5135276wma.84.1604622311779; Thu, 05 Nov 2020 16:25:11 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id k84sm5115337wmf.42.2020.11.05.16.25.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:11 -0800 (PST) Message-Id: In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:57 +0000 Subject: [PATCH v5 14/15] Use new HASHMAP_INIT macro to simplify hashmap initialization Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Now that hashamp has lazy initialization and a HASHMAP_INIT macro, hashmaps allocated on the stack can be initialized without a call to hashmap_init() and in some cases makes the code a bit shorter. Convert some callsites over to take advantage of this. Signed-off-by: Elijah Newren --- attr.c | 26 ++++++++------------------ bloom.c | 3 +-- builtin/difftool.c | 9 ++++----- range-diff.c | 4 +--- revision.c | 9 +-------- t/helper/test-hashmap.c | 3 +-- 6 files changed, 16 insertions(+), 38 deletions(-) diff --git a/attr.c b/attr.c index a826b2ef1f..4ef85d668b 100644 --- a/attr.c +++ b/attr.c @@ -52,13 +52,6 @@ static inline void hashmap_unlock(struct attr_hashmap *map) pthread_mutex_unlock(&map->mutex); } -/* - * The global dictionary of all interned attributes. This - * is a singleton object which is shared between threads. - * Access to this dictionary must be surrounded with a mutex. - */ -static struct attr_hashmap g_attr_hashmap; - /* The container for objects stored in "struct attr_hashmap" */ struct attr_hash_entry { struct hashmap_entry ent; @@ -80,11 +73,14 @@ static int attr_hash_entry_cmp(const void *unused_cmp_data, return (a->keylen != b->keylen) || strncmp(a->key, b->key, a->keylen); } -/* Initialize an 'attr_hashmap' object */ -static void attr_hashmap_init(struct attr_hashmap *map) -{ - hashmap_init(&map->map, attr_hash_entry_cmp, NULL, 0); -} +/* + * The global dictionary of all interned attributes. This + * is a singleton object which is shared between threads. + * Access to this dictionary must be surrounded with a mutex. + */ +static struct attr_hashmap g_attr_hashmap = { + HASHMAP_INIT(attr_hash_entry_cmp, NULL) +}; /* * Retrieve the 'value' stored in a hashmap given the provided 'key'. @@ -96,9 +92,6 @@ static void *attr_hashmap_get(struct attr_hashmap *map, struct attr_hash_entry k; struct attr_hash_entry *e; - if (!map->map.tablesize) - attr_hashmap_init(map); - hashmap_entry_init(&k.ent, memhash(key, keylen)); k.key = key; k.keylen = keylen; @@ -114,9 +107,6 @@ static void attr_hashmap_add(struct attr_hashmap *map, { struct attr_hash_entry *e; - if (!map->map.tablesize) - attr_hashmap_init(map); - e = xmalloc(sizeof(struct attr_hash_entry)); hashmap_entry_init(&e->ent, memhash(key, keylen)); e->key = key; diff --git a/bloom.c b/bloom.c index 719c313a1c..b176f28f53 100644 --- a/bloom.c +++ b/bloom.c @@ -229,10 +229,9 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r, diffcore_std(&diffopt); if (diff_queued_diff.nr <= settings->max_changed_paths) { - struct hashmap pathmap; + struct hashmap pathmap = HASHMAP_INIT(pathmap_cmp, NULL); struct pathmap_hash_entry *e; struct hashmap_iter iter; - hashmap_init(&pathmap, pathmap_cmp, NULL, 0); for (i = 0; i < diff_queued_diff.nr; i++) { const char *path = diff_queued_diff.queue[i]->two->path; diff --git a/builtin/difftool.c b/builtin/difftool.c index 7ac432b881..6e18e623fd 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -342,7 +342,10 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, const char *workdir, *tmp; int ret = 0, i; FILE *fp; - struct hashmap working_tree_dups, submodules, symlinks2; + struct hashmap working_tree_dups = HASHMAP_INIT(working_tree_entry_cmp, + NULL); + struct hashmap submodules = HASHMAP_INIT(pair_cmp, NULL); + struct hashmap symlinks2 = HASHMAP_INIT(pair_cmp, NULL); struct hashmap_iter iter; struct pair_entry *entry; struct index_state wtindex; @@ -383,10 +386,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, rdir_len = rdir.len; wtdir_len = wtdir.len; - hashmap_init(&working_tree_dups, working_tree_entry_cmp, NULL, 0); - hashmap_init(&submodules, pair_cmp, NULL, 0); - hashmap_init(&symlinks2, pair_cmp, NULL, 0); - child.no_stdin = 1; child.git_cmd = 1; child.use_shell = 0; diff --git a/range-diff.c b/range-diff.c index befeecae44..b9950f10c8 100644 --- a/range-diff.c +++ b/range-diff.c @@ -232,11 +232,9 @@ static int patch_util_cmp(const void *dummy, const struct patch_util *a, static void find_exact_matches(struct string_list *a, struct string_list *b) { - struct hashmap map; + struct hashmap map = HASHMAP_INIT((hashmap_cmp_fn)patch_util_cmp, NULL); int i; - hashmap_init(&map, (hashmap_cmp_fn)patch_util_cmp, NULL, 0); - /* First, add the patches of a to a hash map */ for (i = 0; i < a->nr; i++) { struct patch_util *util = a->items[i].util; diff --git a/revision.c b/revision.c index f27649d45d..c6e169e3eb 100644 --- a/revision.c +++ b/revision.c @@ -124,11 +124,6 @@ static int path_and_oids_cmp(const void *hashmap_cmp_fn_data, return strcmp(e1->path, e2->path); } -static void paths_and_oids_init(struct hashmap *map) -{ - hashmap_init(map, path_and_oids_cmp, NULL, 0); -} - static void paths_and_oids_clear(struct hashmap *map) { struct hashmap_iter iter; @@ -213,7 +208,7 @@ void mark_trees_uninteresting_sparse(struct repository *r, struct oidset *trees) { unsigned has_interesting = 0, has_uninteresting = 0; - struct hashmap map; + struct hashmap map = HASHMAP_INIT(path_and_oids_cmp, NULL); struct hashmap_iter map_iter; struct path_and_oids_entry *entry; struct object_id *oid; @@ -237,8 +232,6 @@ void mark_trees_uninteresting_sparse(struct repository *r, if (!has_uninteresting || !has_interesting) return; - paths_and_oids_init(&map); - oidset_iter_init(trees, &iter); while ((oid = oidset_iter_next(&iter))) { struct tree *tree = lookup_tree(r, oid); diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index 2475663b49..36ff07bd4b 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -151,12 +151,11 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) int cmd__hashmap(int argc, const char **argv) { struct strbuf line = STRBUF_INIT; - struct hashmap map; int icase; + struct hashmap map = HASHMAP_INIT(test_entry_cmp, &icase); /* init hash map */ icase = argc > 1 && !strcmp("ignorecase", argv[1]); - hashmap_init(&map, test_entry_cmp, &icase, 0); /* process commands from stdin */ while (strbuf_getline(&line, stdin) != EOF) { From patchwork Fri Nov 6 00:24:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11885563 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0856BC4742C for ; Fri, 6 Nov 2020 00:25:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A5BF220A8B for ; Fri, 6 Nov 2020 00:25:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="LoywFgUd" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732946AbgKFAZX (ORCPT ); Thu, 5 Nov 2020 19:25:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53116 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732906AbgKFAZO (ORCPT ); Thu, 5 Nov 2020 19:25:14 -0500 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 48A2BC0613D3 for ; Thu, 5 Nov 2020 16:25:14 -0800 (PST) Received: by mail-wm1-x344.google.com with SMTP id k18so3273911wmj.5 for ; Thu, 05 Nov 2020 16:25:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=/m8cQExWBEWxoRtNoB5eAbuRwvA8C0BdwF9qLyUY+84=; b=LoywFgUdaHT4wS1n3KRdI7su0gc8hzJuGF6fWuFxEOXudOVdlo8O222r/5x5j55IAI HnRnO39E9FV07QPSYayprAtFk3WGKJCFy+hqUfeuOCRudbtRAJUhdDxzDA+3smIdwK3l t0z6XcpAYFmqYUc5WBOG/Z1yWInJYhpjrP8whC3143CSAlw1c6rWfGxowJSA/JILeFgz 7GPyiqSqk3vxv4AdozLNPxQ5bqR5aCPHWdf9jDDlkQix24VcJ79EXg1ktK/PmpTcauFS 5uEDWe3GPoYrFfvf3sp5Hpyu+xZH12BKk9LsxebXGkW7CjlYlG2UUnAa5rqTUZ/Efy+p LCwQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=/m8cQExWBEWxoRtNoB5eAbuRwvA8C0BdwF9qLyUY+84=; b=fzgvbg2J1Ud4QfqcM/WFLgeehP0wU4Z/xsIGCCEeG/h9Dw2xS1hE38PbDLM72QPnKP HP4MmK0fi6k30ws4xFmkjemZQRB/VyFr8WpBaOA/68crlrj1Fq4zVReINx/XY+1ZaUrD +uxDSSZ2iCu8iQrZ0iIl8KQFWudFkUcznVkFQyRUkqXUIBIwj250k+vF4nov1DzqlZ+j 2Nd92TerF0E/kRwkdhP6e++4aqMnupQqqZ7/I/921og2YuZ/mSTJ8BLAbrEHYVOGSmly PO53nsNWr02TMTWHJYO9Kt+KEUoJa878r/YirI+/HwywZ3CmC3Ft8zzxQ3W70Sj0YYzj Qv8w== X-Gm-Message-State: AOAM530p2YKHI9bopzOWf6lbAm2BPGs39ngpu5gx7A+iQhmcSwzkw312 gdjs40xwKh9pBEz2Pk+aC0UBXStDbPw= X-Google-Smtp-Source: ABdhPJyKJBIpR+YCSaKKJ97h65JsqvKAahxUdkZmmgDRrhw55tFcmFNwlNiwWPKsiAQe4ykeSAH6Zg== X-Received: by 2002:a7b:cbc3:: with SMTP id n3mr5339035wmi.68.1604622312738; Thu, 05 Nov 2020 16:25:12 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id c64sm4672865wmd.41.2020.11.05.16.25.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2020 16:25:12 -0800 (PST) Message-Id: <24e5ce60f5e945239ba23b823c8e69640265e531.1604622299.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Fri, 06 Nov 2020 00:24:58 +0000 Subject: [PATCH v5 15/15] shortlog: use strset from strmap.h Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Jeff King , Elijah Newren , Elijah Newren , Elijah Newren Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren From: Elijah Newren Signed-off-by: Elijah Newren --- builtin/shortlog.c | 61 +++------------------------------------------- 1 file changed, 4 insertions(+), 57 deletions(-) diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 83f0a739b4..c52e4ccd19 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -10,6 +10,7 @@ #include "shortlog.h" #include "parse-options.h" #include "trailer.h" +#include "strmap.h" static char const * const shortlog_usage[] = { N_("git shortlog [] [] [[--] ...]"), @@ -169,60 +170,6 @@ static void read_from_stdin(struct shortlog *log) strbuf_release(&oneline); } -struct strset_item { - struct hashmap_entry ent; - char value[FLEX_ARRAY]; -}; - -struct strset { - struct hashmap map; -}; - -#define STRSET_INIT { { NULL } } - -static int strset_item_hashcmp(const void *hash_data, - const struct hashmap_entry *entry, - const struct hashmap_entry *entry_or_key, - const void *keydata) -{ - const struct strset_item *a, *b; - - a = container_of(entry, const struct strset_item, ent); - if (keydata) - return strcmp(a->value, keydata); - - b = container_of(entry_or_key, const struct strset_item, ent); - return strcmp(a->value, b->value); -} - -/* - * Adds "str" to the set if it was not already present; returns true if it was - * already there. - */ -static int strset_check_and_add(struct strset *ss, const char *str) -{ - unsigned int hash = strhash(str); - struct strset_item *item; - - if (!ss->map.table) - hashmap_init(&ss->map, strset_item_hashcmp, NULL, 0); - - if (hashmap_get_from_hash(&ss->map, hash, str)) - return 1; - - FLEX_ALLOC_STR(item, value, str); - hashmap_entry_init(&item->ent, hash); - hashmap_add(&ss->map, &item->ent); - return 0; -} - -static void strset_clear(struct strset *ss) -{ - if (!ss->map.table) - return; - hashmap_clear_and_free(&ss->map, struct strset_item, ent); -} - static void insert_records_from_trailers(struct shortlog *log, struct strset *dups, struct commit *commit, @@ -253,7 +200,7 @@ static void insert_records_from_trailers(struct shortlog *log, if (!parse_ident(log, &ident, value)) value = ident.buf; - if (strset_check_and_add(dups, value)) + if (!strset_add(dups, value)) continue; insert_one_record(log, value, oneline); } @@ -291,7 +238,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit) log->email ? "%aN <%aE>" : "%aN", &ident, &ctx); if (!HAS_MULTI_BITS(log->groups) || - !strset_check_and_add(&dups, ident.buf)) + strset_add(&dups, ident.buf)) insert_one_record(log, ident.buf, oneline_str); } if (log->groups & SHORTLOG_GROUP_COMMITTER) { @@ -300,7 +247,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit) log->email ? "%cN <%cE>" : "%cN", &ident, &ctx); if (!HAS_MULTI_BITS(log->groups) || - !strset_check_and_add(&dups, ident.buf)) + strset_add(&dups, ident.buf)) insert_one_record(log, ident.buf, oneline_str); } if (log->groups & SHORTLOG_GROUP_TRAILER) {