├── go.sum ├── go.mod ├── .gitignore ├── doc.go ├── Makefile ├── search.go ├── arithmetic.go ├── common.go ├── arithmetic_test.go ├── .github └── workflows │ └── lockfree.yml ├── README.md ├── ringbuffer_test.go ├── LICENSE ├── stack.go ├── search_test.go ├── ringbuffer.go ├── stack_test.go ├── queue_test.go ├── queue.go ├── skiplist_test.go ├── TODO.md ├── rbtree_test.go ├── skiplist.go └── rbtree.go /go.sum: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module golang.design/x/lockfree 2 | 3 | go 1.13 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | *.html -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | // Package lockfree offers lock-free utilities 6 | // 7 | // Note that this package is under development and not for production use. 8 | package lockfree // import "golang.design/x/lockfree" 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 The golang.design Initiative authors. 2 | # All rights reserved. Use of this source code is governed 3 | # by a MIT license that can be found in the LICENSE file. 4 | 5 | COUNT := $(if $(COUNT),$(COUNT),1) 6 | 7 | all: 8 | @echo "Usage:" 9 | @echo " - make tests: run all tests with race detection" 10 | @echo " - make bench count=: run all benches with given count" 11 | 12 | tests: 13 | go test -race -cover -coverprofile=cover.test -v . 14 | go tool cover -html=cover.test -o cover.html 15 | 16 | bench: 17 | go test -bench=. -benchmem -count=$(COUNT) -------------------------------------------------------------------------------- /search.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree 6 | 7 | // BinarySearch implements binary search algorithm. 8 | // It returns the index if element x is found in arr 9 | // Otherwise it returns -1. 10 | func BinarySearch(arr []interface{}, x interface{}, less Less) int { 11 | l, r := 0, len(arr)-1 12 | for l <= r { 13 | mid := (l + r) / 2 14 | if less(arr[mid], x) { 15 | l = mid + 1 16 | } else if less(x, arr[mid]) { 17 | r = mid - 1 18 | } else { 19 | return mid 20 | } 21 | } 22 | return -1 23 | } 24 | -------------------------------------------------------------------------------- /arithmetic.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree 6 | 7 | import ( 8 | "math" 9 | "sync/atomic" 10 | "unsafe" 11 | ) 12 | 13 | // AddFloat64 add delta to given address atomically 14 | func AddFloat64(addr *float64, delta float64) (new float64) { 15 | var old float64 16 | for { 17 | old = math.Float64frombits(atomic.LoadUint64((*uint64)(unsafe.Pointer(addr)))) 18 | if atomic.CompareAndSwapUint64((*uint64)(unsafe.Pointer(addr)), 19 | math.Float64bits(old), math.Float64bits(old+delta)) { 20 | break 21 | } 22 | } 23 | return 24 | } 25 | -------------------------------------------------------------------------------- /common.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree 6 | 7 | import ( 8 | "sync/atomic" 9 | "unsafe" 10 | ) 11 | 12 | // Less defines a function that compares the order of a and b. 13 | // Returns true if a < b 14 | type Less func(a, b interface{}) bool 15 | 16 | type directItem struct { 17 | next unsafe.Pointer 18 | v interface{} 19 | } 20 | 21 | func loaditem(p *unsafe.Pointer) *directItem { 22 | return (*directItem)(atomic.LoadPointer(p)) 23 | } 24 | func casitem(p *unsafe.Pointer, old, new *directItem) bool { 25 | return atomic.CompareAndSwapPointer(p, unsafe.Pointer(old), unsafe.Pointer(new)) 26 | } 27 | -------------------------------------------------------------------------------- /arithmetic_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree_test 6 | 7 | import ( 8 | "sync" 9 | "testing" 10 | 11 | "golang.design/x/lockfree" 12 | ) 13 | 14 | func TestAddFloat64(t *testing.T) { 15 | vs := []float64{} 16 | for i := 1; i <= 10; i++ { 17 | vs = append(vs, float64(i)) 18 | } 19 | 20 | var sum float64 21 | wg := sync.WaitGroup{} 22 | wg.Add(10) 23 | for _, v := range vs { 24 | lv := v 25 | go func() { 26 | lockfree.AddFloat64(&sum, lv) 27 | wg.Done() 28 | }() 29 | } 30 | wg.Wait() 31 | 32 | if sum != float64(55) { 33 | t.Fatalf("AddFloat64 wrong, expected 55, got %v", sum) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.github/workflows/lockfree.yml: -------------------------------------------------------------------------------- 1 | name: lockfree 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | name: Build 13 | runs-on: ubuntu-latest 14 | steps: 15 | 16 | - name: Set up Go 1.x 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: ^1.13 20 | id: go 21 | 22 | - name: Check out code into the Go module directory 23 | uses: actions/checkout@v2 24 | 25 | - name: Get dependencies 26 | run: | 27 | go get -v -t -d ./... 28 | 29 | - name: Test 30 | run: | 31 | go test -v -race -timeout 60m -coverprofile=coverage.txt -covermode=atomic ./... 32 | 33 | - name: Upload coverage profile 34 | uses: codecov/codecov-action@v1 35 | with: 36 | token: ${{secrets.CODECOV_TOKEN}} 37 | file: coverage.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lockfree 2 | 3 | [![PkgGoDev](https://pkg.go.dev/badge/golang.design/x/lockfree)](https://pkg.go.dev/golang.design/x/lockfree) [![Go Report Card](https://goreportcard.com/badge/golang.design/x/lockfree)](https://goreportcard.com/report/golang.design/x/lockfree) 4 | ![lockfree](https://github.com/golang-design/lockfree/workflows/lockfree/badge.svg?branch=master) 5 | [![codecov](https://codecov.io/gh/golang-design/lockfree/branch/master/graph/badge.svg)](https://codecov.io/gh/golang-design/lockfree) 6 | 7 | 8 | Package lock-free offers lock-free utilities in Go. 9 | 10 | ``` 11 | import "golang.design/x/lockfree" 12 | ``` 13 | 14 | ## Contributing 15 | 16 | We would love to have your experiences. Feel free to [submit an issue](https://golang.design/x/lockfree/issues/new) for requesting a new implementation or bug report. 17 | 18 | ## License 19 | 20 | MIT © [Changkun Ou](https://changkun.de) 21 | -------------------------------------------------------------------------------- /ringbuffer_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree_test 6 | 7 | import ( 8 | "reflect" 9 | "testing" 10 | 11 | "golang.design/x/lockfree" 12 | ) 13 | 14 | func TestRingBuffer(t *testing.T) { 15 | rb := lockfree.NewRingBuffer(10) 16 | 17 | for i := 0; i < 20; i++ { 18 | ok := rb.Put(i) 19 | if i < 10 && !ok { 20 | t.Errorf("put failed, %v:%v", i, ok) 21 | } 22 | if i > 9 && ok { 23 | t.Errorf("put failed, %v:%v", i, ok) 24 | } 25 | } 26 | v := rb.LookAll() 27 | want := []interface{}{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 28 | if !reflect.DeepEqual(v, want) { 29 | t.Errorf("not equal: %v", v) 30 | } 31 | 32 | for i := 0; i < 5; i++ { 33 | v := rb.Get() 34 | if v != i { 35 | t.Errorf("get failed, %v:%v", v, i) 36 | } 37 | } 38 | 39 | v = rb.LookAll() 40 | want = []interface{}{5, 6, 7, 8, 9} 41 | if !reflect.DeepEqual(v, want) { 42 | t.Errorf("not equal") 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2020 The golang.design Authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /stack.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree 6 | 7 | import ( 8 | "sync/atomic" 9 | "unsafe" 10 | ) 11 | 12 | // Stack implements lock-free freelist based stack. 13 | type Stack struct { 14 | top unsafe.Pointer 15 | len uint64 16 | } 17 | 18 | // NewStack creates a new lock-free queue. 19 | func NewStack() *Stack { 20 | return &Stack{} 21 | } 22 | 23 | // Pop pops value from the top of the stack. 24 | func (s *Stack) Pop() interface{} { 25 | var top, next unsafe.Pointer 26 | var item *directItem 27 | for { 28 | top = atomic.LoadPointer(&s.top) 29 | if top == nil { 30 | return nil 31 | } 32 | item = (*directItem)(top) 33 | next = atomic.LoadPointer(&item.next) 34 | if atomic.CompareAndSwapPointer(&s.top, top, next) { 35 | atomic.AddUint64(&s.len, ^uint64(0)) 36 | return item.v 37 | } 38 | } 39 | } 40 | 41 | // Push pushes a value on top of the stack. 42 | func (s *Stack) Push(v interface{}) { 43 | item := directItem{v: v} 44 | var top unsafe.Pointer 45 | for { 46 | top = atomic.LoadPointer(&s.top) 47 | item.next = top 48 | if atomic.CompareAndSwapPointer(&s.top, top, unsafe.Pointer(&item)) { 49 | atomic.AddUint64(&s.len, 1) 50 | return 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /search_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "golang.design/x/lockfree" 11 | ) 12 | 13 | func TestBinarySearch(t *testing.T) { 14 | tests := []struct { 15 | input []interface{} 16 | x interface{} 17 | less lockfree.Less 18 | want int 19 | }{ 20 | { 21 | input: []interface{}{1, 2, 3, 4, 5, 6, 7}, 22 | x: 6, 23 | less: func(a, b interface{}) bool { 24 | if a.(int) < b.(int) { 25 | return true 26 | } 27 | return false 28 | }, 29 | want: 5, 30 | }, 31 | { 32 | input: []interface{}{1, 2, 3, 4, 5, 6, 7}, 33 | x: 2, 34 | less: func(a, b interface{}) bool { 35 | if a.(int) < b.(int) { 36 | return true 37 | } 38 | return false 39 | }, 40 | want: 1, 41 | }, 42 | { 43 | input: []interface{}{}, 44 | x: 2, 45 | less: func(a, b interface{}) bool { 46 | if a.(int) < b.(int) { 47 | return true 48 | } 49 | return false 50 | }, 51 | want: -1, 52 | }, 53 | } 54 | 55 | for _, tt := range tests { 56 | r := lockfree.BinarySearch(tt.input, tt.x, tt.less) 57 | if r != tt.want { 58 | t.Fatalf("BinarySearch %v of %v: want %v, got %v", tt.x, tt.input, tt.want, r) 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ringbuffer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree 6 | 7 | // RingBuffer implements ring buffer queue 8 | type RingBuffer struct { 9 | buf []interface{} 10 | head, tail int 11 | len, cap int 12 | } 13 | 14 | // NewRingBuffer creates a ring buffer with given capacity 15 | func NewRingBuffer(capacity int) *RingBuffer { 16 | return &RingBuffer{ 17 | buf: make([]interface{}, capacity), 18 | cap: capacity, 19 | } 20 | } 21 | 22 | // Put puts x into ring buffer 23 | func (rb *RingBuffer) Put(x interface{}) (ok bool) { 24 | if rb.len == rb.cap { 25 | return 26 | } 27 | 28 | rb.buf[rb.tail] = x 29 | rb.tail++ 30 | if rb.tail > rb.cap-1 { 31 | rb.tail = 0 32 | } 33 | rb.len++ 34 | ok = true 35 | return 36 | } 37 | 38 | // Get gets the first element from queue 39 | func (rb *RingBuffer) Get() (x interface{}) { 40 | x = rb.buf[rb.head] 41 | rb.head++ 42 | if rb.head > rb.cap-1 { 43 | rb.head = 0 44 | } 45 | rb.len-- 46 | return 47 | } 48 | 49 | // IsFull checks if the ring buffer is full 50 | func (rb *RingBuffer) IsFull() bool { 51 | return rb.len == rb.cap 52 | } 53 | 54 | // LookAll reads all elements from ring buffer 55 | // this method doesn't consume all elements 56 | func (rb *RingBuffer) LookAll() []interface{} { 57 | all := make([]interface{}, rb.len) 58 | j := 0 59 | for i := rb.head; ; i++ { 60 | if i > rb.cap-1 { 61 | i = 0 62 | } 63 | if i == rb.tail && j > 0 { 64 | break 65 | } 66 | all[j] = rb.buf[i] 67 | j++ 68 | } 69 | return all 70 | } 71 | -------------------------------------------------------------------------------- /stack_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree_test 6 | 7 | import ( 8 | "fmt" 9 | "math/rand" 10 | "sync" 11 | "sync/atomic" 12 | "testing" 13 | 14 | "golang.design/x/lockfree" 15 | ) 16 | 17 | func TestStackPopEmpty(t *testing.T) { 18 | s := lockfree.NewStack() 19 | if s.Pop() != nil { 20 | t.Fatal("pop empty stack returns non-nil") 21 | } 22 | } 23 | 24 | func ExampleStack() { 25 | s := lockfree.NewStack() 26 | 27 | s.Push(1) 28 | s.Push(2) 29 | s.Push(3) 30 | 31 | fmt.Println(s.Pop()) 32 | fmt.Println(s.Pop()) 33 | fmt.Println(s.Pop()) 34 | 35 | // Output: 36 | // 3 37 | // 2 38 | // 1 39 | } 40 | 41 | type stackInterface interface { 42 | Push(interface{}) 43 | Pop() interface{} 44 | } 45 | 46 | type mutexStack struct { 47 | v []interface{} 48 | mu sync.Mutex 49 | } 50 | 51 | func newMutexStack() *mutexStack { 52 | return &mutexStack{v: make([]interface{}, 0)} 53 | } 54 | 55 | func (s *mutexStack) Push(v interface{}) { 56 | s.mu.Lock() 57 | s.v = append(s.v, v) 58 | s.mu.Unlock() 59 | } 60 | 61 | func (s *mutexStack) Pop() interface{} { 62 | s.mu.Lock() 63 | v := s.v[len(s.v)] 64 | s.v = s.v[:len(s.v)-1] 65 | s.mu.Unlock() 66 | return v 67 | } 68 | 69 | func BenchmarkStack(b *testing.B) { 70 | length := 1 << 12 71 | inputs := make([]int, length) 72 | for i := 0; i < length; i++ { 73 | inputs = append(inputs, rand.Int()) 74 | } 75 | s, ms := lockfree.NewStack(), newMutexStack() 76 | b.ResetTimer() 77 | for _, s := range [...]stackInterface{s, ms} { 78 | b.Run(fmt.Sprintf("%T", s), func(b *testing.B) { 79 | var c int64 80 | b.RunParallel(func(pb *testing.PB) { 81 | for pb.Next() { 82 | i := int(atomic.AddInt64(&c, 1)-1) % length 83 | v := inputs[i] 84 | if v >= 0 { 85 | s.Push(v) 86 | } else { 87 | s.Pop() 88 | } 89 | } 90 | }) 91 | }) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /queue_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree_test 6 | 7 | import ( 8 | "fmt" 9 | "math/rand" 10 | "sync" 11 | "sync/atomic" 12 | "testing" 13 | 14 | "golang.design/x/lockfree" 15 | ) 16 | 17 | func TestQueueDequeueEmpty(t *testing.T) { 18 | q := lockfree.NewQueue() 19 | if q.Dequeue() != nil { 20 | t.Fatalf("dequeue empty queue returns non-nil") 21 | } 22 | } 23 | 24 | func TestQueue_Length(t *testing.T) { 25 | q := lockfree.NewQueue() 26 | if q.Length() != 0 { 27 | t.Fatalf("empty queue has non-zero length") 28 | } 29 | 30 | q.Enqueue(1) 31 | if q.Length() != 1 { 32 | t.Fatalf("count of enqueue wrong, want %d, got %d.", 1, q.Length()) 33 | } 34 | 35 | q.Dequeue() 36 | if q.Length() != 0 { 37 | t.Fatalf("count of dequeue wrong, want %d, got %d", 0, q.Length()) 38 | } 39 | } 40 | 41 | func ExampleQueue() { 42 | q := lockfree.NewQueue() 43 | 44 | q.Enqueue("1st item") 45 | q.Enqueue("2nd item") 46 | q.Enqueue("3rd item") 47 | 48 | fmt.Println(q.Dequeue()) 49 | fmt.Println(q.Dequeue()) 50 | fmt.Println(q.Dequeue()) 51 | 52 | // Output: 53 | // 1st item 54 | // 2nd item 55 | // 3rd item 56 | } 57 | 58 | type queueInterface interface { 59 | Enqueue(interface{}) 60 | Dequeue() interface{} 61 | } 62 | 63 | type mutexQueue struct { 64 | v []interface{} 65 | mu sync.Mutex 66 | } 67 | 68 | func newMutexQueue() *mutexQueue { 69 | return &mutexQueue{v: make([]interface{}, 0)} 70 | } 71 | 72 | func (q *mutexQueue) Enqueue(v interface{}) { 73 | q.mu.Lock() 74 | q.v = append(q.v, v) 75 | q.mu.Unlock() 76 | } 77 | 78 | func (q *mutexQueue) Dequeue() interface{} { 79 | q.mu.Lock() 80 | if len(q.v) == 0 { 81 | q.mu.Unlock() 82 | return nil 83 | } 84 | v := q.v[0] 85 | q.v = q.v[1:] 86 | q.mu.Unlock() 87 | return v 88 | } 89 | 90 | func BenchmarkQueue(b *testing.B) { 91 | length := 1 << 12 92 | inputs := make([]int, length) 93 | for i := 0; i < length; i++ { 94 | inputs = append(inputs, rand.Int()) 95 | } 96 | q, mq := lockfree.NewQueue(), newMutexQueue() 97 | b.ResetTimer() 98 | 99 | for _, q := range [...]queueInterface{q, mq} { 100 | b.Run(fmt.Sprintf("%T", q), func(b *testing.B) { 101 | var c int64 102 | b.RunParallel(func(pb *testing.PB) { 103 | for pb.Next() { 104 | i := int(atomic.AddInt64(&c, 1)-1) % length 105 | v := inputs[i] 106 | if v >= 0 { 107 | q.Enqueue(v) 108 | } else { 109 | q.Dequeue() 110 | } 111 | } 112 | }) 113 | }) 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /queue.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree 6 | 7 | import ( 8 | "sync" 9 | "sync/atomic" 10 | "unsafe" 11 | ) 12 | 13 | // Queue implements lock-free FIFO freelist based queue. 14 | // ref: https://dl.acm.org/citation.cfm?doid=248052.248106 15 | type Queue struct { 16 | head unsafe.Pointer 17 | tail unsafe.Pointer 18 | len uint64 19 | pool sync.Pool 20 | } 21 | 22 | // NewQueue creates a new lock-free queue. 23 | func NewQueue() *Queue { 24 | head := directItem{next: nil, v: nil} // allocate a free item 25 | return &Queue{ 26 | tail: unsafe.Pointer(&head), // both head and tail points 27 | head: unsafe.Pointer(&head), // to the free item 28 | pool: sync.Pool{ 29 | New: func() interface{} { 30 | return &directItem{} 31 | }, 32 | }, 33 | } 34 | } 35 | 36 | // Enqueue puts the given value v at the tail of the queue. 37 | func (q *Queue) Enqueue(v interface{}) { 38 | i := q.pool.Get().(*directItem) 39 | i.next = nil 40 | i.v = v 41 | 42 | var last, lastnext *directItem 43 | for { 44 | last = loaditem(&q.tail) 45 | lastnext = loaditem(&last.next) 46 | if loaditem(&q.tail) == last { // are tail and next consistent? 47 | if lastnext == nil { // was tail pointing to the last node? 48 | if casitem(&last.next, lastnext, i) { // try to link item at the end of linked list 49 | casitem(&q.tail, last, i) // enqueue is done. try swing tail to the inserted node 50 | atomic.AddUint64(&q.len, 1) 51 | return 52 | } 53 | } else { // tail was not pointing to the last node 54 | casitem(&q.tail, last, lastnext) // try swing tail to the next node 55 | } 56 | } 57 | } 58 | } 59 | 60 | // Dequeue removes and returns the value at the head of the queue. 61 | // It returns nil if the queue is empty. 62 | func (q *Queue) Dequeue() interface{} { 63 | var first, last, firstnext *directItem 64 | for { 65 | first = loaditem(&q.head) 66 | last = loaditem(&q.tail) 67 | firstnext = loaditem(&first.next) 68 | if first == loaditem(&q.head) { // are head, tail and next consistent? 69 | if first == last { // is queue empty? 70 | if firstnext == nil { // queue is empty, couldn't dequeue 71 | return nil 72 | } 73 | casitem(&q.tail, last, firstnext) // tail is falling behind, try to advance it 74 | } else { // read value before cas, otherwise another dequeue might free the next node 75 | v := firstnext.v 76 | if casitem(&q.head, first, firstnext) { // try to swing head to the next node 77 | atomic.AddUint64(&q.len, ^uint64(0)) 78 | q.pool.Put(first) 79 | return v // queue was not empty and dequeue finished. 80 | } 81 | } 82 | } 83 | } 84 | } 85 | 86 | // Length returns the length of the queue. 87 | func (q *Queue) Length() uint64 { 88 | return atomic.LoadUint64(&q.len) 89 | } 90 | -------------------------------------------------------------------------------- /skiplist_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "golang.design/x/lockfree" 11 | ) 12 | 13 | func newSkipList() *lockfree.SkipList { 14 | return lockfree.NewSkipList(func(a, b interface{}) bool { 15 | if a.(int) < b.(int) { 16 | return true 17 | } 18 | return false 19 | }) 20 | } 21 | 22 | func TestNewSkipList(t *testing.T) { 23 | if newSkipList() == nil { 24 | t.Fatalf("%v: got nil", t.Name()) 25 | } 26 | } 27 | 28 | func TestSkipList_Len(t *testing.T) { 29 | sl := newSkipList() 30 | if sl == nil { 31 | t.Fatalf("%v: got nil", t.Name()) 32 | } 33 | 34 | if got := sl.Len(); got != 0 { 35 | t.Fatalf("Len: got %d, want %d", got, 0) 36 | } 37 | 38 | for i := 0; i < 10000; i++ { 39 | sl.Set(i, i) 40 | } 41 | 42 | if got := sl.Len(); got != 10000 { 43 | t.Fatalf("Len: got %d, want %d", got, 10000) 44 | } 45 | } 46 | 47 | func TestSkipList_GetFail(t *testing.T) { 48 | sl := newSkipList() 49 | if sl == nil { 50 | t.Fatalf("%v: got nil", t.Name()) 51 | } 52 | 53 | v, ok := sl.Get(-1) 54 | if ok { 55 | t.Fatalf("%v: suppose to fail, but got: %v, %v", t.Name(), v, ok) 56 | } 57 | } 58 | 59 | func TestSkipList_GetSuccess(t *testing.T) { 60 | sl := newSkipList() 61 | if sl == nil { 62 | t.Fatalf("%v: got nil", t.Name()) 63 | } 64 | 65 | sl.Set(1, 2) 66 | if got, ok := sl.Get(1); got != 2 || ok != true { 67 | t.Fatalf("got %v, %v want %v, %v", got, ok, 2, true) 68 | } 69 | 70 | sl.Set(1, 3) 71 | if got, ok := sl.Get(1); got != 3 || ok != true { 72 | t.Fatalf("got %v, %v want %v, %v", got, ok, 3, true) 73 | } 74 | } 75 | 76 | func TestSkipList_Search(t *testing.T) { 77 | sl := newSkipList() 78 | if sl == nil { 79 | t.Fatalf("%v: got nil", t.Name()) 80 | } 81 | 82 | if ok := sl.Search(1); ok { 83 | t.Fatalf("got %v want %v", ok, false) 84 | } 85 | 86 | sl.Set(1, 2) 87 | 88 | if got := sl.Len(); got != 1 { 89 | t.Fatalf("Len: got %d, want %d", got, 1) 90 | } 91 | 92 | if ok := sl.Search(1); !ok { 93 | t.Fatalf("got %v want %v", ok, true) 94 | } 95 | 96 | if v, ok := sl.Del(1); v != 2 || !ok { 97 | t.Fatalf("got %v,%v want %d", v, ok, 2) 98 | } 99 | 100 | if got := sl.Len(); got != 0 { 101 | t.Fatalf("Len: got %d, want %d", got, 1) 102 | } 103 | } 104 | 105 | func TestSkiplist_Del(t *testing.T) { 106 | sl := newSkipList() 107 | if sl == nil { 108 | t.Fatalf("%v: got nil", t.Name()) 109 | } 110 | 111 | for i := 0; i < 10; i++ { 112 | sl.Set(i, i) 113 | } 114 | 115 | for i := 0; i < 100; i++ { 116 | if _, ok := sl.Del(i); i > 10 && ok { 117 | t.Fatalf("%v: should fail, got: %v", t.Name(), ok) 118 | } 119 | } 120 | 121 | if got := sl.Len(); got != 0 { 122 | t.Fatalf("Len: got %d, want %d", got, 0) 123 | } 124 | } 125 | 126 | func TestSkipList_Range(t *testing.T) { 127 | sl := newSkipList() 128 | if sl == nil { 129 | t.Fatalf("%v: got nil", t.Name()) 130 | } 131 | 132 | for i := 0; i < 100; i++ { 133 | sl.Set(i, i) 134 | } 135 | 136 | current := 10 137 | sl.Range(10, 20, func(v interface{}) { 138 | if v != current { 139 | t.Fatalf("range failed, want %v, got %v", current, v) 140 | } 141 | current++ 142 | }) 143 | 144 | current = 90 145 | sl.Range(90, 120, func(v interface{}) { 146 | if v != current { 147 | t.Fatalf("range failed, want %v, got %v", current, v) 148 | } 149 | current++ 150 | }) 151 | if current != 99 { 152 | t.Fatalf("range out of bound, want %v, got %v", 99, current) 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO LIST 2 | 3 | ## List of Algorithms 4 | 5 | ### Linked List 6 | 7 | - [ ] Harris, Timothy L. "A pragmatic implementation of non-blocking linked-lists." International Symposium on Distributed Computing. Springer, Berlin, Heidelberg, 2001. [PDF](https://pdfs.semanticscholar.org/68a9/005a5ec10daece36ca5ecb9cad7be44770b1.pdf) 8 | - [ ] Sundell, Hakan, and Philippas Tsigas. "Lock-Free and Practical Deques and Doubly Linked Lists using Single-Word Compare-And-Swap." 2004 [PDF](https://pdfs.semanticscholar.org/8a68/f45bd32ed050a96faa24139ab71178258f13.pdf) 9 | - [ ] Valois, John D. "Lock-free linked lists using compare-and-swap." PODC. Vol. 95. 1995. [PDF](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.41.9506&rep=rep1&type=pdf) 10 | 11 | ### Queue 12 | 13 | - [x] Maged M. Michael and Michael L. Scott. 1996. Simple, fast, and practical non-blocking and blocking concurrent queue algorithms. In Proceedings of the fifteenth annual ACM symposium on Principles of distributed computing (PODC '96). ACM, New York, NY, USA, 267-275. [PDF](https://apps.dtic.mil/dtic/tr/fulltext/u2/a309412.pdf) 14 | - [ ] Shann, Chien-Hua, Ting-Lu Huang, and Cheng Chen. "A practical nonblocking queue algorithm using compare-and-swap." Proceedings Seventh International Conference on Parallel and Distributed Systems (Cat. No. PR00568). IEEE, 2000. [PDF](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.199.7928&rep=rep1&type=pdf) 15 | - [ ] Fober, Dominique, Yann Orlarey, and Stéphane Letz. "Optimised lock-free FIFO queue." (2001). [PDF](https://hal.archives-ouvertes.fr/hal-02158792/document) 16 | - [ ] Evequoz, Claude. "Non-blocking concurrent fifo queues with single word synchronization primitives." 2008 37th International Conference on Parallel Processing. IEEE, 2008. [PDF](https://www.liblfds.org/downloads/white%20papers/%5BQueue%5D%20-%20%5BEvequoz%5D%20-%20Non-Blocking%20Concurrent%20FIFO%20Queues%20With%20Single%20Word%20Synchroniation%20Primitives.pdf) 17 | 18 | ### Skip-list 19 | 20 | - [ ] Fomitchev, Mikhail, and Eric Ruppert. "Lock-free linked lists and skip lists." Proceedings of the twenty-third annual ACM symposium on Principles of distributed computing. ACM, 2004. [PDF](http://people.scs.carleton.ca/~edwardduong/PDF_files_of_relevant_papers/2004%20-%20Lock-free%20Linked%20List%20and%20Skip%20Lists.pdf) 21 | - [ ] Herlihy, Maurice, et al. "A provably correct scalable concurrent skip list." Conference On Principles of Distributed Systems (OPODIS). 2006. [PDF](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.170.719&rep=rep1&type=pdf) 22 | 23 | ### Stack 24 | 25 | - [ ] Hendler, Danny, Nir Shavit, and Lena Yerushalmi. "A scalable lock-free stack algorithm." Proceedings of the sixteenth annual ACM symposium on Parallelism in algorithms and architectures. ACM, 2004. [PDF](http://www.inf.ufsc.br/~dovicchi/pos-ed/pos/artigos/p206-hendler.pdf) 26 | 27 | ### Tree 28 | 29 | - [ ] Bronson, Nathan G., et al. "A practical concurrent binary search tree." ACM Sigplan Notices. Vol. 45. No. 5. ACM, 2010. [PDF](http://www.academia.edu/download/42135309/ppopp207-bronson.pdf) 30 | - [ ] Braginsky, Anastasia, and Erez Petrank. "A lock-free B+ tree." Proceedings of the twenty-fourth annual ACM symposium on Parallelism in algorithms and architectures. ACM, 2012. [PDF](http://www.cs.technion.ac.il/~erez/Papers/lfbtree-full.pdf) 31 | - [ ] Kim, Jong Ho, Helen Cameron, and Peter Graham. "Lock-free red-black trees using cas." Concurrency and Computation: Practice and experience (2006): 1-40. [PDF](https://www.cs.umanitoba.ca/~hacamero/Research/RBTreesKim.pdf) 32 | 33 | ### Hash 34 | 35 | - [ ] Michael, Maged M. "High performance dynamic lock-free hash tables and list-based sets." Proceedings of the fourteenth annual ACM symposium on Parallel algorithms and architectures. ACM, 2002. [PDF](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.114.5854&rep=rep1&type=pdf) -------------------------------------------------------------------------------- /rbtree_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree_test 6 | 7 | import ( 8 | "fmt" 9 | "math/rand" 10 | "testing" 11 | 12 | "golang.design/x/lockfree" 13 | ) 14 | 15 | type UniqueRand struct { 16 | generated map[int]bool 17 | } 18 | 19 | func (u *UniqueRand) Intn(n int) int { 20 | for { 21 | i := rand.Intn(n) 22 | if !u.generated[i] { 23 | u.generated[i] = true 24 | return i 25 | } 26 | } 27 | } 28 | 29 | func check(arr []int) { 30 | for i := range arr { 31 | for j := range arr { 32 | if i == j { 33 | continue 34 | } 35 | if arr[i] == arr[j] { 36 | panic(fmt.Sprintf("found equal: %d,%d, %d,%d", i, j, arr[i], arr[j])) 37 | } 38 | } 39 | } 40 | } 41 | 42 | func TestRBTreeWithEqual(t *testing.T) { 43 | tree := lockfree.NewRBTree(func(a, b interface{}) bool { 44 | if a.(int) < b.(int) { 45 | return true 46 | } 47 | return false 48 | }) 49 | if tree.Len() != 0 { 50 | t.Fatalf("want 0, got %d", tree.Len()) 51 | } 52 | tree.Del(0) 53 | if tree.Len() != 0 { 54 | t.Fatalf("want 0, got %d", tree.Len()) 55 | } 56 | 57 | for i := 0; i <= 5; i++ { 58 | tree.Put(i, i) 59 | } 60 | want := `RBTree 61 | │ ┌── 5 62 | │ ┌── 4 63 | │ ┌── 3 64 | │ │ └── 2 65 | └── 1 66 | └── 0 67 | ` 68 | if tree.String() != want { 69 | t.Fatal("unexpected: ", tree.String()) 70 | } 71 | 72 | tree.Put(1, 2) 73 | if tree.Len() != 6 { 74 | t.Fatalf("want 6, got %d", tree.Len()) 75 | } 76 | tree.Del(1) 77 | if tree.Len() != 5 { 78 | t.Fatalf("want 5, got %d", tree.Len()) 79 | } 80 | tree.Del(2) 81 | if tree.Len() != 4 { 82 | t.Fatalf("want 4, got %d", tree.Len()) 83 | } 84 | if tree.Get(10) != nil { 85 | t.Fatalf("want nil, got %d", tree.Get(10)) 86 | } 87 | 88 | } 89 | 90 | func TestRBTreeNoEqual(t *testing.T) { 91 | N := 1000 92 | for i := 0; i < N; i++ { 93 | t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 94 | tree := lockfree.NewRBTree(func(a, b interface{}) bool { 95 | if a.(int) < b.(int) { 96 | return true 97 | } 98 | return false 99 | }) 100 | 101 | // generate unique numbers 102 | nums := make([]int, i) 103 | ur := UniqueRand{generated: map[int]bool{}} 104 | for ii := range nums { 105 | nums[ii] = ur.Intn(2 * N) 106 | } 107 | check(nums) 108 | 109 | // range all numbers and put into tree 110 | for _, ii := range nums { 111 | tree.Put(ii, ii) 112 | } 113 | 114 | // range all numbers and check get is success 115 | for _, ii := range nums { 116 | if tree.Get(ii) != ii { 117 | t.Fatalf("want %v, got %v", ii, tree.Get(ii)) 118 | } 119 | } 120 | 121 | // check length is correctly equal to len(numbers) 122 | if tree.Len() != len(nums) { 123 | t.Fatalf("want %v, got %v", len(nums), tree.Len()) 124 | } 125 | 126 | // range all nums and delete them all 127 | for _, v := range nums { 128 | tree.Del(v) 129 | } 130 | 131 | if tree.Len() != 0 { 132 | fmt.Println(tree.String()) 133 | t.Fatalf("want %v, got %v", 0, tree.Len()) 134 | } 135 | // for _, ii := range nums { 136 | // if tree.Get(ii) != nil { 137 | // t.Fatalf("want %v, got %v", nil, tree.Get(ii)) 138 | // } 139 | // } 140 | }) 141 | } 142 | } 143 | 144 | func BenchmarkRBTree_Put(b *testing.B) { 145 | count := 0 146 | grow := 1 147 | for size := 0; size < 100000; size += 1 * grow { 148 | if count%10 == 0 { 149 | count = 1 150 | grow *= 10 151 | } 152 | b.Run(fmt.Sprintf("size-%d", size), func(b *testing.B) { 153 | // prepare problem size 154 | tree := lockfree.NewRBTree(func(a, b interface{}) bool { 155 | if a.(int) < b.(int) { 156 | return true 157 | } 158 | return false 159 | }) 160 | for n := 0; n < size-1; n++ { 161 | tree.Put(n, n) 162 | } 163 | b.ResetTimer() 164 | for i := 0; i < b.N; i++ { 165 | tree.Put(size, size) // only measure the last operation 166 | } 167 | }) 168 | count++ 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /skiplist.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree 6 | 7 | import "math/rand" 8 | 9 | // A SkipList maintains an ordered collection of key:valkue pairs. 10 | // It support insertion, lookup, and deletion operations with O(log n) time complexity 11 | // Paper: Pugh, William (June 1990). "Skip lists: a probabilistic alternative to balanced 12 | // trees". Communications of the ACM 33 (6): 668–676 13 | // TODO: FIXME: This implementation is not a non-blocking implementation. 14 | type SkipList struct { 15 | header *skiplistitem 16 | len int 17 | MaxLevel int 18 | less Less 19 | } 20 | 21 | // NewSkipList returns a skiplist. 22 | func NewSkipList(less Less) *SkipList { 23 | return &SkipList{ 24 | header: &skiplistitem{forward: []*skiplistitem{nil}}, 25 | MaxLevel: 32, 26 | less: less, 27 | } 28 | } 29 | 30 | // Len returns the length of given skiplist. 31 | func (s *SkipList) Len() int { 32 | return s.len 33 | } 34 | 35 | // Set sets given k and v pair into the skiplist. 36 | func (s *SkipList) Set(k interface{}, v interface{}) { 37 | // s.level starts from 0, we need to allocate one 38 | update := make([]*skiplistitem, s.level()+1, s.effectiveMaxLevel()+1) // make(type, len, cap) 39 | 40 | x := s.path(s.header, update, k) 41 | if x != nil && (s.less(x.k, k) || s.less(x.k, k)) { // if key exist, update 42 | x.v = v 43 | return 44 | } 45 | 46 | newl := s.randomLevel() 47 | if curl := s.level(); newl > curl { 48 | for i := curl + 1; i <= newl; i++ { 49 | update = append(update, s.header) 50 | s.header.forward = append(s.header.forward, nil) 51 | } 52 | } 53 | 54 | item := &skiplistitem{ 55 | forward: make([]*skiplistitem, newl+1, s.effectiveMaxLevel()+1), 56 | k: k, 57 | v: v, 58 | } 59 | for i := 0; i <= newl; i++ { 60 | item.forward[i] = update[i].forward[i] 61 | update[i].forward[i] = item 62 | } 63 | 64 | s.len++ 65 | } 66 | 67 | func (s *SkipList) path(x *skiplistitem, update []*skiplistitem, k interface{}) (candidate *skiplistitem) { 68 | depth := len(x.forward) - 1 69 | for i := depth; i >= 0; i-- { 70 | for x.forward[i] != nil && s.less(x.forward[i].k, k) { 71 | x = x.forward[i] 72 | } 73 | if update != nil { 74 | update[i] = x 75 | } 76 | } 77 | return x.next() 78 | } 79 | 80 | func (s *SkipList) randomLevel() (n int) { 81 | for n = 0; n < s.effectiveMaxLevel() && rand.Float64() < 0.25; n++ { 82 | } 83 | return 84 | } 85 | 86 | // Get returns corresponding v with given k. 87 | func (s *SkipList) Get(k interface{}) (v interface{}, ok bool) { 88 | x := s.path(s.header, nil, k) 89 | if x == nil || (s.less(x.k, k) || s.less(x.k, k)) { 90 | return nil, false 91 | } 92 | return x.v, true 93 | } 94 | 95 | // Search returns true if k is founded in the skiplist. 96 | func (s *SkipList) Search(k interface{}) (ok bool) { 97 | x := s.path(s.header, nil, k) 98 | if x != nil { 99 | ok = true 100 | return 101 | } 102 | return 103 | } 104 | 105 | // Range interates `from` to `to` with `op`. 106 | func (s *SkipList) Range(from, to interface{}, op func(v interface{})) { 107 | for start := s.path(s.header, nil, from); start.next() != nil; start = start.next() { 108 | if !s.less(start.k, to) { 109 | return 110 | } 111 | 112 | op(start.v) 113 | } 114 | } 115 | 116 | // Del returns the deleted value if ok 117 | func (s *SkipList) Del(k interface{}) (v interface{}, ok bool) { 118 | update := make([]*skiplistitem, s.level()+1, s.effectiveMaxLevel()) 119 | 120 | x := s.path(s.header, update, k) 121 | if x == nil || (s.less(x.k, k) || s.less(x.k, k)) { 122 | ok = false 123 | return 124 | } 125 | 126 | v = x.v 127 | for i := 0; i <= s.level() && update[i].forward[i] == x; i++ { 128 | update[i].forward[i] = x.forward[i] 129 | } 130 | for s.level() > 0 && s.header.forward[s.level()] == nil { 131 | s.header.forward = s.header.forward[:s.level()] 132 | } 133 | s.len-- 134 | ok = true 135 | return 136 | } 137 | 138 | func (s *SkipList) level() int { 139 | return len(s.header.forward) - 1 140 | } 141 | 142 | func (s *SkipList) effectiveMaxLevel() int { 143 | if s.level() < s.MaxLevel { 144 | return s.MaxLevel 145 | } 146 | return s.level() 147 | } 148 | 149 | type skiplistitem struct { 150 | forward []*skiplistitem 151 | k interface{} 152 | v interface{} 153 | } 154 | 155 | func (s *skiplistitem) next() *skiplistitem { 156 | if len(s.forward) == 0 { 157 | return nil 158 | } 159 | return s.forward[0] 160 | } 161 | -------------------------------------------------------------------------------- /rbtree.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The golang.design Initiative authors. 2 | // All rights reserved. Use of this source code is governed 3 | // by a MIT license that can be found in the LICENSE file. 4 | 5 | package lockfree 6 | 7 | import "fmt" 8 | 9 | type color uint32 10 | 11 | const ( 12 | red color = iota 13 | black 14 | ) 15 | 16 | type rbnode struct { 17 | c color 18 | left *rbnode 19 | right *rbnode 20 | parent *rbnode 21 | k, v interface{} 22 | } 23 | 24 | func (n *rbnode) color() color { 25 | if n == nil { 26 | return black 27 | } 28 | return n.c 29 | } 30 | 31 | func (n *rbnode) grandparent() *rbnode { 32 | return n.parent.parent 33 | } 34 | 35 | func (n *rbnode) uncle() *rbnode { 36 | if n.parent == n.grandparent().left { 37 | return n.grandparent().right 38 | } 39 | return n.grandparent().left 40 | } 41 | 42 | func (n *rbnode) sibling() *rbnode { 43 | if n == n.parent.left { 44 | return n.parent.right 45 | } 46 | return n.parent.left 47 | } 48 | 49 | func (n *rbnode) maximumNode() *rbnode { 50 | for n.right != nil { 51 | n = n.right 52 | } 53 | return n 54 | } 55 | 56 | // RBTree is a red-black tree 57 | // TODO: FIXME: This implementation is not a non-blocking implementation. 58 | type RBTree struct { 59 | root *rbnode 60 | len int 61 | less Less 62 | } 63 | 64 | // NewRBTree creates a red-black tree 65 | func NewRBTree(less Less) *RBTree { 66 | return &RBTree{less: less} 67 | } 68 | 69 | // Len returns the size of the tree 70 | func (t *RBTree) Len() int { 71 | return t.len 72 | } 73 | 74 | // Put stores the value by given key 75 | func (t *RBTree) Put(key, value interface{}) { 76 | var insertedNode *rbnode 77 | 78 | new := &rbnode{k: key, v: value, c: red} 79 | if t.root != nil { 80 | node := t.root 81 | LOOP: 82 | for { 83 | switch { 84 | case t.less(key, node.k): 85 | if node.left == nil { 86 | node.left = new 87 | insertedNode = node.left 88 | break LOOP 89 | } 90 | node = node.left 91 | case t.less(node.k, key): 92 | if node.right == nil { 93 | node.right = new 94 | insertedNode = node.right 95 | break LOOP 96 | } 97 | node = node.right 98 | default: // = 99 | node.k = key 100 | node.v = value 101 | return 102 | } 103 | } 104 | insertedNode.parent = node 105 | } else { 106 | t.root = new 107 | insertedNode = t.root 108 | } 109 | t.insertCase1(insertedNode) 110 | t.len++ 111 | } 112 | 113 | func (t *RBTree) insertCase1(n *rbnode) { 114 | if n.parent == nil { 115 | n.c = black 116 | return 117 | } 118 | t.insertCase2(n) 119 | } 120 | func (t *RBTree) insertCase2(n *rbnode) { 121 | if n.parent.color() == black { 122 | return 123 | } 124 | t.insertCase3(n) 125 | } 126 | func (t *RBTree) insertCase3(n *rbnode) { 127 | if n.uncle().color() == red { 128 | n.parent.c = black 129 | n.uncle().c = black 130 | n.grandparent().c = red 131 | t.insertCase1(n.grandparent()) 132 | return 133 | } 134 | t.insertCase4(n) 135 | 136 | } 137 | func (t *RBTree) insertCase4(n *rbnode) { 138 | if n == n.parent.right && n.parent == n.grandparent().left { 139 | t.rotateLeft(n.parent) 140 | n = n.left 141 | } else if n == n.parent.left && n.parent == n.grandparent().right { 142 | t.rotateRight(n.parent) 143 | n = n.right 144 | } 145 | t.insertCase5(n) 146 | } 147 | func (t *RBTree) insertCase5(n *rbnode) { 148 | n.parent.c = black 149 | n.grandparent().c = red 150 | if n == n.parent.left && n.parent == n.grandparent().left { 151 | t.rotateRight(n.grandparent()) 152 | return 153 | } else if n == n.parent.right && n.parent == n.grandparent().right { 154 | t.rotateLeft(n.grandparent()) 155 | } 156 | } 157 | 158 | func (t *RBTree) replace(old, new *rbnode) { 159 | if old.parent == nil { 160 | t.root = new 161 | } else { 162 | if old == old.parent.left { 163 | old.parent.left = new 164 | } else { 165 | old.parent.right = new 166 | } 167 | } 168 | if new != nil { 169 | new.parent = old.parent 170 | } 171 | } 172 | 173 | func (t *RBTree) rotateLeft(n *rbnode) { 174 | right := n.right 175 | t.replace(n, right) 176 | n.right = right.left 177 | if right.left != nil { 178 | right.left.parent = n 179 | } 180 | right.left = n 181 | n.parent = right 182 | } 183 | func (t *RBTree) rotateRight(n *rbnode) { 184 | left := n.left 185 | t.replace(n, left) 186 | n.left = left.right 187 | if left.right != nil { 188 | left.right.parent = n 189 | } 190 | left.right = n 191 | n.parent = left 192 | } 193 | 194 | // Get returns the stored value by given key 195 | func (t *RBTree) Get(key interface{}) interface{} { 196 | n := t.find(key) 197 | if n == nil { 198 | return nil 199 | } 200 | return n.v 201 | } 202 | 203 | func (t *RBTree) find(key interface{}) *rbnode { 204 | n := t.root 205 | for n != nil { 206 | switch { 207 | case t.less(key, n.k): 208 | n = n.left 209 | case t.less(n.k, key): 210 | n = n.right 211 | default: 212 | return n 213 | } 214 | } 215 | return nil 216 | } 217 | 218 | // Del deletes the stored value by given key 219 | func (t *RBTree) Del(key interface{}) { 220 | var child *rbnode 221 | 222 | n := t.find(key) 223 | if n == nil { 224 | return 225 | } 226 | 227 | if n.left != nil && n.right != nil { 228 | pred := n.left.maximumNode() 229 | n.k = pred.k 230 | n.v = pred.v 231 | n = pred 232 | } 233 | 234 | if n.left == nil || n.right == nil { 235 | if n.right == nil { 236 | child = n.left 237 | } else { 238 | child = n.right 239 | } 240 | if n.c == black { 241 | n.c = child.color() 242 | t.delCase1(n) 243 | } 244 | 245 | t.replace(n, child) 246 | if n.parent == nil && child != nil { 247 | child.c = black 248 | } 249 | } 250 | t.len-- 251 | } 252 | 253 | func (t *RBTree) delCase1(n *rbnode) { 254 | if n.parent == nil { 255 | return 256 | } 257 | 258 | t.delCase2(n) 259 | } 260 | func (t *RBTree) delCase2(n *rbnode) { 261 | sibling := n.sibling() 262 | if sibling.color() == red { 263 | n.parent.c = red 264 | sibling.c = black 265 | if n == n.parent.left { 266 | t.rotateLeft(n.parent) 267 | } else { 268 | t.rotateRight(n.parent) 269 | } 270 | } 271 | t.delCase3(n) 272 | } 273 | func (t *RBTree) delCase3(n *rbnode) { 274 | sibling := n.sibling() 275 | if n.parent.color() == black && 276 | sibling.color() == black && 277 | sibling.left.color() == black && 278 | sibling.right.color() == black { 279 | sibling.c = red 280 | t.delCase1(n.parent) 281 | return 282 | } 283 | t.delCase4(n) 284 | } 285 | func (t *RBTree) delCase4(n *rbnode) { 286 | sibling := n.sibling() 287 | if n.parent.color() == red && 288 | sibling.color() == black && 289 | sibling.left.color() == black && 290 | sibling.right.color() == black { 291 | sibling.c = red 292 | n.parent.c = black 293 | return 294 | } 295 | t.delCase5(n) 296 | } 297 | func (t *RBTree) delCase5(n *rbnode) { 298 | sibling := n.sibling() 299 | if n == n.parent.left && 300 | sibling.color() == black && 301 | sibling.left.color() == red && 302 | sibling.right.color() == black { 303 | sibling.c = red 304 | sibling.left.c = black 305 | t.rotateRight(sibling) 306 | } else if n == n.parent.right && 307 | sibling.color() == black && 308 | sibling.right.color() == red && 309 | sibling.left.color() == black { 310 | sibling.c = red 311 | sibling.right.c = black 312 | t.rotateLeft(sibling) 313 | } 314 | t.delCase6(n) 315 | } 316 | func (t *RBTree) delCase6(n *rbnode) { 317 | sibling := n.sibling() 318 | sibling.c = n.parent.color() 319 | n.parent.c = black 320 | if n == n.parent.left && sibling.right.color() == red { 321 | sibling.right.c = black 322 | t.rotateLeft(n.parent) 323 | return 324 | } 325 | sibling.left.c = black 326 | t.rotateRight(n.parent) 327 | } 328 | 329 | func (t *RBTree) String() string { 330 | str := "RBTree\n" 331 | if t.Len() != 0 { 332 | t.root.output("", true, &str) 333 | } 334 | return str 335 | } 336 | 337 | func (n *rbnode) String() string { 338 | return fmt.Sprintf("%v", n.k) 339 | } 340 | 341 | func (n *rbnode) output(prefix string, isTail bool, str *string) { 342 | if n.right != nil { 343 | newPrefix := prefix 344 | if isTail { 345 | newPrefix += "│ " 346 | } else { 347 | newPrefix += " " 348 | } 349 | n.right.output(newPrefix, false, str) 350 | } 351 | *str += prefix 352 | if isTail { 353 | *str += "└── " 354 | } else { 355 | *str += "┌── " 356 | } 357 | *str += n.String() + "\n" 358 | if n.left != nil { 359 | newPrefix := prefix 360 | if isTail { 361 | newPrefix += " " 362 | } else { 363 | newPrefix += "│ " 364 | } 365 | n.left.output(newPrefix, true, str) 366 | } 367 | } 368 | --------------------------------------------------------------------------------