From e4404673f6079fef5828c70b168dfcf51582e36f Mon Sep 17 00:00:00 2001 From: Linneeeeeeee Date: Wed, 27 Sep 2023 13:10:23 +1000 Subject: [PATCH] Dev (#15) --- .editorconfig | 20 ++ .github/FUNDING.yml | 2 + .github/ISSUE_TEMPLATE/README.md | 2 + .github/ISSUE_TEMPLATE/bug_report.yml | 75 ++++++ .github/ISSUE_TEMPLATE/config.yml | 6 + .github/ISSUE_TEMPLATE/feature_request.yml | 62 +++++ .github/PULL_REQUEST_TEMPLATE.md | 25 ++ .github/dependabot.yml | 16 ++ .github/workflows/codeql.yml | 37 +++ .github/workflows/go.yml | 28 -- .github/workflows/pull_request.yml | 42 +++ .github/workflows/stale.yml | 31 +++ .gitignore | 13 +- .pre-commit-config.yaml | 21 ++ BRANCH_NAMING_CONVENTION.md | 69 +++++ .travis.yml => CHANGELOG.md | 0 CODEOWNERS.md | 1 + CODE_OF_CONDUCT.md | 4 + CONTRIBUTING.md | 59 +++++ Dockerfile | 25 ++ GOVERNANCE.md | 0 Makefile | 38 +++ NOTICE | 1 + README.md | 169 ++++-------- SECURITY.md | 22 ++ SUPPORT.md | 1 + VERSION | 0 bool.go | 264 ------------------ byte.go | 264 ------------------ doc.go | 1 + docker-compose.yml | 9 + go.mod | 3 + hashtable.go | 35 +++ hashtable_test.go | 49 ++++ int.go | 264 ------------------ int_test.go | 71 ----- lex.go | 263 ------------------ lex_test.go | 294 --------------------- requirements-dev.txt | 9 + string.go | 264 ------------------ string_test.go | 72 ----- 41 files changed, 728 insertions(+), 1903 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/FUNDING.yml create mode 100644 .github/ISSUE_TEMPLATE/README.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/codeql.yml delete mode 100644 .github/workflows/go.yml create mode 100644 .github/workflows/pull_request.yml create mode 100644 .github/workflows/stale.yml create mode 100644 .pre-commit-config.yaml create mode 100644 BRANCH_NAMING_CONVENTION.md rename .travis.yml => CHANGELOG.md (100%) create mode 100644 CODEOWNERS.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 Dockerfile create mode 100644 GOVERNANCE.md create mode 100644 Makefile create mode 100644 NOTICE create mode 100644 SECURITY.md create mode 100644 SUPPORT.md create mode 100644 VERSION delete mode 100644 bool.go delete mode 100644 byte.go create mode 100644 doc.go create mode 100644 docker-compose.yml create mode 100644 go.mod create mode 100644 hashtable.go create mode 100644 hashtable_test.go delete mode 100644 int.go delete mode 100644 int_test.go delete mode 100644 lex.go delete mode 100644 lex_test.go create mode 100644 requirements-dev.txt delete mode 100644 string.go delete mode 100644 string_test.go diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c1789af --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# http://editorconfig.org +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[{Makefile,go.mod,go.sum,*.go,.gitmodules}] +indent_style = tab +indent_size = 4 + +[Dockerfile] +indent_size = 4 diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..f7f8f14 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: +- lindsaygelle diff --git a/.github/ISSUE_TEMPLATE/README.md b/.github/ISSUE_TEMPLATE/README.md new file mode 100644 index 0000000..8ed6a88 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/README.md @@ -0,0 +1,2 @@ +# Issue Template +Issue Template diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..7d5374b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,75 @@ +--- +name: Bug Report +description: Report a bug +title: (short issue description) +labels: + - bug +assignees: + - lindsaygelle +body: + - type: textarea + id: description + attributes: + label: Describe the bug + description: What is the problem? A clear and concise description of the bug. + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected Behavior + description: | + What did you expect to happen? + validations: + required: true + - type: textarea + id: current + attributes: + label: Current Behavior + description: | + What actually happened? + + Please include full errors, uncaught exceptions, stack traces, and relevant logs. + If service responses are relevant, please include wire logs. + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Reproduction Steps + description: | + Provide a self-contained, concise snippet of code that can be used to reproduce the issue. + For more complex issues provide a repo with the smallest sample that reproduces the bug. + + Avoid including business logic or unrelated code, it makes diagnosis more difficult. + The code sample should be an SSCCE. See http://sscce.org/ for details. In short, please provide a code sample that we can copy/paste, run and reproduce. + validations: + required: true + - type: textarea + id: solution + attributes: + label: Possible Solution + description: | + Suggest a fix/reason for the bug + validations: + required: false + - type: textarea + id: context + attributes: + label: Additional Information/Context + description: | + Anything else that might be relevant for troubleshooting this bug. Providing context helps us come up with a solution that is most useful in the real world. + validations: + required: false + - type: input + id: sdk-version + attributes: + label: SDK version used + validations: + required: true + - type: input + id: environment + attributes: + label: Environment details (OS name and version, etc.) + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..f153fcd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,6 @@ +--- +blank_issues_enabled: false +contact_links: + - name: General Question + url: https://github.com/lindsaygelle/hashtable/discussions/categories/q-a + about: Please ask and answer questions as a discussion thread diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..9e5e2eb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,62 @@ +--- +name: Feature Request +description: Suggest an idea for this project +title: "(short issue description)" +labels: + - feature-request + - needs-triage +assignees: + - lindsaygelle +body: + - type: textarea + id: description + attributes: + label: Describe the feature + description: A clear and concise description of the feature you are proposing. + validations: + required: true + - type: textarea + id: use-case + attributes: + label: Use Case + description: | + Why do you need this feature? For example: "I'm always frustrated when..." + validations: + required: true + - type: textarea + id: solution + attributes: + label: Proposed Solution + description: | + Suggest how to implement the addition or change. Please include prototype/workaround/sketch/reference implementation. + validations: + required: false + - type: textarea + id: other + attributes: + label: Other Information + description: | + Any alternative solutions or features you considered, a more detailed explanation, stack traces, related issues, links for context, etc. + validations: + required: false + - type: checkboxes + id: ack + attributes: + label: Acknowledgements + options: + - label: I may be able to implement this feature request + required: false + - label: This feature might incur a breaking change + required: false + - type: input + id: sdk-version + attributes: + label: SDK version used + validations: + required: true + - type: input + id: environment + attributes: + label: Environment details (OS name and version, etc.) + validations: + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..07cdbd8 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,25 @@ +### Description +[Provide a brief description of the changes in this pull request.] + +### Related Issue +[Reference any related issue(s) or feature request(s) here. For example: "Closes #123"] + +### Changes Made +[Explain the changes you made in this pull request. Include any relevant details about code modifications, added features, or bug fixes.] + +### Screenshots (if applicable) +[If your changes include visual updates or additions, provide screenshots to showcase them.] + +### How to Test +[Explain how reviewers or others can test your changes. Include specific steps, commands, or scenarios to verify the functionality.] + +### Checklist +- [ ] I have followed the coding style guidelines of the project. +- [ ] My code passes all existing unit tests. +- [ ] I have added new unit tests to cover the changes where applicable. +- [ ] I have updated the documentation to reflect the changes. +- [ ] My changes do not introduce any new warnings or errors. +- [ ] I have tested my changes thoroughly. + +### Additional Notes +[Include any additional information, context, or notes that might be helpful for reviewers.] diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..12f475e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + # Go dependency updates + - package-ecosystem: gomod + directory: / + schedule: + interval: daily + labels: + - dependencies + # GitHub actions updates + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + labels: + - dependencies diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..735bcb4 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,37 @@ +name: codeql + +on: + push: + branches: + - main + pull_request: + branches: + - main + schedule: + - cron: 30 1 * * * + +jobs: + main: + defaults: + run: + shell: bash + permissions: + actions: read + contents: read + security-events: write + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + strategy: + fail-fast: false + matrix: + language: + - go + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + steps: + - uses: actions/checkout@v4 + - uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + - uses: github/codeql-action/autobuild@v2 + - uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index cd41905..0000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Go -on: [push] -jobs: - - build: - name: Build - runs-on: ubuntu-latest - steps: - - - name: Set up Go 1.13 - uses: actions/setup-go@v1 - with: - go-version: 1.13 - id: go - - - name: Check out code into the Go module directory - uses: actions/checkout@v2 - - - name: Get dependencies - run: | - go get -v -t -d ./... - if [ -f Gopkg.toml ]; then - curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh - dep ensure - fi - - - name: Build - run: go build -v . diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..397fe0e --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,42 @@ +name: pull_request + +on: + pull_request: + workflow_dispatch: + +jobs: + + lint: + defaults: + run: + shell: bash + permissions: + contents: read + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + - uses: pre-commit/action@v3.0.0 + + test: + defaults: + run: + shell: bash + permissions: + contents: read + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - macos-latest + - ubuntu-latest + - windows-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v4 + - run: go install golang.org/x/lint/golint@latest + - run: golint -set_exit_status ./... + - run: go test ./... -v diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..4d5c495 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,31 @@ +name: stale + +on: + schedule: + - cron: 30 1 * * * + +jobs: + main: + defaults: + run: + shell: bash + permissions: + contents: read + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - uses: actions/stale@v8 + with: + days-before-issue-close: 5 + days-before-issue-stale: 30 + days-before-pr-close: 10 + days-before-pr-stale: 45 + close-issue-message: | + This issue was closed because it has been stalled for 5 days with no activity. + close-pr-message: | + This PR was closed because it has been stalled for 10 days with no activity. + stale-issue-message: | + This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days. + stale-pr-message: | + This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days. diff --git a/.gitignore b/.gitignore index f1c181e..33f9de0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# # Binaries for programs and plugins *.exe *.exe~ @@ -5,8 +8,16 @@ *.so *.dylib -# Test binary, build with `go test -c` +# Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +venv/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..975d2f2 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,21 @@ +repos: + - repo: 'https://github.com/pre-commit/pre-commit-hooks' + rev: v4.3.0 + hooks: + - id: check-merge-conflict + - id: check-json + files: | + (?x)^.*(\.json)$ + - id: check-yaml + files: | + (?x)^.*(\.yaml|\.yml)$ + - id: end-of-file-fixer + - id: debug-statements + - id: mixed-line-ending + - id: no-commit-to-branch + args: [--branch, main] + - id: trailing-whitespace + - repo: 'https://github.com/codespell-project/codespell' + rev: v2.1.0 + hooks: + - id: codespell diff --git a/BRANCH_NAMING_CONVENTION.md b/BRANCH_NAMING_CONVENTION.md new file mode 100644 index 0000000..dd805b1 --- /dev/null +++ b/BRANCH_NAMING_CONVENTION.md @@ -0,0 +1,69 @@ +# Branch Naming Convention + +This document outlines the branch naming convention to be followed for our project/repository. Consistent and descriptive branch names help us maintain a clear and organized codebase. + +## Types of Branches + +### 1. Feature Branches + +Feature branches are used to develop new features or enhancements. They should be created from the `main` branch. + +Naming Convention: `feature/descriptive-feature-name` + +Example: `feature/user-authentication` + +### 2. Bugfix Branches + +Bugfix branches are used to address and fix bugs or issues in the code. They should be created from the `main` branch. + +Naming Convention: `bugfix/descriptive-bug-description` + +Example: `bugfix/navigation-bar-overflow` + +### 3. Hotfix Branches + +Hotfix branches are used to address critical issues that need immediate attention and cannot wait for the next regular release. They should be created from the `main` branch. + +Naming Convention: `hotfix/descriptive-hotfix-description` + +Example: `hotfix/critical-security-vulnerability` + +## Special Cases + +### 1. Release Branches + +Release branches are used to prepare the codebase for a new release. They are created from the `main` branch when the code is ready for deployment. They might be prefixed with the release version. + +Naming Convention: `release/version` + +Example: `release/1.0.0` + +### 2. Main Branch + +The main branch is the primary branch of the repository and represents the latest stable version of the project. + +Branch Name: `main` + +## General Guidelines + +- Use lowercase letters for branch names. +- Use hyphens to separate words in the branch names (e.g., `feature/new-feature`). +- Keep branch names concise and descriptive. +- Avoid using abbreviations or acronyms unless they are widely understood in the context of the project. + +## Examples + +### Good Examples + +- `feature/user-profile` +- `bugfix/login-page-styling` +- `hotfix/404-page-error` + +### Bad Examples + +- `f/newfeature` (too short and lacks descriptive information) +- `fix` (not descriptive enough) + +Remember to always follow this branch naming convention to ensure clarity and consistency in our code repository. + +If you have any questions or need further clarification, feel free to reach out to the team. diff --git a/.travis.yml b/CHANGELOG.md similarity index 100% rename from .travis.yml rename to CHANGELOG.md diff --git a/CODEOWNERS.md b/CODEOWNERS.md new file mode 100644 index 0000000..eacdf8f --- /dev/null +++ b/CODEOWNERS.md @@ -0,0 +1 @@ +* @lindsaygelle diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..5b627cf --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,4 @@ +## Code of Conduct +This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). +For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact +opensource-codeofconduct@amazon.com with any additional questions or comments. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5ab94f2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,59 @@ +Contributing Code +----------------- +A good pull request: + +- Is clear. +- Works across all supported versions of Go. +- Follows the existing style of the code base . +- Has comments included as needed. + +- A test case that demonstrates the previous flaw that now passes with + the included patch, or demonstrates the newly added feature. +- If it adds/changes a public API, it must also include documentation + for those changes. +- Must be appropriately [licensed](./LICENSE). + +Reporting An Issue/Feature +-------------------------- +First, check to see if there's an existing issue/pull request for the +bug/feature. All issues are at +https://github.com/lindsaygelle/hashtable/issues and pull reqs are at +https://github.com/lindsaygelle/hashtable/pulls. + +If there isn't an existing issue there, please file an issue. The +ideal report includes: + +- A description of the problem/suggestion. +- How to recreate the bug. +- If relevant, including the versions of your: + + - Go language + - hashtable + - Optionally of the other dependencies involved + +- If possible, create a pull request with a (failing) test case + demonstrating what's wrong. This makes the process for fixing bugs + quicker & gets issues resolved sooner. + +Codestyle +--------- +This project uses Go format to enforce codstyle requirements. We've codified this +process using a tool called `pre-commit `__. pre-commit +allows us to specify a config file with all tools required for code linting, +and surfaces either a git commit hook, or single command, for enforcing these. + +To validate your PR prior to publishing, you can use the following +`installation guide `__ to setup pre-commit. + +If you don't want to use the git commit hook, you can run the below command +to automatically perform the codestyle validation: + +.. code-block:: bash + + $ pre-commit run + +This will automatically perform simple updates (such as white space clean up) +and provide a list of any failing Go formatting checks. After these are addressed, +you can commit the changes prior to publishing the PR. +These checks are also included in our CI setup under the "Lint" workflow which +will provide output on Github for anything missed locally. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2e51460 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +# Use the latest Alpine as the base image +FROM alpine:latest + +# Install necessary dependencies for building Go applications +RUN apk add --no-cache ca-certificates git + +# Set the latest Go version as an environment variable +ENV GO_VERSION=1.21.0 + +# Download and install the latest Go binary +RUN wget -q https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz && \ + tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz && \ + rm go${GO_VERSION}.linux-amd64.tar.gz + +# Add Go binaries to the system path +ENV PATH="/usr/local/go/bin:${PATH}" + +# Set the working directory +WORKDIR /go/src/github.com/lindsaygelle/hashtable + +# Copy the application source code into the container +COPY . . + +# Download and cache the Go module dependencies +RUN go mod download diff --git a/GOVERNANCE.md b/GOVERNANCE.md new file mode 100644 index 0000000..e69de29 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4b6f689 --- /dev/null +++ b/Makefile @@ -0,0 +1,38 @@ +.PHONY: help test ci +.DEFAULT_GOAL := help + +help: ## Displays this help message. + @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) + +semgrep: ## Run semgrep + semgrep --config auto + +lint: ## Run golangci-lint + golangci-lint run ./... + +vet: ## Run vetting checks + go vet ./... + +report: ## Run goreportcard + goreportcard-cli + +## Runs the tests and vetting +test: vet + go test -v -cover -race -count=1 ./... + +test-all: semgrep lint test report ## Runs the tests, vetting, and golangci-lint, and semgrep + +ci: vet ## Runs the tests and vetting checks (specific for CI) + go test -cover -race -count=1 ./... + +## Runs the tests and benchmarking +bench: + go test -bench . -cpu=4 + +cover: FILE := /tmp/coverage.out # Define coverage file +cover: ## Runs the tests and check & view the test coverage + go test -race -coverprofile=$(FILE) -covermode=atomic $(TARGET) + go tool cover -func=$(FILE) + +cover-all: TARGET := ./... +cover-all: cover diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..be83d5d --- /dev/null +++ b/NOTICE @@ -0,0 +1 @@ +hashtable diff --git a/README.md b/README.md index 02b52c8..520f9a6 100644 --- a/README.md +++ b/README.md @@ -1,142 +1,75 @@ -[![Build Status](https://travis-ci.org/gellel/lex.svg?branch=master)](https://travis-ci.org/gellel/lex) -[![Apache V2 License](https://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/gellel/lex/blob/master/LICENSE) +# Hashtable +Hashtable is a [Go](https://github.com/golang/go) package that provides a generic hashtable with extended functionality. It abstracts common map operations, such as adding, deleting, iterating, and more, making it easier to work with maps in Go. -# Lex +![Hashtable]() -Package lex is a package of map interfaces to handle common map-like operations. +[![PkgGoDev](https://pkg.go.dev/badge/github.com/lindsaygelle/hashtable)](https://pkg.go.dev/github.com/lindsaygelle/hashtable) +[![Go Report Card](https://goreportcard.com/badge/github.com/lindsaygelle/hashtable)](https://goreportcard.com/report/github.com/lindsaygelle/hashtable) +[![GitHub release (latest by date)](https://img.shields.io/github/v/release/lindsaygelle/hashtable)](https://github.com/lindsaygelle/hashtable/releases) +[![GitHub](https://img.shields.io/github/license/lindsaygelle/hashtable)](LICENSE.txt) +[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v1.4%20adopted-ff69b4.svg)](CODE_OF_CONDUCT.md) -Lex contains a single Lex struct that exposes methods to perform traversal and mutation operations -for a map of Go interfaces. The Lex struct can be extended to handle storing and retrieving -of discrete Go types. +## Features -Package map comes with all Go primative types as interfaces out of the box. Each type is named by -its Golang namespace and contains the _er_ pattern in its name. For example, a map of strings is -named `lex.Stringer`. +## Installation +You can install it in your Go project using `go get`: -The map interfaces do not expose the underlying map to prevent a dirty reference. -This pattern should be adopted when wrapping the Lex struct. - -The package is built around the Go API reference documentation. Please consider using `godoc` -to build custom integrations. If you are using Go 1.12 or earlier, godoc should be included. All -Go 1.13 users can grab this package using the `go get` flow. - -## Installing - -Use `go get` to retrieve the SDK to add it to your `GOPATH` workspace, or project's Go module dependencies. - -```go get github.com/gellel/lex``` - -To update the SDK use `go get -u` to retrieve the latest version of the SDK. - -```go get -u github.com/gellel/lex``` - -## Dependencies - -The SDK includes a vendor folder containing the runtime dependencies of the SDK. The metadata of the SDK's dependencies can be found in the Go module file go.mod. - -## Go Modules - -If you are using Go modules, your go get will default to the latest tagged release version of the SDK. To get a specific release version of the SDK use `@` in your `go get` command. - -```go get github.com/gelle/lex@``` - -To get the latest SDK repository change use @latest. - -## License - -This SDK is distributed under the Apache License, Version 2.0, see LICENSE for more information. - -## Snippets +```sh +go get github.com/lindsaygelle/hashtable +``` -Lex exports all primative Go types as interfaces. +## Usage +Import the package into your Go code: ```Go -package main - import ( - "fmt" - - "github.com/gellel/lex" + "github.com/lindsaygelle/hashtable" ) +``` -var ( - b lex.Byter // map[interface{}]byte - bo lex.Booler // map[interface{}]bool - c64 lex.Complexer64 // map[interface{}]complex64 - c128 lex.Complexer128 // map[interface{}]complex128 - f32 lex.Floater32 // map[interface{}]float32 - f64 lex.Floater64 // map[interface{}]float64 - i lex.Inter // map[interface{}]interface{} - i8 lex.Inter8 // map[interface{}]int8 - i16 lex.Inter16 // map[interface{}]int16 - i32 lex.Inter32 // map[interface{}]int32 - i64 lex.Inter64 // map[interface{}]int64 - r lex.Runer // map[interface{}]rune - l *lex.Lex // map[interface{}]interface{} - u lex.UInter // map[interface{}]uint - u8 lex.UInter8 // map[interface{}]uint8 - u16 lex.UInter16 // map[interface{}]uint16 - u32 lex.UInter32 // map[interface{}]uint32 - u64 lex.UInter64 // map[interface{}]uint64 - v lex.Interfacer // map[interface{}]interface{} -) +## Methods +Provided methods for `&hashtable.Hashtable[K]V`. -func main() {} -``` -Each interface is intended to handle a unique Go lang primative type. +## Examples -A Lex interface implements all methods of lex.Lex. -```Go +## Docker +A [Dockerfile](./Dockerfile) is provided for individuals that prefer containerized development. -import ( - "github.com/gellel/lex" -) +### Building +Building the Docker container: +```sh +docker build . -t hashtable +``` -func main() {} +### Running +Developing and running Go within the Docker container: +```sh +docker run -it --rm --name hashtable hashtable ``` -## Extending +## Docker Compose +A [docker-compose](./docker-compose.yml) file has also been included for convenience: +### Running +Running the compose file. +```sh +docker-compose up -d +``` -Lex supports interface extension by wrapping the Lex in an struct and exposing a corresponding interface. +## Contributing +We warmly welcome contributions to Hashtable. Whether you have innovative ideas, bug reports, or enhancements in mind, please share them with us by submitting GitHub issues or creating pull requests. For substantial contributions, it's a good practice to start a discussion by creating an issue to ensure alignment with the project's goals and direction. Refer to the [CONTRIBUTING](./CONTRIBUTING.md) file for comprehensive details. -This is the pattern implemented by this package and is used for the provided interface types. +## Branching +For a smooth collaboration experience, we have established branch naming conventions and guidelines. Please consult the [BRANCH_NAMING_CONVENTION](./BRANCH_NAMING_CONVENTION.md) document for comprehensive information and best practices. -```Go -package food +## License +Hashtable is released under the MIT License, granting you the freedom to use, modify, and distribute the code within this repository in accordance with the terms of the license. For additional information, please review the [LICENSE](./LICENSE) file. -import ( - "github.com/gellel/lex" -) +## Security +If you discover a security vulnerability within this project, please consult the [SECURITY](./SECURITY.md) document for information and next steps. + +## Code Of Conduct +This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). For additional information, please review the [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md) file. -// Food is a struct that describes food. -type Food struct { - Name string -} - -// Fooder is an interface that contains a collection of Food. -type Fooder interface { - Add(interface{}, Food) Fooder - Del(interface{}) Fooder - DelOK(interface{}) bool -} - -// fooder is a struct that interfaces with lex.Lex. -type fooder struct { l *lex.Lex } - -// Add adds a Food struct to the map. -func (f *fooder) Add(k interface{}, v Food) Fooder { - f.l.Add(k, v) - return f -} - -// Del deletes a Food struct from the map. -func (f *fooder) Del(k interface{}) Fooder { - f.l.Del(i) - return f -} - -// DelOK deletes a Food struct from the map and returns a bool on the outcome of the transaction. -func (f *fooder) DelOK(k interface{}) bool { ... } -``` \ No newline at end of file +## Acknowledgements diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..7d331f2 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,22 @@ +# Security Policy + +## Reporting a Vulnerability +We take the security of our project seriously. If you believe you have found a security vulnerability in this repository, please help by following responsible disclosure practices. + +**Please do not submit a regular issue or a pull request for security-related matters.** + +Instead, please report the vulnerability directly. We will strive to provide a timeline for resolution and disclosure of the vulnerability. + +Please include the following details in your report: + +- A clear description of the vulnerability, including steps to reproduce it. +- The affected versions of the project. +- Any additional information that could help us understand and mitigate the issue. + +## Scope +This security policy applies only to the code present in this repository. If you have identified a vulnerability in a third-party library or dependency used by this project, please follow responsible disclosure practices and report it to the maintainers of that project. + +## Security Updates +We strive to keep our project dependencies up-to-date. However, as with any software, vulnerabilities may be discovered over time. Please keep an eye on this repository and our releases for any security updates. + +Thank you for helping to keep our project safe and secure! diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 0000000..b455005 --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1 @@ +github: lindsaygelle diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..e69de29 diff --git a/bool.go b/bool.go deleted file mode 100644 index 180bc1f..0000000 --- a/bool.go +++ /dev/null @@ -1,264 +0,0 @@ -package lex - -import "sync" - -var _ Booler = (&booler{}) - -// NewBooler returns a new Booler interface. -func NewBooler() Booler { - return &booler{sync.Mutex{}, &Lex{}} -} - -// Booler is the interface that manages key value pairs for bools. -// -// Booler accepts any interface as a key but expects a bool as its value. -// Booler is safe for concurrent use by multiple goroutines without additional locking or coordination. -type Booler interface { - Add(interface{}, bool) Booler - AddLength(interface{}, bool) int - AddOK(interface{}, bool) bool - Del(interface{}) Booler - DelAll() Booler - DelLength(interface{}) int - DelSome(...interface{}) Booler - DelSomeLength(...interface{}) int - DelOK(interface{}) bool - Each(func(interface{}, bool)) Booler - EachBreak(func(interface{}, bool) bool) Booler - EachKey(func(interface{})) Booler - EachValue(func(bool)) Booler - Fetch(interface{}) bool - FetchSome(...interface{}) []bool - FetchSomeLength(...interface{}) ([]bool, int) - Get(interface{}) (bool, bool) - GetLength(interface{}) (bool, int, bool) - Has(interface{}) bool - HasSome(...interface{}) bool - Keys() []interface{} - Len() int - Map(func(interface{}, bool) bool) Booler - MapBreak(func(interface{}, bool) (bool, bool)) Booler - MapOK(func(interface{}, bool) (bool, bool)) Booler - Not(interface{}) bool - NotSome(...interface{}) bool - Values() []bool -} - -type booler struct { - mu sync.Mutex - l *Lex -} - -func (booler *booler) Add(k interface{}, v bool) Booler { - return booler.Mutate(func() { booler.l.Add(k, v) }) -} - -func (booler *booler) AddLength(k interface{}, v bool) int { - var l int - booler.Mutate(func() { l = booler.l.AddLength(k, v) }) - return l -} - -func (booler *booler) AddOK(k interface{}, v bool) bool { - var ok bool - booler.Mutate(func() { ok = booler.l.AddOK(k, v) }) - return ok -} - -func (booler *booler) Del(k interface{}) Booler { - return booler.Mutate(func() { booler.l.Del(k) }) -} - -func (booler *booler) DelAll() Booler { - return booler.Mutate(func() { booler.l.DelAll() }) -} - -func (booler *booler) DelLength(k interface{}) int { - var l int - booler.Mutate(func() { booler.l.DelLength(k) }) - return l -} - -func (booler *booler) DelSome(k ...interface{}) Booler { - return booler.Mutate(func() { booler.l.DelSome(k...) }) -} - -func (booler *booler) DelSomeLength(k ...interface{}) int { - var l int - booler.Mutate(func() { l = booler.l.DelSomeLength() }) - return l -} - -func (booler *booler) DelOK(k interface{}) bool { - var ok bool - booler.Mutate(func() { ok = booler.l.DelOK(k) }) - return ok -} - -func (booler *booler) Each(fn func(interface{}, bool)) Booler { - return booler.Mutate(func() { - booler.l.Each(func(k, v interface{}) { - fn(k, v.(bool)) - }) - }) -} - -func (booler *booler) EachBreak(fn func(k interface{}, v bool) bool) Booler { - return booler.Mutate(func() { - booler.l.EachBreak(func(k, v interface{}) bool { - return fn(k, v.(bool)) - }) - }) -} - -func (booler *booler) EachKey(fn func(k interface{})) Booler { - return booler.Mutate(func() { booler.l.EachKey(fn) }) -} - -func (booler *booler) EachValue(fn func(v bool)) Booler { - return booler.Mutate(func() { - booler.l.EachValue(func(v interface{}) { - fn(v.(bool)) - }) - }) -} - -func (booler *booler) Fetch(k interface{}) bool { - var s bool - booler.Mutate(func() { - var v = booler.l.Fetch(k) - if v != nil { - s = v.(bool) - } - }) - return s -} - -func (booler *booler) FetchSome(k ...interface{}) []bool { - var s []bool - booler.Mutate(func() { - var x interface{} - for _, x = range k { - var v = booler.l.Fetch(x) - if v == nil { - continue - } - s = append(s, v.(bool)) - } - }) - return s -} - -func (booler *booler) FetchSomeLength(k ...interface{}) ([]bool, int) { - var s = booler.FetchSome(k...) - var l = booler.Len() - return s, l -} - -func (booler *booler) Get(k interface{}) (bool, bool) { - var s bool - var v interface{} - var ok bool - booler.Mutate(func() { - v, ok = booler.l.Get(k) - if v != nil { - s = v.(bool) - } - }) - return s, ok -} - -func (booler *booler) GetLength(k interface{}) (bool, int, bool) { - var s, ok = booler.Get(k) - var l = booler.Len() - return s, l, ok -} - -func (booler *booler) Has(k interface{}) bool { - var ok bool - booler.Mutate(func() { - ok = booler.l.Has(k) - }) - return ok -} - -func (booler *booler) HasSome(k ...interface{}) bool { - var ok bool - booler.Mutate(func() { - ok = booler.l.HasSome(k...) - }) - return ok -} - -func (booler *booler) Keys() []interface{} { - var s []interface{} - booler.Mutate(func() { - s = booler.l.Keys() - }) - return s -} - -func (booler *booler) Len() int { - var l int - booler.Mutate(func() { - l = booler.l.Len() - }) - return l -} - -func (booler *booler) Map(fn func(k interface{}, s bool) bool) Booler { - return booler.Mutate(func() { - booler.l.Map(func(k, v interface{}) interface{} { - return fn(k, v.(bool)) - }) - }) -} - -func (booler *booler) MapBreak(fn func(interface{}, bool) (bool, bool)) Booler { - return booler.Mutate(func() { - booler.l.MapBreak(func(k, v interface{}) (interface{}, bool) { - return fn(k, v.(bool)) - }) - }) -} - -func (booler *booler) MapOK(fn func(interface{}, bool) (bool, bool)) Booler { - return booler.Mutate(func() { - booler.l.MapOK(func(k, v interface{}) (interface{}, bool) { - return fn(k, v.(bool)) - }) - }) -} - -func (booler *booler) Mutate(fn func()) Booler { - booler.mu.Lock() - fn() - booler.mu.Unlock() - return booler -} - -func (booler *booler) Not(k interface{}) bool { - var ok bool - booler.Mutate(func() { - ok = booler.l.Not(k) - }) - return ok -} - -func (booler *booler) NotSome(k ...interface{}) bool { - var ok bool - booler.Mutate(func() { - ok = booler.l.NotSome(k...) - }) - return ok -} - -func (booler *booler) Values() []bool { - var s = []bool{} - booler.Mutate(func() { - booler.EachValue(func(v bool) { - s = append(s, v) - }) - }) - return s -} diff --git a/byte.go b/byte.go deleted file mode 100644 index 2600f25..0000000 --- a/byte.go +++ /dev/null @@ -1,264 +0,0 @@ -package lex - -import "sync" - -var _ Byter = (&byter{}) - -// NewByter returns a new Byter interface. -func NewByter() Byter { - return &byter{sync.Mutex{}, &Lex{}} -} - -// Byter is the interface that manages key value pairs for bytes. -// -// Byter accepts any interface as a key but expects a byte as its value. -// Byter is safe for concurrent use by multiple goroutines without additional locking or coordination. -type Byter interface { - Add(interface{}, byte) Byter - AddLength(interface{}, byte) int - AddOK(interface{}, byte) bool - Del(interface{}) Byter - DelAll() Byter - DelLength(interface{}) int - DelSome(...interface{}) Byter - DelSomeLength(...interface{}) int - DelOK(interface{}) bool - Each(func(interface{}, byte)) Byter - EachBreak(func(interface{}, byte) bool) Byter - EachKey(func(interface{})) Byter - EachValue(func(byte)) Byter - Fetch(interface{}) byte - FetchSome(...interface{}) []byte - FetchSomeLength(...interface{}) ([]byte, int) - Get(interface{}) (byte, bool) - GetLength(interface{}) (byte, int, bool) - Has(interface{}) bool - HasSome(...interface{}) bool - Keys() []interface{} - Len() int - Map(func(interface{}, byte) byte) Byter - MapBreak(func(interface{}, byte) (byte, bool)) Byter - MapOK(func(interface{}, byte) (byte, bool)) Byter - Not(interface{}) bool - NotSome(...interface{}) bool - Values() []byte -} - -type byter struct { - mu sync.Mutex - l *Lex -} - -func (byter *byter) Add(k interface{}, v byte) Byter { - return byter.Mutate(func() { byter.l.Add(k, v) }) -} - -func (byter *byter) AddLength(k interface{}, v byte) int { - var l int - byter.Mutate(func() { l = byter.l.AddLength(k, v) }) - return l -} - -func (byter *byter) AddOK(k interface{}, v byte) bool { - var ok bool - byter.Mutate(func() { ok = byter.l.AddOK(k, v) }) - return ok -} - -func (byter *byter) Del(k interface{}) Byter { - return byter.Mutate(func() { byter.l.Del(k) }) -} - -func (byter *byter) DelAll() Byter { - return byter.Mutate(func() { byter.l.DelAll() }) -} - -func (byter *byter) DelLength(k interface{}) int { - var l int - byter.Mutate(func() { byter.l.DelLength(k) }) - return l -} - -func (byter *byter) DelSome(k ...interface{}) Byter { - return byter.Mutate(func() { byter.l.DelSome(k...) }) -} - -func (byter *byter) DelSomeLength(k ...interface{}) int { - var l int - byter.Mutate(func() { l = byter.l.DelSomeLength() }) - return l -} - -func (byter *byter) DelOK(k interface{}) bool { - var ok bool - byter.Mutate(func() { ok = byter.l.DelOK(k) }) - return ok -} - -func (byter *byter) Each(fn func(interface{}, byte)) Byter { - return byter.Mutate(func() { - byter.l.Each(func(k, v interface{}) { - fn(k, v.(byte)) - }) - }) -} - -func (byter *byter) EachBreak(fn func(k interface{}, v byte) bool) Byter { - return byter.Mutate(func() { - byter.l.EachBreak(func(k, v interface{}) bool { - return fn(k, v.(byte)) - }) - }) -} - -func (byter *byter) EachKey(fn func(k interface{})) Byter { - return byter.Mutate(func() { byter.l.EachKey(fn) }) -} - -func (byter *byter) EachValue(fn func(v byte)) Byter { - return byter.Mutate(func() { - byter.l.EachValue(func(v interface{}) { - fn(v.(byte)) - }) - }) -} - -func (byter *byter) Fetch(k interface{}) byte { - var s byte - byter.Mutate(func() { - var v = byter.l.Fetch(k) - if v != nil { - s = v.(byte) - } - }) - return s -} - -func (byter *byter) FetchSome(k ...interface{}) []byte { - var s []byte - byter.Mutate(func() { - var x interface{} - for _, x = range k { - var v = byter.l.Fetch(x) - if v == nil { - continue - } - s = append(s, v.(byte)) - } - }) - return s -} - -func (byter *byter) FetchSomeLength(k ...interface{}) ([]byte, int) { - var s = byter.FetchSome(k...) - var l = byter.Len() - return s, l -} - -func (byter *byter) Get(k interface{}) (byte, bool) { - var s byte - var v interface{} - var ok bool - byter.Mutate(func() { - v, ok = byter.l.Get(k) - if v != nil { - s = v.(byte) - } - }) - return s, ok -} - -func (byter *byter) GetLength(k interface{}) (byte, int, bool) { - var s, ok = byter.Get(k) - var l = byter.Len() - return s, l, ok -} - -func (byter *byter) Has(k interface{}) bool { - var ok bool - byter.Mutate(func() { - ok = byter.l.Has(k) - }) - return ok -} - -func (byter *byter) HasSome(k ...interface{}) bool { - var ok bool - byter.Mutate(func() { - ok = byter.l.HasSome(k...) - }) - return ok -} - -func (byter *byter) Keys() []interface{} { - var s []interface{} - byter.Mutate(func() { - s = byter.l.Keys() - }) - return s -} - -func (byter *byter) Len() int { - var l int - byter.Mutate(func() { - l = byter.l.Len() - }) - return l -} - -func (byter *byter) Map(fn func(k interface{}, s byte) byte) Byter { - return byter.Mutate(func() { - byter.l.Map(func(k, v interface{}) interface{} { - return fn(k, v.(byte)) - }) - }) -} - -func (byter *byter) MapBreak(fn func(interface{}, byte) (byte, bool)) Byter { - return byter.Mutate(func() { - byter.l.MapBreak(func(k, v interface{}) (interface{}, bool) { - return fn(k, v.(byte)) - }) - }) -} - -func (byter *byter) MapOK(fn func(interface{}, byte) (byte, bool)) Byter { - return byter.Mutate(func() { - byter.l.MapOK(func(k, v interface{}) (interface{}, bool) { - return fn(k, v.(byte)) - }) - }) -} - -func (byter *byter) Mutate(fn func()) Byter { - byter.mu.Lock() - fn() - byter.mu.Unlock() - return byter -} - -func (byter *byter) Not(k interface{}) bool { - var ok bool - byter.Mutate(func() { - ok = byter.l.Not(k) - }) - return ok -} - -func (byter *byter) NotSome(k ...interface{}) bool { - var ok bool - byter.Mutate(func() { - ok = byter.l.NotSome(k...) - }) - return ok -} - -func (byter *byter) Values() []byte { - var s = []byte{} - byter.Mutate(func() { - byter.EachValue(func(v byte) { - s = append(s, v) - }) - }) - return s -} diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..fe81235 --- /dev/null +++ b/doc.go @@ -0,0 +1 @@ +package hashtable diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9b74356 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +version: "3" + +services: + hashtable: + build: + context: . + dockerfile: Dockerfile + container_name: hashtable + image: hashtable:latest diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..aefac74 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/lindsaygelle/hashtable + +go 1.21.1 diff --git a/hashtable.go b/hashtable.go new file mode 100644 index 0000000..c1b8cfc --- /dev/null +++ b/hashtable.go @@ -0,0 +1,35 @@ +package hashtable + +// Hashtable represents a generic hash table that maps keys of type K to values of type V. It provides efficient key-value storage and retrieval operations. +// +// Example: +// // Create a new Hashtable with string keys and integer values. +// ht := make(hashtable.Hashtable[string, int]) +// +// // Insert key-value pairs into the hashtable. +// ht["apple"] = 5 +// ht["banana"] = 3 +// ht["cherry"] = 8 +// +// // Retrieve the value associated with a specific key. +// value := ht["banana"] // 3 +// +// // Check if a key exists in the hashtable. +// _, exists := ht["grape"] +// +// // Delete a key-value pair from the hashtable. +// delete(ht, "cherry") +type Hashtable[K comparable, V any] map[K]V + +// Add inserts a key-value pair into the hashtable. If the key already exists, its associated value is updated. +// +// Example: +// ht := make(hashtable.Hashtable[string, int]) +// ht.Add("apple", 5) +// ht.Add("banana", 3) +// ht.Add("cherry", 8) +// ht.Add("banana", 10) // Updates the value associated with the "banana" key. +func (hashtable *Hashtable[K, V]) Add(key K, value V) *Hashtable[K, V] { + (*hashtable)[key] = value + return hashtable +} diff --git a/hashtable_test.go b/hashtable_test.go new file mode 100644 index 0000000..47f64fa --- /dev/null +++ b/hashtable_test.go @@ -0,0 +1,49 @@ +package hashtable_test + +import ( + "testing" + + "github.com/lindsaygelle/hashtable" +) + +// TestHashtable tests Hashtable. +func TestHashtable(t *testing.T) { + table := hashtable.Hashtable[string, string]{ + "hello": "world"} + t.Log(table) +} + +// TestAdd tests Hashtable.Add +func TestAdd(t *testing.T) { + // Create a new hashtable + ht := make(hashtable.Hashtable[string, int]) + + // Add key-value pairs to the hashtable + ht.Add("apple", 5) + ht.Add("banana", 3) + ht.Add("cherry", 8) + + // Verify that the key-value pairs have been added correctly + expected := map[string]int{ + "apple": 5, + "banana": 3, + "cherry": 8, + } + + for key, expectedValue := range expected { + actualValue, ok := ht[key] + if !ok { + t.Fatalf("Key %s not found in the hashtable", key) + } else if actualValue != expectedValue { + t.Fatalf("Expected value for key %s is %d, but got %d", key, expectedValue, actualValue) + } + } + + // Update the value associated with the "banana" key + ht.Add("banana", 10) + + // Verify that the value has been updated correctly + if ht["banana"] != 10 { + t.Fatalf("Expected value for key 'banana' to be updated to 10, but got %d", ht["banana"]) + } +} diff --git a/int.go b/int.go deleted file mode 100644 index f41786b..0000000 --- a/int.go +++ /dev/null @@ -1,264 +0,0 @@ -package lex - -import "sync" - -var _ Inter = (&inter{}) - -// NewInter returns a new Inter interface. -func NewInter() Inter { - return &inter{sync.Mutex{}, &Lex{}} -} - -// Inter is the interface that manages key value pairs of integers. -// -// Inter accepts any interface as a key but expects a int as its value. -// Inter is safe for concurrent use by multiple goroutines without additional locking or coordination. -type Inter interface { - Add(interface{}, int) Inter - AddLength(interface{}, int) int - AddOK(interface{}, int) bool - Del(interface{}) Inter - DelAll() Inter - DelLength(interface{}) int - DelSome(...interface{}) Inter - DelSomeLength(...interface{}) int - DelOK(interface{}) bool - Each(func(interface{}, int)) Inter - EachBreak(func(interface{}, int) bool) Inter - EachKey(func(interface{})) Inter - EachValue(func(int)) Inter - Fetch(interface{}) int - FetchSome(...interface{}) []int - FetchSomeLength(...interface{}) ([]int, int) - Get(interface{}) (int, bool) - GetLength(interface{}) (int, int, bool) - Has(interface{}) bool - HasSome(...interface{}) bool - Keys() []interface{} - Len() int - Map(func(interface{}, int) int) Inter - MapBreak(func(interface{}, int) (int, bool)) Inter - MapOK(func(interface{}, int) (int, bool)) Inter - Not(interface{}) bool - NotSome(...interface{}) bool - Values() []int -} - -type inter struct { - mu sync.Mutex - l *Lex -} - -func (inter *inter) Add(k interface{}, v int) Inter { - return inter.Mutate(func() { inter.l.Add(k, v) }) -} - -func (inter *inter) AddLength(k interface{}, v int) int { - var l int - inter.Mutate(func() { l = inter.l.AddLength(k, v) }) - return l -} - -func (inter *inter) AddOK(k interface{}, v int) bool { - var ok bool - inter.Mutate(func() { ok = inter.l.AddOK(k, v) }) - return ok -} - -func (inter *inter) Del(k interface{}) Inter { - return inter.Mutate(func() { inter.l.Del(k) }) -} - -func (inter *inter) DelAll() Inter { - return inter.Mutate(func() { inter.l.DelAll() }) -} - -func (inter *inter) DelLength(k interface{}) int { - var l int - inter.Mutate(func() { inter.l.DelLength(k) }) - return l -} - -func (inter *inter) DelSome(k ...interface{}) Inter { - return inter.Mutate(func() { inter.l.DelSome(k...) }) -} - -func (inter *inter) DelSomeLength(k ...interface{}) int { - var l int - inter.Mutate(func() { l = inter.l.DelSomeLength() }) - return l -} - -func (inter *inter) DelOK(k interface{}) bool { - var ok bool - inter.Mutate(func() { ok = inter.l.DelOK(k) }) - return ok -} - -func (inter *inter) Each(fn func(interface{}, int)) Inter { - return inter.Mutate(func() { - inter.l.Each(func(k, v interface{}) { - fn(k, v.(int)) - }) - }) -} - -func (inter *inter) EachBreak(fn func(k interface{}, v int) bool) Inter { - return inter.Mutate(func() { - inter.l.EachBreak(func(k, v interface{}) bool { - return fn(k, v.(int)) - }) - }) -} - -func (inter *inter) EachKey(fn func(k interface{})) Inter { - return inter.Mutate(func() { inter.l.EachKey(fn) }) -} - -func (inter *inter) EachValue(fn func(v int)) Inter { - return inter.Mutate(func() { - inter.l.EachValue(func(v interface{}) { - fn(v.(int)) - }) - }) -} - -func (inter *inter) Fetch(k interface{}) int { - var s int - inter.Mutate(func() { - var v = inter.l.Fetch(k) - if v != nil { - s = v.(int) - } - }) - return s -} - -func (inter *inter) FetchSome(k ...interface{}) []int { - var s []int - inter.Mutate(func() { - var x interface{} - for _, x = range k { - var v = inter.l.Fetch(x) - if v == nil { - continue - } - s = append(s, v.(int)) - } - }) - return s -} - -func (inter *inter) FetchSomeLength(k ...interface{}) ([]int, int) { - var s = inter.FetchSome(k...) - var l = inter.Len() - return s, l -} - -func (inter *inter) Get(k interface{}) (int, bool) { - var s int - var v interface{} - var ok bool - inter.Mutate(func() { - v, ok = inter.l.Get(k) - if v != nil { - s = v.(int) - } - }) - return s, ok -} - -func (inter *inter) GetLength(k interface{}) (int, int, bool) { - var s, ok = inter.Get(k) - var l = inter.Len() - return s, l, ok -} - -func (inter *inter) Has(k interface{}) bool { - var ok bool - inter.Mutate(func() { - ok = inter.l.Has(k) - }) - return ok -} - -func (inter *inter) HasSome(k ...interface{}) bool { - var ok bool - inter.Mutate(func() { - ok = inter.l.HasSome(k...) - }) - return ok -} - -func (inter *inter) Keys() []interface{} { - var s []interface{} - inter.Mutate(func() { - s = inter.l.Keys() - }) - return s -} - -func (inter *inter) Len() int { - var l int - inter.Mutate(func() { - l = inter.l.Len() - }) - return l -} - -func (inter *inter) Map(fn func(k interface{}, s int) int) Inter { - return inter.Mutate(func() { - inter.l.Map(func(k, v interface{}) interface{} { - return fn(k, v.(int)) - }) - }) -} - -func (inter *inter) MapBreak(fn func(interface{}, int) (int, bool)) Inter { - return inter.Mutate(func() { - inter.l.MapBreak(func(k, v interface{}) (interface{}, bool) { - return fn(k, v.(int)) - }) - }) -} - -func (inter *inter) MapOK(fn func(interface{}, int) (int, bool)) Inter { - return inter.Mutate(func() { - inter.l.MapOK(func(k, v interface{}) (interface{}, bool) { - return fn(k, v.(int)) - }) - }) -} - -func (inter *inter) Mutate(fn func()) Inter { - inter.mu.Lock() - fn() - inter.mu.Unlock() - return inter -} - -func (inter *inter) Not(k interface{}) bool { - var ok bool - inter.Mutate(func() { - ok = inter.l.Not(k) - }) - return ok -} - -func (inter *inter) NotSome(k ...interface{}) bool { - var ok bool - inter.Mutate(func() { - ok = inter.l.NotSome(k...) - }) - return ok -} - -func (inter *inter) Values() []int { - var s = []int{} - inter.Mutate(func() { - inter.EachValue(func(v int) { - s = append(s, v) - }) - }) - return s -} diff --git a/int_test.go b/int_test.go deleted file mode 100644 index a588794..0000000 --- a/int_test.go +++ /dev/null @@ -1,71 +0,0 @@ -package lex_test - -import ( - "sync" - "testing" - - "github.com/gellel/lex" -) - -var ( - inter lex.Inter -) - -func TestInter(t *testing.T) { - var ( - ok bool - ) - inter = lex.NewInter() - ok = inter != nil - if !ok { - t.Fatalf("(lex.NewInter() lex.Inter) == nil") - } - var ( - k = 1 - v int - x int - ) - ok = inter.AddOK(k, v) - if !ok { - t.Fatalf("(lex.Inter.AddOK(interface{}, int) bool) != true") - } - x, ok = inter.Get(k) - if !ok { - t.Fatalf("(lex.Inter.Get(interface{}) (int, bool) != (_, true)") - } - ok = v == x - if !ok { - t.Fatalf("(lex.Inter.Get(interface{}) (int, bool) != (int, _)") - } - ok = inter.DelOK(k) - if !ok { - t.Fatalf("(lex.Inter.DelOK(interface{}) (bool) != true") - } -} - -func TestInterConcurrency(t *testing.T) { - var ( - ok bool - size = 20 - wg sync.WaitGroup - ) - wg.Add(1) - go func() { - defer wg.Done() - for i := 0; i < size/2; i++ { - inter.AddLength(i, i) - } - }() - wg.Add(1) - go func() { - defer wg.Done() - for i := size / 2; i < size; i++ { - inter.AddLength(i, i) - } - }() - wg.Wait() - ok = inter.Len() == size - if !ok { - t.Fatalf("(lex.Inter.Len() (int) != int") - } -} diff --git a/lex.go b/lex.go deleted file mode 100644 index cdf18c9..0000000 --- a/lex.go +++ /dev/null @@ -1,263 +0,0 @@ -package lex - -var _ lexer = (&Lex{}) - -type lexer interface { - Add(interface{}, interface{}) *Lex - AddLength(interface{}, interface{}) int - AddOK(interface{}, interface{}) bool - Del(interface{}) *Lex - DelAll() *Lex - DelLength(interface{}) int - DelSome(...interface{}) *Lex - DelSomeLength(...interface{}) int - DelOK(interface{}) bool - Each(func(interface{}, interface{})) *Lex - EachBreak(func(interface{}, interface{}) bool) *Lex - EachKey(func(interface{})) *Lex - EachValue(func(interface{})) *Lex - Fetch(interface{}) interface{} - FetchSome(...interface{}) []interface{} - Get(interface{}) (interface{}, bool) - GetLength(interface{}) (interface{}, int, bool) - Has(interface{}) bool - HasSome(...interface{}) bool - Keys() []interface{} - Len() int - Map(func(interface{}, interface{}) interface{}) *Lex - MapBreak(func(interface{}, interface{}) (interface{}, bool)) *Lex - MapOK(func(interface{}, interface{}) (interface{}, bool)) *Lex - Not(interface{}) bool - NotSome(...interface{}) bool - Values() []interface{} -} - -// Lex is an implementation of a *map[interface{}]interface{}. -// -// Lex has methods to perform traversal and mutation operations. -// -// To extend a Lex construct a struct and a supporting interface that implements the Lex methods. -type Lex map[interface{}]interface{} - -// Add adds a new key and element to the map and returns the modified map. -func (lex *Lex) Add(k interface{}, v interface{}) *Lex { - (*lex)[k] = v - return lex -} - -// AddLength adds a new key and value to the map and returns the length of the modified map. -func (lex *Lex) AddLength(k interface{}, v interface{}) int { return lex.Add(k, v).Len() } - -// AddOK adds a key and value to the map and returns a boolean confirming whether the key, value pair was successfully added. -func (lex *Lex) AddOK(k interface{}, v interface{}) bool { - var ( - ok bool - ) - if lex.Not(k) { - lex.Add(k, v) - ok = true - } - return ok -} - -// Del deletes the key and value from the map and returns the modified map. -func (lex *Lex) Del(k interface{}) *Lex { - delete((*lex), k) - return lex -} - -// DelAll deletes all keys and values from the map and returns the modified map. -func (lex *Lex) DelAll() *Lex { - (*lex) = (Lex{}) - return lex -} - -// DelLength deletes the key and value from the map and returns the length of modified map. -func (lex *Lex) DelLength(k interface{}) int { return (lex.Del(k).Len()) } - -// DelSome deletes some keys and values from the map and returns the modified map. Arguments are treated as keys to the map. -func (lex *Lex) DelSome(k ...interface{}) *Lex { - for _, k := range k { - lex.Del(k) - } - return lex -} - -// DelSomeLength deletes some keys and values from the map and returns the length of modified map. -func (lex *Lex) DelSomeLength(k ...interface{}) int { return (lex.DelSome(k...).Len()) } - -// DelOK deletes the key and value from the map and returns a boolean on the outcome of the transaction. -func (lex *Lex) DelOK(k interface{}) bool { return (lex.Del(k).Has(k) == false) } - -// Each executes a provided function once for each map key, value pair. -func (lex *Lex) Each(fn func(k interface{}, v interface{})) *Lex { - var ( - k, v interface{} - ) - for k, v = range *lex { - fn(k, v) - } - return lex -} - -// EachBreak executes a provided function once for each key, value with an optional break when the function returns false. -func (lex *Lex) EachBreak(fn func(interface{}, interface{}) bool) *Lex { - var ( - ok = true - k, v interface{} - ) - for k, v = range *lex { - ok = fn(k, v) - if !ok { - break - } - } - return lex -} - -// EachKey executes a provided function once for each key in the map. -func (lex *Lex) EachKey(fn func(k interface{})) *Lex { - lex.Each(func(k, _ interface{}) { - fn(k) - }) - return lex -} - -// EachValue executes a provided function once for each value in the map. -func (lex *Lex) EachValue(fn func(v interface{})) *Lex { - lex.Each(func(_, v interface{}) { - fn(v) - }) - return lex -} - -// Fetch retrieves the value held by the argument key without checking if the key exists. -func (lex *Lex) Fetch(k interface{}) interface{} { - var v, _ = lex.Get(k) - return v -} - -// FetchSome retrieves a slice of values from the map if they are found in the argument of keys. -func (lex *Lex) FetchSome(k ...interface{}) []interface{} { - var ( - s = []interface{}{} - ) - for _, k := range k { - var ( - v = lex.Fetch(k) - ) - if v != nil { - s = append(s, v) - } - } - return s -} - -// Get gets the value from the map using the provided key. Returns a boolean on the outcome of the transaction. -func (lex *Lex) Get(k interface{}) (interface{}, bool) { - var v, ok = (*lex)[k] - return v, ok -} - -// GetLength gets the value from the map using the provided key and returns the length of the map. -// Returns an additional boolean on the outcome of the transaction. -func (lex *Lex) GetLength(k interface{}) (interface{}, int, bool) { - var v, ok = lex.Get(k) - var l = lex.Len() - return v, l, ok -} - -// Has checks that the map has a key of the corresponding value in the map. -func (lex *Lex) Has(k interface{}) bool { - var _, ok = lex.Get(k) - return ok -} - -// HasSome checks that the map contains the series of key in the map. -func (lex *Lex) HasSome(k ...interface{}) bool { - var ok bool - var x interface{} - for _, x = range k { - ok = lex.Has(x) - if !ok { - break - } - } - return ok -} - -// Keys returns a slice of the maps keys in the order found. -func (lex *Lex) Keys() []interface{} { - var ( - s = []interface{}{} - ) - lex.Each(func(k, _ interface{}) { - s = append(s, k) - }) - return s -} - -// Len returns the number of values in the map. -func (lex *Lex) Len() int { return (len(*lex)) } - -// Map executes a provided function once for each key, value in the map and sets the returned value to the current key. -func (lex *Lex) Map(fn func(k interface{}, v interface{}) interface{}) *Lex { - lex.Each(func(k interface{}, v interface{}) { - lex.Add(k, fn(k, v)) - }) - return lex -} - -// MapBreak executes a provided function once for each key, value in the map and sets -// returned value to the current key with an optional break when the function returns false. -func (lex *Lex) MapBreak(fn func(k interface{}, v interface{}) (interface{}, bool)) *Lex { - var ok bool - lex.EachBreak(func(k, v interface{}) bool { - v, ok = fn(k, v) - if ok { - lex.Add(k, v) - } - return ok - }) - return lex -} - -// MapOK executes a provided function once for each key, value in the map and sets -// the returned value to the current key if a boolean of true is returned. -func (lex *Lex) MapOK(fn func(k interface{}, v interface{}) (interface{}, bool)) *Lex { - var ok bool - lex.Each(func(k interface{}, v interface{}) { - v, ok = fn(k, v) - if ok { - lex.Add(k, v) - } - }) - return lex -} - -// Not checks that the map does not contain the argument key in the map. -func (lex *Lex) Not(k interface{}) bool { return (lex.Has(k) == false) } - -// NotSome checks that the map does not contain the series of key in the map. -func (lex *Lex) NotSome(k ...interface{}) bool { - var ok = true - var x interface{} - for _, x = range k { - ok = lex.Not(x) - if !ok { - break - } - } - return ok -} - -// Values returns a slice of the map values in order found. -func (lex *Lex) Values() []interface{} { - var ( - s = []interface{}{} - ) - lex.Each(func(_, v interface{}) { - s = append(s, v) - }) - return s -} diff --git a/lex_test.go b/lex_test.go deleted file mode 100644 index 9ebf5e9..0000000 --- a/lex_test.go +++ /dev/null @@ -1,294 +0,0 @@ -package lex_test - -import ( - "fmt" - "math/rand" - "testing" - "time" - - "github.com/gellel/lex" -) - -var ( - l = (*&lex.Lex{}) -) - -func Test(t *testing.T) { - rand.Seed(time.Now().UnixNano()) -} - -func TestAdd(t *testing.T) { - var ( - k = rand.Intn(10) - ok bool - v = rand.Intn(10) - x interface{} - ) - l.Add(k, v) - x, ok = (l)[k] - if !ok { - t.Fatalf("(&lex.Lex.Add(interface{}, interface{}) (_, bool)) != true") - } - ok = (x == v) - if !ok { - t.Fatalf("(&lex.Lex.Add(interface{}, interface{}) (interface{}, _)) != interface{}") - } -} - -func TestAddOK(t *testing.T) { - var ( - max = 20 - min = 11 - ok bool - ) - var ( - k = (rand.Intn(max-min+1) + min) - v = (rand.Intn(k*2-k+1) + k) - ) - ok = l.AddOK(k, v) - if !ok { - t.Fatalf("(&lex.Lex.AddOK(interface{}, interface{}) (bool)) != true") - } -} - -func TestDel(t *testing.T) { - var ( - k interface{} - ok bool - ) - for k = range l { - l.Del(k) - } - ok = len(l) == 0 - if !ok { - t.Fatalf("len(&lex.Lex.Del(interface{})) != 0") - } -} - -func TestDelAll(t *testing.T) { - var ( - length int - nextLength int - ok bool - ) - for i := 0; i < (rand.Intn(10-5+1) + 5); i++ { - l.Add(i, i) - } - length = len(l) - l.DelAll() - nextLength = len(l) - ok = nextLength != length - if !ok { - t.Fatalf("len(&lex.Lex.DelAll()) != 0") - } - ok = nextLength == 0 - if !ok { - t.Fatalf("len(&lex.Lex.DelAll()) != 0") - } -} - -func TestDelSome(t *testing.T) { - var ( - size = (rand.Intn(10-5+1) + 5) - ) - var ( - k = make([]interface{}, size) - length = len(l) - ok bool - ) - for i := range k { - k[i] = i - l.Add(i, i) - } - l.DelSome(k...) - ok = len(l) == length - if !ok { - t.Fatalf("len(&lex.Lex.DelSome()) != n") - } -} - -func TestDelOK(t *testing.T) { - var ( - k = rand.Intn(10) - ok bool - ) - l.Add(k, k) - ok = l.DelOK(k) - if !ok { - t.Fatalf("(&lex.Lex.DelOK(interface{}) (bool)) != true") - } -} - -func TestEach(t *testing.T) { - var ( - size = (rand.Intn(10-5+1) + 5) - ) - var ( - k = make([]interface{}, size) - ) - for i := 0; i < size; i++ { - k = append(k, i) - } - l.Each(func(x, v interface{}) { - var ok = k[x.(int)] == v - if !ok { - t.Fatalf("(&lex.Lex.Each(func(interface{}, interface{}))) != interface{}, interface{}") - } - }) -} - -func TestEachSome(t *testing.T) { - var ( - size = (rand.Intn(10-5+1) + 5) - ) - var ( - k = make([]interface{}, size) - ) - for i := 0; i < size; i++ { - k[i] = i - l.Add(i, i) - } - var ( - v = l.FetchSome(k...) - ) - var ok = len(v) == len(k) - if !ok { - t.Fatalf("len(&lex.Lex.EachSome(interface{}...) []interface{}) != n") - } -} - -func TestGet(t *testing.T) { - var ( - k = (rand.Intn(10-5+1) + 5) - ) - l.Add(k, k) - var v, ok = l.Get(k) - if !ok { - t.Fatalf("(&lex.Lex.Get(interface{}) (_, bool)) != true") - } - ok = v == k - if !ok { - t.Fatalf("(&lex.Lex.Add(interface{}, interface{}) (interface{},)) != interface{}") - } -} - -func TestGetLength(t *testing.T) { - var ( - size = len(l) - ) - var ( - k = (rand.Intn(size*2-size+1) + size) - ) - l.Add(k, k) - var v, n, ok = l.GetLength(k) - if !ok { - t.Fatalf("(&lex.Lex.GetLength(interface{}) (_, _, bool)) != true") - } - ok = (n == (size + 1)) - if !ok { - t.Fatalf("(&lex.Lex.Get(interface{}) (_, int, _)) != n + 1") - } - ok = v == k - if !ok { - t.Fatalf("(&lex.Lex.Get(interface{}) (interface{}, _, _)) != interface{}") - } -} - -func TestHas(t *testing.T) { - var ( - size = len(l) - ) - var ( - k = (rand.Intn(size*2-size+1) + size) - ) - l.Add(k, k) - var ok = l.Has(k) - if !ok { - t.Fatalf("(&lex.Lex.Has(interface{}) (bool)) != true") - } -} - -func TestKeys(t *testing.T) { - var ( - a = []interface{}{} - k interface{} - v = []interface{}{} - ) - for k = range l { - v = append(v, k) - } - a = l.Keys() - var ok = len(a) == len(v) - if !ok { - t.Fatalf("len(&lex.Lex.Keys() []interface{}) != n") - } -} - -func TestLen(t *testing.T) { - var ok = len(l) == l.Len() - if !ok { - t.Fatalf("len(&lex.Lex.Len() int) != n") - } -} - -func TestMap(t *testing.T) { - l.Map(func(_, v interface{}) interface{} { - return fmt.Sprintf("%v", v) - }) - for _, v := range l { - switch v.(type) { - case int: - t.Fatalf("len(&lex.Lex.Map(func(interface{}, interface{}) interface{})) != string") - } - } -} - -func TestNot(t *testing.T) { - var ( - size = len(l) - ) - var ( - k = size + 1 - ) - var ok = l.Not(k) - if !ok { - t.Fatalf("(&lex.Lex.Not(interface{}) (bool)) != true") - } -} - -func TestNotSome(t *testing.T) { - var ( - size = len(l) - ) - var ( - k = (rand.Intn(size*2-size+1) + size) - ) - var v = []interface{}{} - l = lex.Lex{} - for i := k; i > size; i-- { - v = append(v, i) - } - var ok = l.NotSome(v...) - if !ok { - t.Fatalf("(&lex.Lex.NotSome(...interface{}) (bool)) != true") - } -} - -func TestValues(t *testing.T) { - var ( - k = (rand.Intn(10-5+1) + 5) - ) - var ( - a = make([]interface{}, k) - b []interface{} - ) - for i := 0; i != k; i++ { - a[i] = i - l.Add(i, i) - } - b = l.Values() - var ok = len(a) == len(b) - if !ok { - t.Fatalf("len(&lex.Lex.Values() []interface{}) != n") - } -} diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..afa608a --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,9 @@ +cfgv==3.3.1 +distlib==0.3.7 +filelock==3.12.2 +identify==2.5.26 +nodeenv==1.8.0 +platformdirs==3.9.1 +pre-commit==3.3.3 +PyYAML==6.0.1 +virtualenv==20.24.2 diff --git a/string.go b/string.go deleted file mode 100644 index 378075f..0000000 --- a/string.go +++ /dev/null @@ -1,264 +0,0 @@ -package lex - -import "sync" - -var _ Stringer = (&stringer{}) - -// NewStringer returns a new Stringer interface. -func NewStringer() Stringer { - return &stringer{sync.Mutex{}, &Lex{}} -} - -// Stringer is the interface that manages key value pairs for strings. -// -// Stringer accepts any interface as a key but expects a string as its value. -// Stringer is safe for concurrent use by multiple goroutines without additional locking or coordination. -type Stringer interface { - Add(interface{}, string) Stringer - AddLength(interface{}, string) int - AddOK(interface{}, string) bool - Del(interface{}) Stringer - DelAll() Stringer - DelLength(interface{}) int - DelSome(...interface{}) Stringer - DelSomeLength(...interface{}) int - DelOK(interface{}) bool - Each(func(interface{}, string)) Stringer - EachBreak(func(interface{}, string) bool) Stringer - EachKey(func(interface{})) Stringer - EachValue(func(string)) Stringer - Fetch(interface{}) string - FetchSome(...interface{}) []string - FetchSomeLength(...interface{}) ([]string, int) - Get(interface{}) (string, bool) - GetLength(interface{}) (string, int, bool) - Has(interface{}) bool - HasSome(...interface{}) bool - Keys() []interface{} - Len() int - Map(func(interface{}, string) string) Stringer - MapBreak(func(interface{}, string) (string, bool)) Stringer - MapOK(func(interface{}, string) (string, bool)) Stringer - Not(interface{}) bool - NotSome(...interface{}) bool - Values() []string -} - -type stringer struct { - mu sync.Mutex - l *Lex -} - -func (stringer *stringer) Add(k interface{}, v string) Stringer { - return stringer.Mutate(func() { stringer.l.Add(k, v) }) -} - -func (stringer *stringer) AddLength(k interface{}, v string) int { - var l int - stringer.Mutate(func() { l = stringer.l.AddLength(k, v) }) - return l -} - -func (stringer *stringer) AddOK(k interface{}, v string) bool { - var ok bool - stringer.Mutate(func() { ok = stringer.l.AddOK(k, v) }) - return ok -} - -func (stringer *stringer) Del(k interface{}) Stringer { - return stringer.Mutate(func() { stringer.l.Del(k) }) -} - -func (stringer *stringer) DelAll() Stringer { - return stringer.Mutate(func() { stringer.l.DelAll() }) -} - -func (stringer *stringer) DelLength(k interface{}) int { - var l int - stringer.Mutate(func() { stringer.l.DelLength(k) }) - return l -} - -func (stringer *stringer) DelSome(k ...interface{}) Stringer { - return stringer.Mutate(func() { stringer.l.DelSome(k...) }) -} - -func (stringer *stringer) DelSomeLength(k ...interface{}) int { - var l int - stringer.Mutate(func() { l = stringer.l.DelSomeLength() }) - return l -} - -func (stringer *stringer) DelOK(k interface{}) bool { - var ok bool - stringer.Mutate(func() { ok = stringer.l.DelOK(k) }) - return ok -} - -func (stringer *stringer) Each(fn func(interface{}, string)) Stringer { - return stringer.Mutate(func() { - stringer.l.Each(func(k, v interface{}) { - fn(k, v.(string)) - }) - }) -} - -func (stringer *stringer) EachBreak(fn func(k interface{}, v string) bool) Stringer { - return stringer.Mutate(func() { - stringer.l.EachBreak(func(k, v interface{}) bool { - return fn(k, v.(string)) - }) - }) -} - -func (stringer *stringer) EachKey(fn func(k interface{})) Stringer { - return stringer.Mutate(func() { stringer.l.EachKey(fn) }) -} - -func (stringer *stringer) EachValue(fn func(v string)) Stringer { - return stringer.Mutate(func() { - stringer.l.EachValue(func(v interface{}) { - fn(v.(string)) - }) - }) -} - -func (stringer *stringer) Fetch(k interface{}) string { - var s string - stringer.Mutate(func() { - var v = stringer.l.Fetch(k) - if v != nil { - s = v.(string) - } - }) - return s -} - -func (stringer *stringer) FetchSome(k ...interface{}) []string { - var s []string - stringer.Mutate(func() { - var x interface{} - for _, x = range k { - var v = stringer.l.Fetch(x) - if v == nil { - continue - } - s = append(s, v.(string)) - } - }) - return s -} - -func (stringer *stringer) FetchSomeLength(k ...interface{}) ([]string, int) { - var s = stringer.FetchSome(k...) - var l = stringer.Len() - return s, l -} - -func (stringer *stringer) Get(k interface{}) (string, bool) { - var s string - var v interface{} - var ok bool - stringer.Mutate(func() { - v, ok = stringer.l.Get(k) - if v != nil { - s = v.(string) - } - }) - return s, ok -} - -func (stringer *stringer) GetLength(k interface{}) (string, int, bool) { - var s, ok = stringer.Get(k) - var l = stringer.Len() - return s, l, ok -} - -func (stringer *stringer) Has(k interface{}) bool { - var ok bool - stringer.Mutate(func() { - ok = stringer.l.Has(k) - }) - return ok -} - -func (stringer *stringer) HasSome(k ...interface{}) bool { - var ok bool - stringer.Mutate(func() { - ok = stringer.l.HasSome(k...) - }) - return ok -} - -func (stringer *stringer) Keys() []interface{} { - var s []interface{} - stringer.Mutate(func() { - s = stringer.l.Keys() - }) - return s -} - -func (stringer *stringer) Len() int { - var l int - stringer.Mutate(func() { - l = stringer.l.Len() - }) - return l -} - -func (stringer *stringer) Map(fn func(k interface{}, s string) string) Stringer { - return stringer.Mutate(func() { - stringer.l.Map(func(k, v interface{}) interface{} { - return fn(k, v.(string)) - }) - }) -} - -func (stringer *stringer) MapBreak(fn func(interface{}, string) (string, bool)) Stringer { - return stringer.Mutate(func() { - stringer.l.MapBreak(func(k, v interface{}) (interface{}, bool) { - return fn(k, v.(string)) - }) - }) -} - -func (stringer *stringer) MapOK(fn func(interface{}, string) (string, bool)) Stringer { - return stringer.Mutate(func() { - stringer.l.MapOK(func(k, v interface{}) (interface{}, bool) { - return fn(k, v.(string)) - }) - }) -} - -func (stringer *stringer) Mutate(fn func()) Stringer { - stringer.mu.Lock() - fn() - stringer.mu.Unlock() - return stringer -} - -func (stringer *stringer) Not(k interface{}) bool { - var ok bool - stringer.Mutate(func() { - ok = stringer.l.Not(k) - }) - return ok -} - -func (stringer *stringer) NotSome(k ...interface{}) bool { - var ok bool - stringer.Mutate(func() { - ok = stringer.l.NotSome(k...) - }) - return ok -} - -func (stringer *stringer) Values() []string { - var s = []string{} - stringer.Mutate(func() { - stringer.EachValue(func(v string) { - s = append(s, v) - }) - }) - return s -} diff --git a/string_test.go b/string_test.go deleted file mode 100644 index f58549f..0000000 --- a/string_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package lex_test - -import ( - "fmt" - "sync" - "testing" - - "github.com/gellel/lex" -) - -var ( - s lex.Stringer -) - -func TestStringer(t *testing.T) { - var ( - ok bool - ) - s = lex.NewStringer() - ok = s != nil - if !ok { - t.Fatalf("(lex.NewStringer() lex.Stringer) == nil") - } - var ( - k = 1 - v string - x string - ) - ok = s.AddOK(k, v) - if !ok { - t.Fatalf("(lex.Stringer.AddOK(interface{}, string) bool) != true") - } - x, ok = s.Get(k) - if !ok { - t.Fatalf("(lex.Stringer.Get(interface{}) (string, bool) != (_, true)") - } - ok = v == x - if !ok { - t.Fatalf("(lex.Stringer.Get(interface{}) (string, bool) != (string, _)") - } - ok = s.DelOK(k) - if !ok { - t.Fatalf("(lex.Stringer.DelOK(interface{}) (bool) != true") - } -} - -func TestStringerConcurrency(t *testing.T) { - var ( - ok bool - size = 20 - wg sync.WaitGroup - ) - wg.Add(1) - go func() { - defer wg.Done() - for i := 0; i < size/2; i++ { - s.AddLength(i, fmt.Sprintf("%d", i)) - } - }() - wg.Add(1) - go func() { - defer wg.Done() - for i := size / 2; i < size; i++ { - s.AddLength(i, fmt.Sprintf("%d", i)) - } - }() - wg.Wait() - ok = s.Len() == size - if !ok { - t.Fatalf("(lex.Stringer.Len() (int) != int") - } -}