{"id":17537746,"url":"https://github.com/lthibault/treap","last_synced_at":"2025-04-23T21:08:02.096Z","repository":{"id":87128276,"uuid":"257299001","full_name":"lthibault/treap","owner":"lthibault","description":"A thread-safe, persistent Treap (tree + heap) for ordered key-value mapping and priority sorting.","archived":false,"fork":false,"pushed_at":"2021-12-04T04:34:59.000Z","size":82,"stargazers_count":28,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-23T21:07:53.326Z","etag":null,"topics":["concurrency","concurrent","datastructure","golang","heap","persistent","persistent-data-structure","threadsafe","treap","tree"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lthibault.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-20T14:02:21.000Z","updated_at":"2023-10-27T14:12:51.000Z","dependencies_parsed_at":null,"dependency_job_id":"2a94393c-da76-410d-bb88-2636a7f98f32","html_url":"https://github.com/lthibault/treap","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lthibault%2Ftreap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lthibault%2Ftreap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lthibault%2Ftreap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lthibault%2Ftreap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lthibault","download_url":"https://codeload.github.com/lthibault/treap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250514785,"owners_count":21443209,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["concurrency","concurrent","datastructure","golang","heap","persistent","persistent-data-structure","threadsafe","treap","tree"],"created_at":"2024-10-20T20:42:39.861Z","updated_at":"2025-04-23T21:08:02.080Z","avatar_url":"https://github.com/lthibault.png","language":"Go","readme":"# Treap\n\nTread-safe, persistent treaps in pure Go.\n\n![tests](https://github.com/lthibault/treap/workflows/tests/badge.svg?branch=master)\n[![Godoc Reference](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/lthibault/treap)\n[![Go Report Card](https://goreportcard.com/badge/github.com/SentimensRG/ctx?style=flat-square)](https://goreportcard.com/report/github.com/lthibault/treap)\n\n## Installation\n\n```bash\ngo get github.com/lthibault/treap\n```\n\nTreap is tested using go 1.14 and later, but is likely to work with earlier versions.\n\n## Why Treaps?\n\nMost developers are familiar with maps and heaps.\n\n- Maps provide keyed lookups.  Some even sort entries by key.\n- Heaps provide priority-ordering, with fast inserts and pops.\n\nBut what if you need **both?**  And what if it needs to be both **thread-safe**, _and_\nnon-blocking?\n\nEnter the _Immutable Treap_.\n\nImmutable treaps are persistent datastructures that provide:\n\n- Keyed lookups (like maps)\n- Priority ordering, pops and weighted inserts (like heaps)\n- Wait-free concurrency through immutability\n- Memory-efficiency through structural sharing\n- O(log n) time complexity for all operations\n\nWhen used in conjunction with `atomic.CompareAndSwapPointer`, it is possible to read\nfrom a treap without ever blocking -- even in the presence of concurrent writers!  Your\ntypical CAS-loop will look like this:\n\n```go\ntype Foo struct {\n    ptr unsafe.Pointer  // a *treap.Node\n}\n\nfunc (f *Foo) AddItem(key string, value, weight int) {\n    for {\n        old := (*treap.Node)(atomic.LoadPointer(\u0026f.ptr))\n        new, _ := handle.Upsert(old, key, value, weight)\n\n        // attempt CAS\n        if atomic.CompareAndSwapPointer(\u0026f.ptr,\n            unsafe.Pointer(old),\n            unsafe.Pointer(new),\n        ) {\n            break  // value successfully set; we're done\n        }\n    }\n}\n```\n\nIn addition, this package features zero external dependencies and extensive test\ncoverage.\n\n## Usage\n\nThe treap data-structure is purely functional and immutable.  Methods like `Insert` and\n`Delete` return a **new** treap containing the desired modifications.\n\nA fully-runnable version of the following example can be found in `example_test.go`.\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n\n    \"github.com/lthibault/treap\"\n)\n\n// Treap operations are performed by a lightweight handle.  Usually, you'll create a\n// single global handle and share it between goroutines.  Handle's methods are thread-\n// safe.\n//\n// A handle is defined by it's comparison functions (type `treap.Comparator`).\nvar handle = treap.Handle{\n    // CompareKeys is used to store and receive mapped entries.  The comparator must be\n    // compatible with the Go type used for keys.  In this example, we'll use strings as\n    // keys.\n    CompareKeys: treap.StringComparator,\n\n    // CompareWeights is used to maintain priority-ordering of mapped entries, providing\n    // us with fast `Pop`, `Insert` and `SetWeight` operations.  You'll usually want\n    // to use a `treap.IntComparator` for weights, but you can use any comparison\n    // function you require.  Try it with `treap.TimeComparator`!\n    //\n    // Note that treaps are min-heaps by default, so `Pop` will always return the item\n    // with the _smallest_ weight.  You can easily switch to a max-heap by using\n    // `treap.MaxTreap`, if required.\n    CompareWeights: treap.IntComparator,\n}\n\nfunc main() {\n    // We define an empty root node.  Don't worry -- there's no initialization required!\n    var root *treap.Node\n\n    // We're going to insert each of these boxers into the treap, and observe how the\n    // treap treap provides us with a combination of map and heap semantics.\n    for _, boxer := range []struct{\n        FirstName, LastName string\n        Weight int\n    }{{\n        FirstName: \"Cassius\",\n        LastName: \"Clay\",\n        Weight: 210,\n    }, {\n        FirstName: \"Joe\",\n        LastName: \"Frazier\",\n        Weight: 215,\n    }, {\n        FirstName: \"Marcel\",\n        LastName: \"Cerdan\",\n        Weight: 154,\n    }, {\n        FirstName: \"Jake\",\n        LastName: \"LaMotta\",\n        Weight: 160,\n    }}{\n        // Again, the treap is a purely-functional, persistent data structure.  `Insert`\n        // returns a _new_ heap, which replaces `root` on each iteration.\n        //\n        // When used in conjunction with `atomic.CompareAndSwapPointer`, it is possible\n        // to read from a treap without ever blocking -- even in the presence of\n        // concurrent writers!\n        root, _ = handle.Insert(root, boxer.FirstName, boxer.LastName, boxer.Weight)\n    }\n\n    // Now that we've populated the treap, we can query it like an ordinary map.\n    lastn, _ := handle.Get(root, \"Cassius\")\n    fmt.Printf(\"Cassius %s\\n\", lastn)  // prints:  \"Cassius Clay\"\n\n    // Treaps also behave like binary heaps.  Let's start by peeking at the first value\n    // in the resulting priority queue.  Remember:  this is a min-heap by default.\n    fmt.Printf(\"%s %s, %d lbs\\n\", root.Key, root.Value, root.Weight)\n\n    // Woah, that was easy!  Now let's Pop that first value off of the heap.\n    // Remember:  this is an immutable data-structure, so `Pop` doesn't actually mutate\n    // any state!\n    lastn, _ = handle.Pop(root)\n    fmt.Printf(\"Marcel %s\\n\", lastn)  // prints:  \"Marcel Cerdan\"\n\n    // Jake LaMotta moved up to the heavyweight class late in his career.  Let's made an\n    // adjustment to his weight.\n    root, _ = handle.SetWeight(root, \"Jake\", 205)\n\n    // Let's list our boxers in ascending order of weight.  You may have noticed\n    // there's no `PopNode` method on `treap.Handler`.  This is not a mistake!  A `Pop`\n    // is just a merge on the root node's subtrees.  Check it out:\n    for n := root; n != nil; {\n        fmt.Printf(\"%s %s: %d\\n\", n.Key, n.Value, n.Weight)\n        n = handle.Merge(n.Left, n.Right)\n    }\n\n    // Lastly, we can iterate through the treap in key-order (smallest to largest).\n    // To do this, we use an iterator.  Contrary to treaps, iterators are stateful and\n    // mutable!  As such, they are NOT thread-safe.  However, multiple concurrent\n    // iterators can traverse the same treap safely.\n    for iterator := handle.Iter(root); iterator.Node != nil; iterator.Next(); {\n        fmt.Printf(\"%s %s: %d\\n\", iterator.Key, iterator.Value, iterator.Weight)\n    }\n}\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flthibault%2Ftreap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flthibault%2Ftreap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flthibault%2Ftreap/lists"}