File: var_store.go

package info (click to toggle)
golang-github-pzhin-go-sophia 0.0~git20180715.8bdc218-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 924 kB
  • sloc: ansic: 23,001; makefile: 4
file content (86 lines) | stat: -rw-r--r-- 2,561 bytes parent folder | download
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
78
79
80
81
82
83
84
85
86
package sophia

import (
	"reflect"
	"unsafe"
)

// varStore manages memory allocation and free for C variables
// Interface for C sophia object
// Only for internal usage
type varStore struct {
	// ptr Pointer to C sophia object
	ptr unsafe.Pointer

	// pointers slice of pointers to allocated C variables,
	// that must be freed after store usage
	pointers []unsafe.Pointer
}

func newVarStore(ptr unsafe.Pointer, size int) *varStore {
	return &varStore{
		ptr:      ptr,
		pointers: make([]unsafe.Pointer, 0, size),
	}
}

// TODO :: implement custom types
func (s *varStore) Set(path string, val interface{}) bool {
	v := reflect.ValueOf(val)

	switch v.Kind() {
	case reflect.String:
		return s.SetString(path, v.String())
	case reflect.Int, reflect.Int64, reflect.Int8, reflect.Int16, reflect.Int32:
		return s.SetInt(path, v.Int())
	case reflect.Uint, reflect.Uint64, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		return s.SetInt(path, int64(v.Uint()))
	}

	cPath := getCStringFromCache(path)

	size := int(reflect.TypeOf(val).Size())
	return spSetString(s.ptr, cPath, (unsafe.Pointer)(reflect.ValueOf(val).Pointer()), size)
}

func (s *varStore) SetString(path, val string) bool {
	cPath := getCStringFromCache(path)
	cVal := cString(val)
	s.pointers = append(s.pointers, unsafe.Pointer(cVal))
	return spSetString(s.ptr, cPath, unsafe.Pointer(cVal), len(val))
}

func (s *varStore) SetInt(path string, val int64) bool {
	return spSetInt(s.ptr, getCStringFromCache(path), val)
}

func (s *varStore) Get(path string, size *int) unsafe.Pointer {
	return spGetString(s.ptr, getCStringFromCache(path), size)
}

// GetString returns string without extra allocations.
// We can use C pointer to string to make Go string without allocation.
// C memory will be freed on Document Destroy() call.
// So for long-term usage you should to make copy of string to avoid data corruption.
func (s *varStore) GetString(path string, size *int) string {
	ptr := spGetString(s.ptr, getCStringFromCache(path), size)
	sh := reflect.StringHeader{Data: uintptr(ptr), Len: *size}
	return *(*string)(unsafe.Pointer(&sh))
}

func (s *varStore) GetObject(path string) unsafe.Pointer {
	return spGetObject(s.ptr, getCStringFromCache(path))
}

func (s *varStore) GetInt(path string) int64 {
	return spGetInt(s.ptr, getCStringFromCache(path))
}

// Free frees allocated memory for all C variables, that were in this store
// This always should be called to prevent memory leaks
func (s *varStore) Free() {
	for _, f := range s.pointers {
		free(f)
	}
	s.pointers = s.pointers[:0]
}