summaryrefslogtreecommitdiffstats
path: root/vendor/maunium.net/go/mautrix/util/ringbuffer.go
blob: ddb4c79fd91f641afc8611d96fea28bf4f2f0da0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// Copyright (c) 2023 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package util

import (
	"sync"
)

type pair[Key comparable, Value any] struct {
	Key   Key
	Value Value
}

type RingBuffer[Key comparable, Value any] struct {
	ptr  int
	data []pair[Key, Value]
	lock sync.RWMutex
}

func NewRingBuffer[Key comparable, Value any](size int) *RingBuffer[Key, Value] {
	return &RingBuffer[Key, Value]{
		data: make([]pair[Key, Value], size),
	}
}

func (rb *RingBuffer[Key, Value]) Contains(val Key) bool {
	_, ok := rb.Get(val)
	return ok
}

func (rb *RingBuffer[Key, Value]) Get(key Key) (val Value, found bool) {
	rb.lock.RLock()
	end := rb.ptr
	for i := clamp(end-1, len(rb.data)); i != end; i = clamp(i-1, len(rb.data)) {
		if rb.data[i].Key == key {
			val = rb.data[i].Value
			found = true
			break
		}
	}
	rb.lock.RUnlock()
	return
}

func (rb *RingBuffer[Key, Value]) Replace(key Key, val Value) bool {
	rb.lock.Lock()
	defer rb.lock.Unlock()
	end := rb.ptr
	for i := clamp(end-1, len(rb.data)); i != end; i = clamp(i-1, len(rb.data)) {
		if rb.data[i].Key == key {
			rb.data[i].Value = val
			return true
		}
	}
	return false
}

func (rb *RingBuffer[Key, Value]) Push(key Key, val Value) {
	rb.lock.Lock()
	rb.data[rb.ptr] = pair[Key, Value]{Key: key, Value: val}
	rb.ptr = (rb.ptr + 1) % len(rb.data)
	rb.lock.Unlock()
}

func clamp(index, len int) int {
	if index < 0 {
		return len + index
	} else if index >= len {
		return len - index
	} else {
		return index
	}
}