From patchwork Thu Nov 5 00:22:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11882767 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 DAE77C2D0A3 for ; Thu, 5 Nov 2020 00:24:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9446720867 for ; Thu, 5 Nov 2020 00:24:45 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BE1rd19X" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732835AbgKEAYo (ORCPT ); Wed, 4 Nov 2020 19:24:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54090 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729441AbgKEAWu (ORCPT ); Wed, 4 Nov 2020 19:22:50 -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 A9175C0613D2 for ; Wed, 4 Nov 2020 16:22:49 -0800 (PST) Received: by mail-wm1-x344.google.com with SMTP id c9so23834wml.5 for ; Wed, 04 Nov 2020 16:22:49 -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=BE1rd19XtKUFSUvD9ERc0gsaQyToqT66XPiEATk81sNuqaMv9T8mTyjmQpyKJ6Uof2 6D+AjG7Lo1pW2E6YmylGzvBorz1fFbxOWBXzHpE4T5bvj29RjLyDGkpiZvcK9u8fdDZD pba0A3bTZQCbWszezZlM6EBjzEHc4zX7l9LCqd+yPDoUOsC9rahD/JsN+W6k1L2TWs1J ZICM7hmr//AAkIRcwBwVYCxW+I9iw7a8KhvkfNskDKnxURqqCF7ftCB2THXtcGVGHsap BUqGnjpmhbKh3tat1HANaq0Lg5Z/rFiKeg9yl7UUN4Zyybx8K5fPwH6E6zJXVRnArslN PB6g== 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=qru12V6Pu3oGvyrGdrYuJxBSTyIdrqVcx5y01194l9LEUtZv2zz7Pe0xJyiPZDUkUF qN5z5hKGC52vL4cbrwHP0Ws437e0HDlaTlSpDorGUxN2Mk+UiVTk57hx5/d7YcmfXmKx 4I9xlliRgqVy6areSzlqlDqoXzGmai1VEeAp0u79hfSIGGWsdroCSG0RFLMA9KpIlkNs XYZn5vgxFZvn6mTpp3WxwRVUWMYkDSD8lit/udmoNO9Di0LgVjq+xCySdITkPZLGB5nI if4GdBpsjAzksPWViejLkKkLngBLhUID3C9LQqQAQtVzC8FC/3olDuUr/xZbrUlJGTNb MVfA== X-Gm-Message-State: AOAM533JoxIubD4iuo9takLwVt8iKP8ZQ0DowDT7laaY0peCLCN0a6Pa PRKKJdYmU898RDxG5tR2PZFN0XxqBA4= X-Google-Smtp-Source: ABdhPJxQOJrCUorbTLEB1Yy+hftN6XF+me9leV8eDFUGonZW0fgMA2Aisu8+1/wQ6l4UUn43/6MsLA== X-Received: by 2002:a1c:4888:: with SMTP id v130mr87245wma.84.1604535768218; Wed, 04 Nov 2020 16:22:48 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id n4sm26918wmi.32.2020.11.04.16.22.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:47 -0800 (PST) Message-Id: In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:33 +0000 Subject: [PATCH v4 01/13] 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 Thu Nov 5 00:22:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11882765 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 48572C4741F for ; Thu, 5 Nov 2020 00:24:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EE06B20825 for ; Thu, 5 Nov 2020 00:24:41 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Zi6RR1DQ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732816AbgKEAYl (ORCPT ); Wed, 4 Nov 2020 19:24:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54094 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730131AbgKEAWw (ORCPT ); Wed, 4 Nov 2020 19:22:52 -0500 Received: from mail-wr1-x434.google.com (mail-wr1-x434.google.com [IPv6:2a00:1450:4864:20::434]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 81E0BC0613CF for ; Wed, 4 Nov 2020 16:22:50 -0800 (PST) Received: by mail-wr1-x434.google.com with SMTP id x7so400372wrl.3 for ; Wed, 04 Nov 2020 16:22:50 -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=Zi6RR1DQkMJPrQ8RJ6J4ZzcfpFXtTg6PnbF30Mr+ulsEuQsrwCTCWnjn8kfGMGmMG7 +IqDP7d7p8AIhtiaO7QmHZOj5ZO89eeuHOxX2mVbark5UyqIt7NNe7gme4rjTQO1Pu9P 6aY1z6BJk76WxgS2CZZDiBpg+EXY2AczNFR8Tj5CsSA0DYZFQsgBINYnLYbPF2rYgjm4 u9RIT7RFER5YwrldtphkjsSq6L3xIIHGwHlaetVfa1AZlqTQwzkag7q0ZjVNWSksyV7x NWrNn5lb1znC+r/qNLP4PxleN77cwGRmD3SUmCYQqs5I8aMSPimy84JG1XbGSsMntVwt A2DA== 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=V13iZJBEIaR80A+0O4EABc8hW8UnNbzPF4p1drmAtVfFB4tnUlENrxoNc9BUaJrEVY 5eWvnha6ERrozIedOALlT/AbRt+wagTMRtB4lZ2AjGmbrJOmlno3NQ5NDC4AMV/mFsh4 +aEaW4FqziiONybPPNXxYLUlv59VOfoBMVXatGjM6RVEEUwR+SllsB0RgWgAHhNyc7Gd HDvGIpL7u4jYwI2uPkcGPLoDvveY+pOddVNEmJcoBYvWfl/Wfz7gAg/Dx3NtJagOUkwm OcFIlvu/cPVkM018OuA4RJOWX8KDX9UGOmSiTNrcgf+P6sGKKrdVn9rTZ49eNuKrrOnX UOlA== X-Gm-Message-State: AOAM5316JoWQT+mVaSwKvNsK0no+b6vqK8HRcD10V3tzi6AQn4+4CDSd 3FLiN1ZmaqQl2zcs4XQdImaeAVNQVW0= X-Google-Smtp-Source: ABdhPJzQQ94ptIQ8VaCZ8f2uYtrw/yTMZ5jt7pnuhUMYJ7SGdPNvSaccXFP2f0k3an9xHiNgp8ZVtQ== X-Received: by 2002:adf:8484:: with SMTP id 4mr605193wrg.334.1604535769075; Wed, 04 Nov 2020 16:22:49 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id h4sm4832692wrp.52.2020.11.04.16.22.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:48 -0800 (PST) Message-Id: <591161fd781b7666ddaa45694eb20610cc359741.1604535765.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:34 +0000 Subject: [PATCH v4 02/13] 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 Thu Nov 5 00:22:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11882761 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 0E254C55178 for ; Thu, 5 Nov 2020 00:24:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id ACFB620825 for ; Thu, 5 Nov 2020 00:24:43 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="obWQVHBM" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732830AbgKEAYl (ORCPT ); Wed, 4 Nov 2020 19:24:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54098 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729546AbgKEAWv (ORCPT ); Wed, 4 Nov 2020 19:22:51 -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 4FAFCC0613D2 for ; Wed, 4 Nov 2020 16:22:51 -0800 (PST) Received: by mail-wm1-x344.google.com with SMTP id s13so27745wmh.4 for ; Wed, 04 Nov 2020 16:22:51 -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=obWQVHBM05L2iGmhR1E5lditq9cEjKzG83HrRcnvlogtnS9mEOo+j167/Hi1dcEzak P9YHpPl9c14VOVqzTYQ1BzQLF3XthyCnN7ScVC9NIOHb7FXShcnYJzJ/Om2LZi9CKi1w ttyl98y94E9tVtpO6ur31gdnMOKxP9/2d/KTi49ZLGudlvXZ6vbn2y3wyG4X+XhqCXjC d56A5egJi45lmNDx7ha4o/wHtt+G221QJ077dJxJEzIE/gsVNPWLIAqIysBpWH5MxTj8 aMBJnctQ+cAWzVxlWodZvZO3C7ANfixz8g0vh1wgnkGF1Ao7datCwOJEYk3TqBnCijGQ eEQg== 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=fLeGb3uhMTsI4mOoKOHz5uY28sJLS5KNiQHbwtt9WUWpJVCuFnm++OV79U3dzFcyha sdEHoCfuOjxAFyYv++8zesd8JyLgfiH3/n3dbTzYQreK+UWJ0lBHcNdJNBaGV36l7wyz zB9ujyZEw1XMjxVmTUYTgZDfEOxXoMKOU4m0OWQEReC4w+H7oRJJPaqSTLp2f2SU8OJH P3n8dyLkM0LQykZVyHPwdkyjmfFydg99UO47HUzIVqeZU2T2cVAPuxYXRGRYVaaPOpoO EdAGTWGc5HtHtSK+LQe05hvaInHGO+qPztzccmBw27Y8GNBF99tE5HJw/GzIPsN9ievl Na9w== X-Gm-Message-State: AOAM532y7Ilc+PExpJw/d1AED7vM9xrTkNKhaUIcD60Dupt8p/ZGI+zB MQ1Og2+zFSkZa5tLr378h1dNhjjJskg= X-Google-Smtp-Source: ABdhPJxiGUEJBB8qykQLyqMTBPBnmrpKydVjeTEMmI/esCeJgxE5HSdWSJFpHBhL1Kltcv487FIvXQ== X-Received: by 2002:a1c:7515:: with SMTP id o21mr77803wmc.5.1604535769921; Wed, 04 Nov 2020 16:22:49 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id o63sm6421wmo.2.2020.11.04.16.22.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:49 -0800 (PST) Message-Id: In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:35 +0000 Subject: [PATCH v4 03/13] 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 Thu Nov 5 00:22:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11882759 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 39C0AC388F7 for ; Thu, 5 Nov 2020 00:24:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D543020825 for ; Thu, 5 Nov 2020 00:24:39 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="inc1XOIB" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732792AbgKEAYi (ORCPT ); Wed, 4 Nov 2020 19:24:38 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54100 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730630AbgKEAWx (ORCPT ); Wed, 4 Nov 2020 19:22:53 -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 1ECF7C0613D2 for ; Wed, 4 Nov 2020 16:22:52 -0800 (PST) Received: by mail-wr1-x441.google.com with SMTP id w1so394671wrm.4 for ; Wed, 04 Nov 2020 16:22:52 -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=hz04PDbA9UEQiHo/9pZvZ4q4Euew0clND1poGrjjarc=; b=inc1XOIBbKCTEvq5GFbd9Ye3xy2z5feLr4Ce1B+HkyoG50CSsMcbLx4A6mgVCNgTMu e6BhM5kBhfQLt42OkhNyv+/O3p7kZIxUp8K1EpQDmvLd+zVna2RaHaPpqEvGM+NKszDF LZdoUlrb0lcYyuxh3tgZ3d39J38sRFqiayLR6TLQrIzdTdDq77EBDWw06NYIm5hknQcc zp8yE99wvb/VJ5Ptc20I3Kq/X7J9zE5FW7xuUFPUEalADxzpMFiDodleMKZErYTPeVhk Y2sSO424FMJB1joNYlmNMh0GNXtzkjACfcIVPvQNlYhnIR6GcYUCC9Rg17zGoB23Mrty gOfg== 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=hz04PDbA9UEQiHo/9pZvZ4q4Euew0clND1poGrjjarc=; b=my2bQ6sjFKAcfBir0Vvi3UR6xGoyL0lB2R1akR7W2uPkG5W1nAO66R3hA3+UmnLD/c TmVdWbwwAelROkSdndY5fq2om1TQiEnAbHcJXnyWLJmnWmpmbsiqsuIaBpldB+1vmM2U 6ohXF7rd+6EcqsRqdVtrVfPi8XtXe3xSgOS/eCRwMjCrDQ1Q6KRMaPI7IROMmk5YmQlt 5kwA7VVnS1RmHRH84ADY1tim7CpyH5czjhY3fl4sD45zNdzdp9CZgyubl7/m30QFg2aL s5sLODWlKdhF9ITw0UXV66BnzHCwUWucd1edl/GsGvUYKK/g/jQiZhtfwGQ7V04LR0fB K4BA== X-Gm-Message-State: AOAM530CODJUHCox/UQNu583qfMhoo8kvLiOc/Hm3iIgV6r9y/UW4X6o pLRQob82yiex09B8hvdi9R3ClgYkh9k= X-Google-Smtp-Source: ABdhPJygy0+nokQ9ODHI+KUYUcGQkvzjVMPP+oyVogHI8wM4e7rj6xUHMTovD80aXG33klaXbOTdXw== X-Received: by 2002:adf:c101:: with SMTP id r1mr542170wre.87.1604535770724; Wed, 04 Nov 2020 16:22:50 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id x10sm5006381wrp.62.2020.11.04.16.22.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:50 -0800 (PST) Message-Id: <61f1da3c51b521035ba728c025cd6a28397f8051.1604535765.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:36 +0000 Subject: [PATCH v4 04/13] hashmap: introduce a new hashmap_partial_clear() 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 merge-ort is a heavy user of strmaps, which are built on hashmap.[ch]. clear_or_reinit_internal_opts() in merge-ort was taking about 12% of overall runtime in my testcase involving rebasing 35 patches of linux.git across a big rename. clear_or_reinit_internal_opts() was calling hashmap_free() followed by hashmap_init(), meaning that not only was it freeing all the memory associated with each of the strmaps just to immediately allocate a new array again, it was allocating a new array that was likely smaller than needed (thus resulting in later need to rehash things). The ending size of the map table on the previous commit was likely almost perfectly sized for the next commit we wanted to pick, and not dropping and reallocating the table immediately is a win. Add some new API to hashmap to clear a hashmap of entries without freeing map->table (and instead only zeroing it out like alloc_table() would do, along with zeroing the count of items in the table and the shrink_at field). Signed-off-by: Elijah Newren --- hashmap.c | 39 +++++++++++++++++++++++++++------------ hashmap.h | 13 ++++++++++++- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/hashmap.c b/hashmap.c index bb7c9979b8..922ed07954 100644 --- a/hashmap.c +++ b/hashmap.c @@ -174,22 +174,37 @@ void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function, map->do_count_items = 1; } +static void free_individual_entries(struct hashmap *map, ssize_t entry_offset) +{ + struct hashmap_iter iter; + struct hashmap_entry *e; + + hashmap_iter_init(map, &iter); + while ((e = hashmap_iter_next(&iter))) + /* + * like container_of, but using caller-calculated + * offset (caller being hashmap_free_entries) + */ + free((char *)e - entry_offset); +} + +void hashmap_partial_clear_(struct hashmap *map, ssize_t entry_offset) +{ + if (!map || !map->table) + return; + if (entry_offset >= 0) /* called by hashmap_clear_entries */ + free_individual_entries(map, entry_offset); + memset(map->table, 0, map->tablesize * sizeof(struct hashmap_entry *)); + map->shrink_at = 0; + map->private_size = 0; +} + void hashmap_free_(struct hashmap *map, ssize_t entry_offset) { if (!map || !map->table) return; - if (entry_offset >= 0) { /* called by hashmap_free_entries */ - struct hashmap_iter iter; - struct hashmap_entry *e; - - hashmap_iter_init(map, &iter); - while ((e = hashmap_iter_next(&iter))) - /* - * like container_of, but using caller-calculated - * offset (caller being hashmap_free_entries) - */ - free((char *)e - entry_offset); - } + if (entry_offset >= 0) /* called by hashmap_free_entries */ + free_individual_entries(map, entry_offset); free(map->table); memset(map, 0, sizeof(*map)); } diff --git a/hashmap.h b/hashmap.h index 3b0f2bcade..e9430d582a 100644 --- a/hashmap.h +++ b/hashmap.h @@ -235,7 +235,8 @@ void hashmap_init(struct hashmap *map, const void *equals_function_data, size_t initial_size); -/* internal function for freeing hashmap */ +/* 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); /* @@ -268,6 +269,16 @@ void hashmap_free_(struct hashmap *map, ssize_t offset); */ #define hashmap_free(map) hashmap_free_(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. + */ +#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. From patchwork Thu Nov 5 00:22:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11882747 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 EB3F6C2D0A3 for ; Thu, 5 Nov 2020 00:24:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 827212080D for ; Thu, 5 Nov 2020 00:24:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Ylc54wvK" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732807AbgKEAYj (ORCPT ); Wed, 4 Nov 2020 19:24:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54108 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730153AbgKEAWx (ORCPT ); Wed, 4 Nov 2020 19:22:53 -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 4410CC0613CF for ; Wed, 4 Nov 2020 16:22:53 -0800 (PST) Received: by mail-wr1-x444.google.com with SMTP id 33so380140wrl.7 for ; Wed, 04 Nov 2020 16:22:53 -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=Ylc54wvKrnsvfyWPBaS/zOV7d6s7vtizM/HCswA0Qd5LxgsiaxD1ivTxHp9QWRxAzs gsz7Nfst/Dd+yViBEy9n+3pAgssMhE7CPhY34Hxk+csiHebxCmCH+SttX+vlg9Q7ahGZ AL1NagR+HOYlBMynH9moxFUmN5/ce29mtMvueW6JUHDpT5uGLw1pcZp/gsAJ82hR67LX t1pnmRQkWIsf0z/9vsjQCH1RJuWiTFks6Q1GasSkcFCeQEz1XtsGb+8ROSc0RM+OBwFQ /6+agiHwj1QOhu7Q5zG4M7FymCSlBxTHp/KJbp3YoPhSSo8q5GuB2Bpbhl3+CpcEvWyr /uBg== 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=EA1zs0CJ2wqwnxRz6DEaEcbxkRjOWb88JwS1C92Vji0hKyhilzBMyZxz4jt8RsjJyh V9rErXxd+iHaJPCXrkuLJSfgMB7VRHhr2yu9wl4evWQ4aaZ6tF/oPqnGHbjRceovydpS laKCvO2HAaRReJYpF6icPTyVygIAT2PMRjhgdKgstgQH3fN5Eg/vDMLKJCPb6TN7m9ol hyYFqsR1+A3jwRZNPvGonxPo1AOHAv5gPm8pyi06Fheyk5E9GoFe1Uon8aX7C4jizVbq 9015ySj2vIH1BrhnVuJGQmfd4xm4nBUlJJ2gOUXU6tEQZBSJ4G/R2qz8SsgwNw4Hnwli DM8g== X-Gm-Message-State: AOAM531XjBmI7QVgS4nArN5yl/eor3xPUBuRVDJbi4zexX+QCiIUuhGu h5le+W6ZftiDDq6g0W+opkzPmbMtOBo= X-Google-Smtp-Source: ABdhPJx2X2QgGE2C+QHAHMBf+YY0ZdKqq6Auv0G9r0PSuyfjyZiYdWGld4136RSmkFrGgt/GI8s+jg== X-Received: by 2002:a05:6000:1185:: with SMTP id g5mr613705wrx.42.1604535771604; Wed, 04 Nov 2020 16:22:51 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id l3sm32738wmg.32.2020.11.04.16.22.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:51 -0800 (PST) Message-Id: <861e8d65ae8065595d9d4ccff5f70155fec408c9.1604535765.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:37 +0000 Subject: [PATCH v4 05/13] 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 Thu Nov 5 00:22:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11882757 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 099EAC2D0A3 for ; Thu, 5 Nov 2020 00:24:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A48D420825 for ; Thu, 5 Nov 2020 00:24:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="gytGdqZO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732775AbgKEAYg (ORCPT ); Wed, 4 Nov 2020 19:24:36 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54110 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731211AbgKEAWy (ORCPT ); Wed, 4 Nov 2020 19:22:54 -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 10992C0613CF for ; Wed, 4 Nov 2020 16:22:54 -0800 (PST) Received: by mail-wm1-x342.google.com with SMTP id 23so29520wmg.1 for ; Wed, 04 Nov 2020 16:22:53 -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=gytGdqZOdyj5WDZYcdMw6RTJk8MJZqd8WfnAcquaBhWK23Cgqm3bg0DpC2TLjpFBaj 54slrfKFEY3J2IXof6hhpBirm7Cxm2Sgaony3VFiDffuYUc/9opg6biQzXBRLjR8mSuW AxNW/7olMivJ9DmZvFe+UkXNyzC0fCgYVXJmNIm0QnbNsQjXV7qJSAx7JazhW2Jf1d5J J7UBIVKDhWQG6qeVoCQcSw8ilvXO0d5E95cdVPFMRhgkzAewjb1vkdH+3aUUbDcMB42n qKr85xJKdZECu4spy0yChLjfVSa/ckpUzRviaF7Fgu3AX9YnbaRixhwGawNZLTwjfZ2h yAHg== 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=Qe/yQqzR8v5nG+qfjZ6N6ff/eojkSbGAbkEUwscDAHifsg3mC5H+jTb8BWYqM9TIGT 0woZ+oA71W+Odyd8BTktfRHobfEw5DLoZfKEZe2rmg7Oz0vdALFuuuv0KCQ8beUFiI/h 8yUg6H77wbKayMz/edPEUl3AS5Z+4rsLsgG94oUbpW2XkMNWNqEAhqHG5mEGrpohDwuP AdGV2eUGQ3ryxHGmjkeX5HnXRye1mWFHKXPTXGzn4srCr1w7zYsEjd41Pb0cCcGnmERz FOhWGWZCWDTU1M/tCERb/Ibo09Ofe9tTmvqnhSTL/NmxTpTuuW9AydLue2T2fJnBHz2I s7VA== X-Gm-Message-State: AOAM532pszX4/JvQiIIHsfT9nHN0IquJ6uc9AcYubCuYJaasU9qN96H/ 11RXguhaDw4yrhPq9kDUgXDpcD6K/b4= X-Google-Smtp-Source: ABdhPJx03kCnfto/tASPs+bunYO+2OWvp96A11x7p6kNXJ963IYF5pOEcBE1Bz1KKCGrojqBD/SC0w== X-Received: by 2002:a7b:c7d3:: with SMTP id z19mr103909wmk.4.1604535772548; Wed, 04 Nov 2020 16:22:52 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id z14sm48982wmc.15.2020.11.04.16.22.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:51 -0800 (PST) Message-Id: <448d3b219ffebbc0daa4ef033d78fd45693c5ccd.1604535766.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:38 +0000 Subject: [PATCH v4 06/13] 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 Thu Nov 5 00:22:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11882753 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 B4191C4741F for ; Thu, 5 Nov 2020 00:24:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5827520825 for ; Thu, 5 Nov 2020 00:24:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="rd4IDFvH" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732536AbgKEAYe (ORCPT ); Wed, 4 Nov 2020 19:24:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54114 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731324AbgKEAW4 (ORCPT ); Wed, 4 Nov 2020 19:22:56 -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 CD3AAC0613CF for ; Wed, 4 Nov 2020 16:22:54 -0800 (PST) Received: by mail-wr1-x441.google.com with SMTP id n15so403244wrq.2 for ; Wed, 04 Nov 2020 16:22:54 -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=rd4IDFvH9Nah1LkaOAhsanb0d/eeTLGqbLhh3PNsBXOzdSgLR1zPh02OUuX5YCSy4e C8GAQ/VGBD8oS02E2IOL4bb1HeJlGw9rfwyFoqqkO9HUJf7Z9fUNvF24G2bgtfMbvctR /hakk+b+CGn2P3Q8PRjEbquj5qgkdkX1NhWMqnlza0OeEgg5glCB08kSn83DsuuD2uvN 6oCKiWJ2lPahLF7JxL+PfqAO6yCDbcLEq7pTMf7suO+FoRPADX11/WKgoEs9POFNXmn/ zRW0KQ4CqyTsXPcH/nyAEwoE0sVt9c/80Ah8yahNzIYJfVpC0O0hHXVH7hMdzPxf7A8j 7nEg== 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=WyWahaKBblyxGec3HHB1qQWglhd07XTPlXAOvyyJeI2w7SRL7MHypHgc7o+I4Ba4gT 6BTKD8hFm9Z+GJ/0b4eNjX6wHUX7OHGGs7tK1zaAxufZ0l4camOnS2We1JyyXXud5OPV GIq1gIFc5UsZZET6CvzwezHJPmUORzxE8Kw0bw3bcrPa1BcmAa5/DRMdgdGiApyHeWh1 F6Wyq5RpmuTZ8Y5Qd7nSNsmR/x8rdybsFaCL8kagJKUgSSfxGk/5PmDe/BpRYC11Hb5C 0AtUfo9lcG18NJixLSL9kJcAKRiQ04EPD5ygaQyNtMOMptMNJnXtqt5Ag/4oM00QKFQk K0Yw== X-Gm-Message-State: AOAM531JZFCsrL43R5WvqcYKrvBoc/Nf9vCk4M4q3HtnM7DHpyCXH4b+ y/GWdxKaQbbgPYPud6Fc36xpw5/Ueq4= X-Google-Smtp-Source: ABdhPJzIMuAmoCA+sNqk0XsNO3Lj8oh+q8BwHEmp62I4pTIULcDyM8jVR5d+ro+bTYg5QL+irWUBcw== X-Received: by 2002:adf:ce12:: with SMTP id p18mr608540wrn.52.1604535773415; Wed, 04 Nov 2020 16:22:53 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id v6sm5343117wrb.53.2020.11.04.16.22.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:52 -0800 (PST) Message-Id: <5e8004c728580589cdaf46d755f2c977feaffb34.1604535766.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:39 +0000 Subject: [PATCH v4 07/13] 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 Thu Nov 5 00:22:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11882755 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 E8BD4C4741F for ; Thu, 5 Nov 2020 00:24:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A0DCD20825 for ; Thu, 5 Nov 2020 00:24:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="kWjxaYB3" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732790AbgKEAYg (ORCPT ); Wed, 4 Nov 2020 19:24:36 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54118 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731212AbgKEAW4 (ORCPT ); Wed, 4 Nov 2020 19:22:56 -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 B0139C0613D2 for ; Wed, 4 Nov 2020 16:22:55 -0800 (PST) Received: by mail-wm1-x341.google.com with SMTP id p22so30118wmg.3 for ; Wed, 04 Nov 2020 16:22:55 -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=kWjxaYB3uIL+1bhIUD2NOq/wXKTihOfLRMUcunx0b3d9hQ/qB8Dmj/p3SfBuIqpKfJ KLZcHiD/FCxsHrNaj2xgHSvs2NUqvGyiaE+Ru8wSyIYih6g1S9arnMGtsGaL+psMkCT0 5abQuoSMhhTpMtvbX+JJSpPWDEiK738w1MenaezEVghEaI9Xt7WjON9FCliQ5shfJ3s5 0ZcF9+pILUkVucw0v4hXQBTIKZ35JarpjFmlXBW2bgrlTQJnRsR2axDXIccMW3eqt47z 2HzuZaNlD5tsVoUKmqAoTKbQaY/fFXogct74J0HR24t/qIwbslV2N96rhp5ncA6318se 8UFg== 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=m5uN1l/HWwVVewn0y+I4l9PxoR0LzI+8FftOehaE3i6IdvgBFdkcwXhpTGAYfvJJQh JnY40kDPAjyCnduKfVL8SR+oKA5TrfbJ0IBGKmo8N+Rv7JxvoRtY2sm1GyehEYXSFXoV IAAvZQ3tkazyAg7vpyiP64BpyAj3UCM0YWzOI8SkgWe7ANrDR8Mq3l88G7qS7MPv7fiW sG0BJ1qUmIbdH4Lujqd6QtVg/HB/xLonsO4SimKARUL/3gah/iuQDyGTChc9ADX7ABkP unqPtRT7o1+BBWVTEQhESkPdfD7BouQ0VhsMjqotj9yxaD+VGcEMG68OPQrVnSfvdNAH hgrA== X-Gm-Message-State: AOAM531bHmpBqGDDPYXYVt4eIRyFhJUy+ocrM5tKcNg5JbvOCDPsaavN UNV9kzjGjKxYiQYAIgZhHUGQ1z7Rwas= X-Google-Smtp-Source: ABdhPJwR0Nb4BdqDgkehvZBl/We3ZUvu/DfhsqVP9n21wyZ/jhUtTOyRZ0ITvOtp/+RdbKR/TTpP3A== X-Received: by 2002:a1c:3b87:: with SMTP id i129mr87048wma.134.1604535774251; Wed, 04 Nov 2020 16:22:54 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id x1sm4872781wrl.41.2020.11.04.16.22.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:53 -0800 (PST) Message-Id: In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:40 +0000 Subject: [PATCH v4 08/13] 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 Thu Nov 5 00:22:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11882763 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 C38B1C55178 for ; Thu, 5 Nov 2020 00:24:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 71C2920825 for ; Thu, 5 Nov 2020 00:24:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="QV5vT8gn" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731293AbgKEAYf (ORCPT ); Wed, 4 Nov 2020 19:24:35 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54124 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731335AbgKEAW4 (ORCPT ); Wed, 4 Nov 2020 19:22:56 -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 8C901C0613D2 for ; Wed, 4 Nov 2020 16:22:56 -0800 (PST) Received: by mail-wr1-x444.google.com with SMTP id x12so55262wrm.8 for ; Wed, 04 Nov 2020 16:22:56 -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=QV5vT8gnhRpEBnTPVgbx9ocihiYMbXGReyjxyvgptcvJ8MSMKxr3GAFQDv/jSTOIx3 27RsyPdBNJFGxcUSWZJl0ts4CR1IDs9PHDKAZE6rUpner3Am3mBtDOwXOoLHhc/RN+sZ h2mf/e6Ny974tac8EC1ZJxf1bMd4R8bS71EbfyKBwyHUWTAZxWd/tjR2XJnFT/CLRYjF 1p/Ef4fUh1lqwPB7q8O+9Q3O/vDwzLDi+vJlNi5J5jzYzlQ++MI0T4j7qc7Q1z7OryO1 Uggn1NMqRDHunPXepIVgyvzmRXOZWbdpgbrDBGB700HifhmjVPnn276VXR8vclN5/J88 pNEA== 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=ed25iKswv+T+Y594ws/LTegbOIzT/1UMAyW0TLb6omEJRbyLM59Wp2JsvB8CIK5SPj 27tsSUAohLDNcneLoAK9h9s00LYb55h9XptroxfRSnDlrbLzvjQSIKV7ponkQ47+nXxg 8Thd83HEdEvPDnOEylLsEvqaModYfcVJJbLPcdopVECCn+BPUtgPh+RnAZiPG9JZh/gq tRjtCj7JohnlKG4TfprdYAAmROZi/VZsPW9+ttoektPYHArtxaDnJWxasj8PlwqDWfeK j/MxCXOfI77OXsNBIP+Kg97B0sC5R15iwZrf5h15xcweMv+T02XfsfqOmPooD8TfGUq7 +pRw== X-Gm-Message-State: AOAM533IJpTk1DFtnuB8WNvPxkdIaDeMmHP50oUOrYTfGMPHe6v7krFh qCcf+3wKohA/y7OUYjVzygvpMjTjiJQ= X-Google-Smtp-Source: ABdhPJxaSevCcYYCyIh01cpdtfGOVFOwNYTEqWDrGw/FNx/40sdSYXe5W6g7+Wz6LDBwnyKDKQHg8Q== X-Received: by 2002:adf:c847:: with SMTP id e7mr587422wrh.346.1604535775091; Wed, 04 Nov 2020 16:22:55 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id h128sm23176wme.38.2020.11.04.16.22.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:54 -0800 (PST) Message-Id: In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:41 +0000 Subject: [PATCH v4 09/13] 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 Thu Nov 5 00:22:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11882745 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 63B53C55178 for ; Thu, 5 Nov 2020 00:24:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 06DF520825 for ; Thu, 5 Nov 2020 00:24:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ghCC2vkH" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732754AbgKEAYb (ORCPT ); Wed, 4 Nov 2020 19:24:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54128 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731526AbgKEAW5 (ORCPT ); Wed, 4 Nov 2020 19:22:57 -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 7C4D5C0613CF for ; Wed, 4 Nov 2020 16:22:57 -0800 (PST) Received: by mail-wr1-x441.google.com with SMTP id y12so385800wrp.6 for ; Wed, 04 Nov 2020 16:22:57 -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=2gcop2RIjSqtF4D5GONDrn3Pf6fDwI4nosJXJatTx5c=; b=ghCC2vkHgDlm7f4WAVR+ceFHXgWpST22G4Bx9/7AQhKFqs28mhe1zjX6KIlB1L63Rj XQMuQywnzIkYEaPDGspp+Do80QYiD0/q0C752ulZtaejlwJcJmAkqHqOsSGzHwcWpnbp 4cMJ4vm2omqF8MmivMRpwKM8KLED203xAG5IwQ8+DeYJnmdI36lH/jzDJHV0YZL+XYFx RNUk2TjwE3JLWIWd4nmrhZYdaSmEPgXbFk/XRxFteWt/zEBTbkPGaUTXCW/hNZuO5OY5 esxw11CceU2P1vB87V3e40tc54wfP+YsMzvHIyB2+DbXey0sLrOHtX8o7WHjDYUQWFvE SInA== 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=2gcop2RIjSqtF4D5GONDrn3Pf6fDwI4nosJXJatTx5c=; b=rA64JH0il9lWZKvhjJgtkDc9kSgnAfH4HKsk24T2pjXLblw+dJeDFGzUqg/pRRit84 /ejAg+Vb9lVUfcst92AaOf5YgYwIh+AoATkE23QZW3OmW4pD60FI23CyZa7tuYJ8Swcx A5WgSU+cyrNnWVpHoLw3/3yiYqcV3S/ROWBLkQIswSPMWDm9ygS24ypU9Lmg+nQLkZ2+ 4wmoUBlt+nbbLr8jX1dz0nnGRAYTsbFEnMRVE1XowSO6bXI/LYjkYPQiLEmX6sl/BI2f zHhlXkxqaN+PpBFlsjnjI8iXaKN4r3xIAfzfXLhXydbnWCN1quVJFETICe7QIwgh9DEW X/Yw== X-Gm-Message-State: AOAM531EHeo41wQPRIq9VH4TDZYtZ+dwfG8s0aFGNKeU8NqzyFR4aZcg iheDzBP30ACTDrORtua3Vj6D+Lq9Wpo= X-Google-Smtp-Source: ABdhPJwl2qORmTujz2djYmoTr8r0u3sqZIcLzWec5rg9LJjaY410wcNH6xNSXvsRClDUGAOeR08wkQ== X-Received: by 2002:adf:9043:: with SMTP id h61mr580510wrh.237.1604535776111; Wed, 04 Nov 2020 16:22:56 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id l3sm7407wmf.0.2020.11.04.16.22.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:55 -0800 (PST) Message-Id: In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:42 +0000 Subject: [PATCH v4 10/13] 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.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/strmap.h b/strmap.h index 56a5cdb864..22df987644 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,68 @@ 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); +} + +static inline void strset_add(struct strset *set, const char *str) +{ + strmap_put(&set->map, str, NULL); +} + #endif /* STRMAP_H */ From patchwork Thu Nov 5 00:22:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elijah Newren X-Patchwork-Id: 11882743 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 C31B6C4741F for ; Thu, 5 Nov 2020 00:24:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6335220825 for ; Thu, 5 Nov 2020 00:24:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GpIEXMr7" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732723AbgKEAY3 (ORCPT ); Wed, 4 Nov 2020 19:24:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54132 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731539AbgKEAW6 (ORCPT ); Wed, 4 Nov 2020 19:22:58 -0500 Received: from mail-wm1-x343.google.com (mail-wm1-x343.google.com [IPv6:2a00:1450:4864:20::343]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 51B36C0613CF for ; Wed, 4 Nov 2020 16:22:58 -0800 (PST) Received: by mail-wm1-x343.google.com with SMTP id h62so31192wme.3 for ; Wed, 04 Nov 2020 16:22:58 -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=vuOmP4h42WdNvbkUSAXROh7F3ep+J+M/i0tcBU8uhpU=; b=GpIEXMr7hlhW1ZVz3OxdBsyAKMeMPt84EV9RYvNw6WtIDUNGuV1PMrkPxf2eKTy4yR 8vco/8exJgqpRbuwG+pyI1uMCON+7qluVbBvcE620yJ+wA1qhFl8sCoBhufVw/FS3GJS AMfPVejPs4AyG+qWV9CPoG2/ijvzw/yb3xy1hKIuwLguHuUKrzuV2xMcQZANEzqCsw/5 WJy1b6H+M3bhiTSno/5AJbheWfu3qvexEXZjRrnoVw84h9lStdJeHdQlHhvCHY8mVUO8 MOBo8tzIjqwPxtrsETjzdV5lHE5XtxNX/fYA598pSFNcvAd1HFLG62lT9tR+EOcqqH2C 52lQ== 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=vuOmP4h42WdNvbkUSAXROh7F3ep+J+M/i0tcBU8uhpU=; b=s113P6CzqnxzzW0emdlLBtvGz8VRFSJqsbdGASckMMujRtDPpVYdr4l/PtNMUOThPe Dmri7gSdlnUgHqqvR3gsNYyBaWuC0cblA0wuWQE6mOIw3FviZqz+6fOsT1cq3SiZsI4T Bg+/MG/8clQP1J1UJ/qhsp0ikbB/nLSQPgMOJ9Q1BzT1C+6/44obdXsLGZKj1R0TAYmm wcHXii1PuL9PQVj1BEn0KInVyoq3CnCD6aZiEARXEH3tpfOUnZFapwhSqYUbKrSlBYPF fRTLST/lT+/OpEzURT5JLCNC3kAyYo3fjDmfOIh1N7jpmsDquGSeV8T4oT6+ImpCkrRR N+Lw== X-Gm-Message-State: AOAM532V0Epb1R0uBtaVX9a/qRb1zYixJv60rAy7LB1xfANEX1nQz/Xn scZFiEUzvSA5H7IzOE47hQzOMYK+ekw= X-Google-Smtp-Source: ABdhPJygVfzlgChD8iO9/EfRxmT7TjR3yZ1DGtbbFJt4Adi2Gus4wGx8ga67/yh+EeopJ4bZ5lKOrA== X-Received: by 2002:a1c:4b04:: with SMTP id y4mr59256wma.93.1604535776921; Wed, 04 Nov 2020 16:22:56 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id w4sm4882188wrk.28.2020.11.04.16.22.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:56 -0800 (PST) Message-Id: <73a57045c37f50fee3a1d3912f5ed7a217142029.1604535766.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:43 +0000 Subject: [PATCH v4 11/13] 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 0d10a884b5..f5904138e1 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); + } } } @@ -81,11 +90,13 @@ void *strmap_put(struct strmap *map, const char *str, void *data) } else { 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; hashmap_add(&map->map, &entry->ent); @@ -119,9 +130,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 22df987644..b9d882a2d0 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 Thu Nov 5 00:22: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: 11882749 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 BCE48C388F7 for ; Thu, 5 Nov 2020 00:24:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 52D6020825 for ; Thu, 5 Nov 2020 00:24:33 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="dWrPt88b" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732633AbgKEAY2 (ORCPT ); Wed, 4 Nov 2020 19:24:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54136 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731541AbgKEAXA (ORCPT ); Wed, 4 Nov 2020 19:23:00 -0500 Received: from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com [IPv6:2a00:1450:4864:20::32a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D6660C0613CF for ; Wed, 4 Nov 2020 16:22:59 -0800 (PST) Received: by mail-wm1-x32a.google.com with SMTP id d142so26457wmd.4 for ; Wed, 04 Nov 2020 16:22:59 -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=JPP2s9lPoramP43ojtmL2q5StsGenrMHXk4OxxxNUMs=; b=dWrPt88bC/6dH7c3BIvMfB80CU+43E7lmF8L5Vin7bgNhBpxkNi7Ecr0SBODrjI4i5 xFLeEyd/nSh+KXodj9RzuQQnI9I+Kr3GeaFZnnEmt78g79FmCK2Z3VHXXCBgLZAZS95H I1SfcUeGoNbod5x3LZKUbPtS9focQ7TApbzpkvik1Tlsb9kBeXmQfQdJL83RgKs5beEf RcsfhCBJxidCpCZ+y3cvP7diBgytel+KMhDHzvsGE1RnJtiWlRaOjl6FyjFRthHx59jS mjJ7TiEMmI4NgNJJ71ucBR4Psivuxon4TVHU0XoAwFoyhDMg13uqXf1kWOZcz5H2rhff KTww== 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=JPP2s9lPoramP43ojtmL2q5StsGenrMHXk4OxxxNUMs=; b=Y0ipcvSoNLSBmOdx2w8YsesF3FEwRY+w9KKiB5rfpO+/VnE2yYwi3rFY8xHnUG3a3Y AsAqiihytCMGy1Zsc9wt33diujx6Qg2qz9urMyTqM0NrAs+HjWOD/uxPcTJlGE5EsicK GNe/TGbgduJLLnL9kHHL6Fq51q0Kk5qyLC672TuWpNgWr2dGqF/u+9/A7JQ9EHPIzKqC NMugpUGUxNolC1hYQeel2QjC6w4y/0WdebUbEHIBVLZKOIHD7GvBQk549WZjUsEwwDkt 4KHsnQ8URa1rV7GlSfOiB93abPVs3AjoCTZSpeXEsr1OSu4IGE9dDZRMosSKNEu7TTjs 742w== X-Gm-Message-State: AOAM531BnkB/0IKzOVMKEz/HzA9prLUbRhZLyFugTraZUi3Vqj6GabzJ 19xOnTmwtxpr2FtcjO7UB3SOD25HNXM= X-Google-Smtp-Source: ABdhPJzXB4YOXsLFtiOgLmhhJ8PHW0lQAAkZz1BuAC1/cC30qP7fgX2k7cYArfcPnaAYmzzMF9q0ZQ== X-Received: by 2002:a7b:c4c3:: with SMTP id g3mr64227wmk.65.1604535777814; Wed, 04 Nov 2020 16:22:57 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id e5sm4839654wrw.93.2020.11.04.16.22.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:57 -0800 (PST) Message-Id: <0352260de479e2c61d9971e6072435476ad3d620.1604535766.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:44 +0000 Subject: [PATCH v4 12/13] 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 | 48 +++++++++++++++++++++++++----------------------- strmap.h | 1 + 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/strmap.c b/strmap.c index f5904138e1..98513f7d58 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); - } } } @@ -82,26 +79,34 @@ void strmap_partial_clear(struct strmap *map, int free_values) 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; + void *old = entry->value; entry->value = data; - } else { - const char *key = str; - - entry = map->pool ? mem_pool_alloc(map->pool, sizeof(*entry)) - : xmalloc(sizeof(*entry)); - hashmap_entry_init(&entry->ent, strhash(str)); + return old; + } - if (map->strdup_strings) - key = map->pool ? mem_pool_strdup(map->pool, str) - : xstrdup(str); - entry->key = key; - entry->value = data; - hashmap_add(&map->map, &entry->ent); + 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)); } - return old; + hashmap_entry_init(&entry->ent, strhash(str)); + if (!map->strdup_strings) + entry->key = str; + entry->value = data; + hashmap_add(&map->map, &entry->ent); + return NULL; } struct strmap_entry *strmap_get_entry(struct strmap *map, const char *str) @@ -130,11 +135,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 b9d882a2d0..d210da5904 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 Thu Nov 5 00:22: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: 11882751 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 B8851C2D0A3 for ; Thu, 5 Nov 2020 00:24:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 434DA2080D for ; Thu, 5 Nov 2020 00:24:30 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fLTLb312" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732686AbgKEAY3 (ORCPT ); Wed, 4 Nov 2020 19:24:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54142 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732604AbgKEAXA (ORCPT ); Wed, 4 Nov 2020 19:23:00 -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 3F5EEC0613D2 for ; Wed, 4 Nov 2020 16:23:00 -0800 (PST) Received: by mail-wm1-x341.google.com with SMTP id c9so24076wml.5 for ; Wed, 04 Nov 2020 16:23:00 -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=fLTLb312kptawXSx02SwfPk5rP2oQyD0zSYv6E2XKOfy5vdI3REn07+NMp2D4g5kQ6 wawZGq3mhhGZH3mM4YbHL/rWkXR4J+7npuk773KV07159uLgazcWycaOWwniwHE0EI7W UjbFKIivr+Zxxp8geaK8GsgKCv83PbS50g5zwrmJcdZ7mOBdQ+mCSjRgH06M5cWpYnIx agtRkjFQ2lG/Ylc4kErFluUNcO1RfKyR4ncnzd8vbvM0HvQW41eD76upDInaaZaeW/6n +wcIRGyniEFVSwQF/ndRJGCPBLL39bKJDZb7jroGJ2LmoLcm9Wo7jU9o3Vw1StBlNPVc XBuA== 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=e9vrOVCg5nBxxvBCtfzqjEJxGCB9caOVoV10zlNgBDH29EQ3HSVarcLTwHU2aa/sgF yX7/EoLJ44mBcY8K0CKkS782NytXorABxnudG2QqhpOIOpfbZ4u65uoFsX/tlf8Wf+rR Uhl1NCxmqyBYFdfziy2uYuZJc8k2nYQv/89Rf+VUsuMII/s9sxvnoJs34DVme1NnNTi1 Z847YIyaOXehBvbp/j0malHlq8+1CRvmQVnkZwkyp+jq7LGU+kmwCZaHqlMXkmfyMRQz hH0TIHR1kk/s6R3jLFSxvkPBED2lEU2zBNcmMBXKdfnG8yH1p5RB0lnBvAStQW1SlDTN 2Z0w== X-Gm-Message-State: AOAM532UZog1pIoUPTGv5d7YWEYsw/fSxaqpWV3EX7MMEVLmf+KLNqLv F2G+Nw/DFLo7ITJHqOlXh8mpx1FJ9VI= X-Google-Smtp-Source: ABdhPJzJGSE/uAzP/FMD2IEZLUzQK3JG9gO2+MFtG5gS4Q+S8NMLFnXXHExcpj3R2XkRAW2wgD6Oaw== X-Received: by 2002:a1c:7301:: with SMTP id d1mr50563wmb.141.1604535778651; Wed, 04 Nov 2020 16:22:58 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id s188sm13996wmf.45.2020.11.04.16.22.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 16:22:58 -0800 (PST) Message-Id: <617926540b837576a07f8e93272ea729f37077d6.1604535766.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Thu, 05 Nov 2020 00:22:45 +0000 Subject: [PATCH v4 13/13] 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) {