4 Commits

Author SHA1 Message Date
521b38c550 ci: issue templates, issue config
Some checks failed
CI / Check PR Title (pull_request) Failing after 15s
CI / Go Lint (pull_request) Successful in 31s
CI / Markdown Lint (pull_request) Successful in 17s
CI / Makefile Lint (pull_request) Successful in 31s
CI / Unit Tests (pull_request) Successful in 29s
CI / Fuzz Tests (pull_request) Successful in 1m0s
CI / Mutation Tests (pull_request) Successful in 1m4s
2026-03-29 22:19:46 +02:00
cbe4483326 revert: release.yml
- It is not needed, because this is a library. We are not shipping a binary.
2026-03-29 22:00:54 +02:00
3bb663dc8b ci: release workflow with 'go-releaser' 2026-03-29 21:49:59 +02:00
db2dfb466b ci: add 'check-pr-title' job to pipeline 2026-03-29 21:47:11 +02:00
8 changed files with 46 additions and 35 deletions

View File

@@ -7,20 +7,20 @@ body:
id: context id: context
attributes: attributes:
label: Context label: Context
placeholder: What circumstances led to the bug? description: What circumstances led to the bug?
validations: validations:
required: true required: true
- type: textarea - type: textarea
id: expected-behavior id: expected-behavior
attributes: attributes:
label: Expected Behavior label: Expected Behavior
placeholder: What did you expect would happen? description: What did you expect would happen?
validations: validations:
required: true required: true
- type: textarea - type: textarea
id: actual-behavior id: actual-behavior
attributes: attributes:
label: Actual Behavior label: Actual Behavior
placeholder: What happened, and why was it unexpected? description: What happened, and why was it unexpected?
validations: validations:
required: true required: true

View File

@@ -6,10 +6,18 @@ name: ✨ Feature Request
about: Suggest an idea for this project about: Suggest an idea for this project
title: "[FEATURE]: " title: "[FEATURE]: "
body: body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature request! 🤗
Please make sure this feature request hasn't been already submitted by
someone by looking through other open/closed issues. 😃
- type: dropdown - type: dropdown
attributes: attributes:
multiple: false multiple: false
label: Feature Type label: Type of Feature
description: Select the type of feature request.
options: options:
- "✨ New Feature" - "✨ New Feature"
- "📝 Documentation" - "📝 Documentation"
@@ -23,7 +31,7 @@ body:
id: description id: description
attributes: attributes:
label: Description label: Description
placeholder: | description: |
Give us a brief description of the feature or enhancement you would Give us a brief description of the feature or enhancement you would
like! like!
validations: validations:
@@ -32,6 +40,6 @@ body:
id: additional-information id: additional-information
attributes: attributes:
label: Additional Information label: Additional Information
placeholder: | description: |
Give us some additional information on the feature request like proposed Give us some additional information on the feature request like proposed
solutions, links, screenshots, etc. solutions, links, screenshots, etc.

View File

@@ -1,2 +1,2 @@
# yaml-language-server: $schema=https://www.schemastore.org/gitea-issue-config.json # yaml-language-server: $schema=https://www.schemastore.org/gitea-issue-config.json
blank_issues_enabled: false blank_issues_enabled: true

View File

@@ -1,17 +0,0 @@
---
name: "New Pull Request"
about: "Standard PR template"
title: ""
ref: "main"
---
## Description
## Changes
### Design Decisions
## Checklist
- [ ] Tests pass
- [ ] Docs updated

View File

@@ -9,12 +9,10 @@ jobs:
check-pr-title: check-pr-title:
name: Check PR Title name: Check PR Title
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
env:
TITLE: ${{ gitea.event.pull_request.title }}
steps: steps:
- run: | - run: |
if ! echo "$TITLE" | grep -qE '^(WIP: )?(feat|fix|docs|chore|ci|test|refactor|perf|build|style|revert)(\(.+\))?(!)?: .+'; then TITLE="${{ gitea.event.pull_request.title }}"
if ! echo "$TITLE" | grep -qE '^(feat|fix|docs|chore|ci|test|refactor|perf|build|style|revert)(\(.+\))?(!)?: .+'; then
echo "::error::Pull Request title must follow conventional commits" echo "::error::Pull Request title must follow conventional commits"
exit 1 exit 1
fi fi

View File

@@ -3,6 +3,7 @@ package cuckoo_test
import ( import (
"fmt" "fmt"
"maps" "maps"
"math"
"os" "os"
"testing" "testing"
@@ -29,6 +30,7 @@ type fuzzStep struct {
type fuzzScenario struct { type fuzzScenario struct {
seedA, seedB uint32 seedA, seedB uint32
capacity, growthFactor uint8 capacity, growthFactor uint8
load float64
steps []fuzzStep steps []fuzzStep
} }
@@ -46,6 +48,7 @@ func FuzzInsertLookup(f *testing.F) {
seedA, seedB := scenario.seedA, scenario.seedB seedA, seedB := scenario.seedA, scenario.seedB
growthFactor := max(2, int(scenario.growthFactor)) growthFactor := max(2, int(scenario.growthFactor))
capacity := int(scenario.capacity) capacity := int(scenario.capacity)
minimumLoad := math.Abs(math.Mod(scenario.load, 1.0))
// If they are the same number, the hashes will clash, always causing an // If they are the same number, the hashes will clash, always causing an
// error. // error.
@@ -53,8 +56,14 @@ func FuzzInsertLookup(f *testing.F) {
t.Skip() t.Skip()
} }
fmt.Fprintf(os.Stderr, "seedA=%d seedB=%d capacity=%d growthFactor=%d\n", // If the load is too high, the hashs will not be able to allocate
seedA, seedB, capacity, growthFactor) // properly.
if minimumLoad > 0.20 {
t.Skip()
}
fmt.Fprintf(os.Stderr, "seedA=%d seedB=%d capacity=%d growthFactor=%d minimumLoad=%f\n",
seedA, seedB, capacity, growthFactor, minimumLoad)
actual := cuckoo.NewCustomTable[uint32, uint32]( actual := cuckoo.NewCustomTable[uint32, uint32](
offsetHash(seedA), offsetHash(seedA),
@@ -62,6 +71,7 @@ func FuzzInsertLookup(f *testing.F) {
func(a, b uint32) bool { return a == b }, func(a, b uint32) bool { return a == b },
cuckoo.Capacity(capacity), cuckoo.Capacity(capacity),
cuckoo.GrowthFactor(growthFactor), cuckoo.GrowthFactor(growthFactor),
cuckoo.MinimumLoad(minimumLoad),
) )
expected := map[uint32]uint32{} expected := map[uint32]uint32{}

View File

@@ -12,12 +12,11 @@ const DefaultCapacity uint64 = 16
// hash table implementations use 2. // hash table implementations use 2.
const DefaultGrowthFactor uint64 = 2 const DefaultGrowthFactor uint64 = 2
// defaultMinimumLoad is the default lowest acceptable occupancy of a [Table]. // DefaultMinimumLoad is the default lowest acceptable occupancy of a [Table].
// The higher the minimum load, the more likely that a [Table.Put] will not // The value of 5% is taken from [libcuckoo].
// succeed. The value of 5% is taken from [libcuckoo].
// //
// [libcuckoo]: https://github.com/efficient/libcuckoo/blob/656714705a055df2b7a605eb3c71586d9da1e119/libcuckoo/cuckoohash_config.hh#L21 // [libcuckoo]: https://github.com/efficient/libcuckoo/blob/656714705a055df2b7a605eb3c71586d9da1e119/libcuckoo/cuckoohash_config.hh#L21
const defaultMinimumLoad float64 = 0.05 const DefaultMinimumLoad float64 = 0.05
type settings struct { type settings struct {
growthFactor uint64 growthFactor uint64
@@ -39,6 +38,19 @@ func Capacity(value int) Option {
return func(s *settings) { s.bucketSize = uint64(value) } return func(s *settings) { s.bucketSize = uint64(value) }
} }
// MinimumLoad modifies the [DefaultMinimumLoad] of the [Table]. The value must
// be between 0.00 and 1.00.
//
// The higher the minimum load, the more likely that a [Table.Put] will not
// succeed. Minimum loads above 20% are not tested.
func MinimumLoad(value float64) Option {
if value < 0.00 || value > 1.00 {
panic(fmt.Sprintf("go-cuckoo: MinimumLoad must be between 0.00 and 1.00, got %f", value))
}
return func(s *settings) { s.minLoadFactor = value }
}
// GrowthFactor controls how much the capacity of the [Table] multiplies when // GrowthFactor controls how much the capacity of the [Table] multiplies when
// it must resize. The value must be greater than 1. // it must resize. The value must be greater than 1.
func GrowthFactor(value int) Option { func GrowthFactor(value int) Option {

View File

@@ -198,7 +198,7 @@ func NewCustomTable[K, V any](hashA, hashB Hash[K], compare EqualFunc[K], option
settings := &settings{ settings := &settings{
growthFactor: DefaultGrowthFactor, growthFactor: DefaultGrowthFactor,
bucketSize: DefaultCapacity, bucketSize: DefaultCapacity,
minLoadFactor: defaultMinimumLoad, minLoadFactor: DefaultMinimumLoad,
} }
for _, option := range options { for _, option := range options {