[libc-commits] [libc] [libc] [search] implement hcreate(_r)/hsearch(_r)/hdestroy(_r) (PR #73469)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Sun Nov 26 19:36:12 PST 2023


================
@@ -0,0 +1,229 @@
+//===-- Fix-sized Monotonic HashTable ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_HASHTABLE_table_H
+#define LLVM_LIBC_SRC___SUPPORT_HASHTABLE_table_H
+
+#include "include/llvm-libc-types/ENTRY.h"
+#include "src/__support/CPP/type_traits.h"
+#include "src/__support/HashTable/bitmask.h"
+#include "src/__support/bit.h"
+#include "src/__support/hash.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/memory_size.h"
+#include "src/string/memset.h"
+#include "src/string/strcmp.h"
+#include "src/string/strlen.h"
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+namespace LIBC_NAMESPACE {
+namespace internal {
+
+static LIBC_INLINE uint8_t secondary_hash(uint64_t hash) {
+  // top 7 bits of the hash.
+  return static_cast<uint8_t>((hash >> 57) & 0x7f);
+}
+
+// Probe sequence based on triangular numbers, which is guaranteed (since our
+// table size is a power of two) to visit every group of elements exactly once.
+//
+// A triangular probe has us jump by 1 more group every time. So first we
+// jump by 1 group (meaning we just continue our linear scan), then 2 groups
+// (skipping over 1 group), then 3 groups (skipping over 2 groups), and so on.
+//
+// If we set sizeof(Group) to be one unit:
+//               T[k] = sum {1 + 2 + ... + k} = k * (k + 1) / 2
+// It is provable that T[k] mod 2^m generates a permutation of
+//                0, 1, 2, 3, ..., 2^m - 2, 2^m - 1
+// Detailed proof is available at:
+// https://fgiesen.wordpress.com/2015/02/22/triangular-numbers-mod-2n/
+struct ProbeSequence {
+  size_t position;
+  size_t stride;
+  size_t entries_mask;
+
+  size_t next() {
+    position += stride;
+    position &= entries_mask;
+    stride += sizeof(Group);
+    return position;
+  }
+};
+
+// The number of entries is at least group width: we do not
+// need to do the fixup when we set the control bytes.
+// The number of entries is at least 8: we don't have to worry
+// about special sizes when check the fullness of the table.
+static LIBC_INLINE size_t capacity_to_entries(size_t cap) {
+  if (8 >= sizeof(Group) && cap < 8)
+    return 8;
+  if (16 >= sizeof(Group) && cap < 15)
+    return 16;
+  if (cap < sizeof(Group))
+    cap = sizeof(Group);
+  // overflow is always checked in allocate()
+  return next_power_of_two(cap * 8 / 7);
+}
+
+// The heap memory layout for N buckets HashTable is as follows:
+//
+//             =======================
+//             |   N * Entry         |
+//             ======================= <- align boundary
+//             |   Header            |
+//             =======================
+//             |   (N + 1) * Byte    |
+//             =======================
+//
+// The trailing group part is to make sure we can always load
+// a whole group of control bytes.
+
+struct HashTable {
+  HashState state;
+  size_t entries_mask;    // number of buckets - 1
+  size_t available_slots; // less than capacity
+private:
+  // How many entries are there in the table.
+  size_t num_of_entries() const { return entries_mask + 1; }
+
+  bool is_full() const { return available_slots == 0; }
+
+  size_t offset_from_entries() const {
+    size_t entries_size = num_of_entries() * sizeof(ENTRY);
+    return entries_size + offset_to(entries_size, alignof(HashTable));
----------------
SchrodingerZhu wrote:

I catch this issue after the submission. It should be `table_alignment` rather than `alignof(HashTable)`.

https://github.com/llvm/llvm-project/pull/73469


More information about the libc-commits mailing list