https://github.com/neurlang/table
Package table implements a memory efficient in-memory multicolumn string table aka multimap/bimap in golang
https://github.com/neurlang/table
bimap go golang multimap string
Last synced: 5 months ago
JSON representation
Package table implements a memory efficient in-memory multicolumn string table aka multimap/bimap in golang
- Host: GitHub
- URL: https://github.com/neurlang/table
- Owner: neurlang
- License: mit
- Created: 2025-03-02T10:53:49.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2025-11-23T12:45:50.000Z (7 months ago)
- Last Synced: 2025-11-23T14:21:53.716Z (7 months ago)
- Topics: bimap, go, golang, multimap, string
- Language: Go
- Homepage:
- Size: 85.9 KB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# 📚 `table`
**A blazing-fast, memory-efficient multicolumn string table (multimap/bimap) for Go.**
Store billions of rows in RAM, filter by multiple `(column → value)` clauses, and perform high-performance queries with optional “holes” for instant deletion performance.
---
## ✨ Features
✅ In-memory multicolumn string storage
✅ Supports duplicate rows, multi-key lookups, and range queries
✅ Explicit *holes* model for cheap deletes
✅ Manual compaction for full reuse of space
✅ Tiny memory footprint with optional quaternary filters
✅ Zero external dependencies except for `quaternary`
---
## 🚀 Quick Example
```go
package main
import (
"fmt"
"github.com/neurlang/table"
)
func main() {
var t table.Table
// Insert rows
data := [][]string{
{"play", "pièce", "obra"},
{"cup", "tasse", "taza"},
{"bank", "banque", "banco"},
{"coin", "pièce", "moneda"},
{"boat", "bateau", "barco"},
{"cup", "verre", "copa"},
{"earth", "terre", "tierra"},
{"land", "terre", "tierra"},
{"soap", "savon", "jabón"},
{"ice", "glace", "hielo"},
{"book", "livre", "libro"},
{"room", "pièce", "habitación"},
{"cup", "coupe", "copa"},
{"glass", "verre", "copa"},
{"pie", "gâteau", "tarta"},
}
t.Insert(data)
t.Compact()
// Query
fmt.Println("Cups:", t.GetAll(0, "cup"))
fmt.Println("terre:", t.GetAll(1, "terre"))
fmt.Println("copa:", t.GetAll(2, "copa"))
// Insert more
t.Insert([][]string{
{"bench", "banc", "banco"},
{"faucet", "robinet", "llave"},
{"key", "clé", "llave"},
})
t.Compact()
fmt.Println("banco:", t.GetAll(2, "banco"))
fmt.Println("llave:", t.GetAll(2, "llave"))
// Delete by value
t.Remove(1, "verre")
fmt.Println("Cups after delete:", t.GetAll(0, "cup"))
}
```
---
## ⚙️ API Overview
| Method | Description | Direction |
| ----------------------- | ------------------------------------------------------------------------------------- | --------- |
| `Insert(rows)` | Insert rows. Holes are ignored. | Write |
| `InsertHoles(rows)` | Insert rows as-is, including holes. | Write |
| `Remove(col, val)` | Delete all rows where `col` equals `val`. Leaves holes for speed. | Write |
| `DeleteBy(filters)` | Delete rows matching every `(col → val)`. Panics if filter is nil or empty. | Write |
| `Get(col, val)` | Get one arbitrary row where `col` equals `val`. | Read |
| `GetAll(col, val)` | Get all rows where `col` equals `val`. | Read |
| `QueryBy(filters)` | Find all rows matching every `(col → val)`. Skips holes. Panics if filters nil/empty. | Read |
| `QueryByHoles(filters)` | Same as `QueryBy` but includes holes. | Read |
| `All()` | Return all rows, skipping holes. | Read |
| `AllHoles()` | Return all rows including holes. | Read |
| `Compact()` | Physically remove holes to reclaim RAM, rebuilds the quaternary indices. | Write |
| `Count(col, val)` | Count number of times `val` appears in `col`. | Read |
---
## 🧹 Holes & Compaction
* **What’s a “hole”?**
Deletions just nullify slots for speed. Rows with holes still take space.
* **When to `Compact()`?**
After bulk inserts or optionally after heavy deletes. Frequent compactions may hurt performance.
* **Do I have to handle holes?**
Use `QueryBy` and `All()` to skip holes. Use `QueryByHoles` and `AllHoles()` for raw physical view.
---
## ⚡️ Best Practices
* 🗝️ Use a consistent schema: same column count per row.
* ⚠️ Never pass nil or empty filters to `QueryBy` or `DeleteBy` — they will panic!
* 🧹 Run `Compact()` wisely — it’s not automatic.
* 🚀 You can store millions of rows easily, but monitor RAM if you use `InsertHoles` a lot.
* 🐛 Note: `GetAll` may return holes in some versions. Use `QueryBy` if you need strict correctness.
---
## 📏 Limitations
* No schema enforcement: you must keep row length consistent yourself.
* No transactional batch operations.
* No OR filter logic — `QueryBy` is always AND.
* Panics on nil/empty filters — not error-safe by default.
* It’s pure in-memory: no persistence, snapshot, or on-disk mode yet.
* No mutex. Use mutex if threading, based on API call direction.
---
## 📚 Documentation
Full API reference: [pkg.go.dev](https://pkg.go.dev/github.com/neurlang/table)
Issues and improvements: [GitHub Issues](https://github.com/neurlang/table/issues)
---
## 🔑 License
MIT — do anything you want. Attribution appreciated.
---
## 🙌 Contributing
We welcome improvements!
File an issue for bug reports, feature requests, or performance tuning ideas.
Large-scale fuzz tests, schema enforcement, and auto-compaction PRs are especially welcome.
---
## 🏁 Example Output
```shell
[[cup tasse taza] [cup verre copa] [cup coupe copa]]
[[earth terre tierra] [land terre tierra]]
[[cup verre copa] [cup coupe copa] [glass verre copa]]
[[bank banque banco] [bench banc banco]]
[[faucet robinet llave] [key clé llave]]
[[cup tasse taza] [cup coupe copa]]
```
---
## ❤️ Built for performance fanatics, by performance fanatics.