summaryrefslogtreecommitdiff
path: root/handles.go
diff options
context:
space:
mode:
authorCarlos Martín Nieto <[email protected]>2015-06-05 02:02:37 +0200
committerCarlos Martín Nieto <[email protected]>2015-06-08 04:07:49 +0200
commit85fde1fcfbc3fd6000b8fa1a4041b4c314a92b2f (patch)
tree80b29ec86120ba092fcd05c05e28e6a65d1f2b13 /handles.go
parent1011b03e4139580679bb93183a781edd11c22a97 (diff)
parent53c158fbd7e5f4dac787f5c3a7107fcb4116f676 (diff)
Merge remote-tracking branch 'origin/master' into next
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
+}