summaryrefslogtreecommitdiff
path: root/handles.go
diff options
context:
space:
mode:
authorCarlos Martín Nieto <[email protected]>2015-05-30 22:23:23 +0200
committerCarlos Martín Nieto <[email protected]>2015-05-30 22:23:23 +0200
commit35ff0de8559ed987ff82b025cc2bb5983f29e559 (patch)
tree62b2ffe5ef7c32f89a49bb722c1cce85b2a9656b /handles.go
parent193deb7ae3cbc5d5a1f7f186aae6edb20bff950a (diff)
parente8531dd5c31fc87044e9061b18f37df9b05bd0ac (diff)
Merge pull request #196 from pks-t/pointer-indirection
[WIP/RFC] Pointer indirection
Diffstat (limited to 'handles.go')
-rw-r--r--handles.go84
1 files changed, 84 insertions, 0 deletions
diff --git a/handles.go b/handles.go
new file mode 100644
index 0000000..ec62a48
--- /dev/null
+++ b/handles.go
@@ -0,0 +1,84 @@
+package git
+
+import (
+ "fmt"
+ "sync"
+ "unsafe"
+)
+
+type HandleList struct {
+ sync.RWMutex
+ // stores the Go pointers
+ handles []interface{}
+ // indicates which indices are in use
+ set map[int]bool
+}
+
+func NewHandleList() *HandleList {
+ return &HandleList{
+ handles: make([]interface{}, 5),
+ set: make(map[int]bool),
+ }
+}
+
+// findUnusedSlot finds the smallest-index empty space in our
+// list. You must only run this function while holding a write lock.
+func (v *HandleList) findUnusedSlot() int {
+ for i := 1; i < len(v.handles); i++ {
+ isUsed := v.set[i]
+ if !isUsed {
+ return i
+ }
+ }
+
+ // reaching here means we've run out of entries so append and
+ // return the new index, which is equal to the old length.
+ slot := len(v.handles)
+ v.handles = append(v.handles, nil)
+
+ return slot
+}
+
+// Track adds the given pointer to the list of pointers to track and
+// returns a pointer value which can be passed to C as an opaque
+// pointer.
+func (v *HandleList) Track(pointer interface{}) unsafe.Pointer {
+ v.Lock()
+
+ slot := v.findUnusedSlot()
+ v.handles[slot] = pointer
+ v.set[slot] = true
+
+ v.Unlock()
+
+ return unsafe.Pointer(&slot)
+}
+
+// Untrack stops tracking the pointer given by the handle
+func (v *HandleList) Untrack(handle unsafe.Pointer) {
+ slot := *(*int)(handle)
+
+ v.Lock()
+
+ v.handles[slot] = nil
+ delete(v.set, slot)
+
+ v.Unlock()
+}
+
+// Get retrieves the pointer from the given handle
+func (v *HandleList) Get(handle unsafe.Pointer) interface{} {
+ slot := *(*int)(handle)
+
+ v.RLock()
+
+ if _, ok := v.set[slot]; !ok {
+ panic(fmt.Sprintf("invalid pointer handle: %p", handle))
+ }
+
+ ptr := v.handles[slot]
+
+ v.RUnlock()
+
+ return ptr
+}