atom.go raw
1 package atom
2
3 import (
4 "github.com/p9c/p9/pkg/btcaddr"
5 "github.com/p9c/p9/pkg/chaincfg"
6 "time"
7
8 "go.uber.org/atomic"
9
10 "github.com/p9c/p9/pkg/btcjson"
11 "github.com/p9c/p9/pkg/chainhash"
12 )
13
14 // import all the atomics from uber atomic
15 type (
16 Int32 struct{ *atomic.Int32 }
17 Int64 struct{ *atomic.Int64 }
18 Uint32 struct{ *atomic.Uint32 }
19 Uint64 struct{ *atomic.Uint64 }
20 Bool struct{ *atomic.Bool }
21 Float64 struct{ *atomic.Float64 }
22 Duration struct{ *atomic.Duration }
23 Value struct{ *atomic.Value }
24 )
25
26 // The following are types added for handling cryptocurrency data for
27 // ParallelCoin
28
29 // Time is an atomic wrapper around time.Time
30 // https://godoc.org/time#Time
31 type Time struct {
32 v *Int64
33 }
34
35 // NewTime creates a Time.
36 func NewTime(tt time.Time) *Time {
37 t := &Int64{atomic.NewInt64(tt.UnixNano())}
38 return &Time{v: t}
39 }
40
41 // Load atomically loads the wrapped value.
42 func (at *Time) Load() time.Time {
43 return time.Unix(0, at.v.Load())
44 }
45
46 // Store atomically stores the passed value.
47 func (at *Time) Store(n time.Time) {
48 at.v.Store(n.UnixNano())
49 }
50
51 // Add atomically adds to the wrapped time.Duration and returns the new value.
52 func (at *Time) Add(n time.Time) time.Time {
53 return time.Unix(0, at.v.Add(n.UnixNano()))
54 }
55
56 // Sub atomically subtracts from the wrapped time.Duration and returns the new value.
57 func (at *Time) Sub(n time.Time) time.Time {
58 return time.Unix(0, at.v.Sub(n.UnixNano()))
59 }
60
61 // Swap atomically swaps the wrapped time.Duration and returns the old value.
62 func (at *Time) Swap(n time.Time) time.Time {
63 return time.Unix(0, at.v.Swap(n.UnixNano()))
64 }
65
66 // CAS is an atomic compare-and-swap.
67 func (at *Time) CAS(old, new time.Time) bool {
68 return at.v.CAS(old.UnixNano(), new.UnixNano())
69 }
70
71 // Hash is an atomic wrapper around chainhash.Hash
72 // Note that there isn't really any reason to have CAS or arithmetic or
73 // comparisons as it is fine to do these non-atomically between Load / Store and
74 // they are (slightly) long operations)
75 type Hash struct {
76 *Value
77 }
78
79 // NewHash creates a Hash.
80 func NewHash(tt chainhash.Hash) *Hash {
81 t := &Value{
82 Value: &atomic.Value{},
83 }
84 t.Store(tt)
85 return &Hash{Value: t}
86 }
87
88 // Load atomically loads the wrapped value.
89 // The returned value copied so as to prevent mutation by concurrent users
90 // of the atomic, as arrays, slices and maps are pass-by-reference variables
91 func (at *Hash) Load() chainhash.Hash {
92 o := at.Value.Load().(chainhash.Hash)
93 var v chainhash.Hash
94 copy(v[:], o[:])
95 return v
96 }
97
98 // Store atomically stores the passed value.
99 // The passed value is copied so further mutations are not propagated.
100 func (at *Hash) Store(h chainhash.Hash) {
101 var v chainhash.Hash
102 copy(v[:], h[:])
103 at.Value.Store(v)
104 }
105
106 // Swap atomically swaps the wrapped chainhash.Hash and returns the old value.
107 func (at *Hash) Swap(n chainhash.Hash) chainhash.Hash {
108 o := at.Value.Load().(chainhash.Hash)
109 at.Value.Store(n)
110 return o
111 }
112
113 // Address is an atomic wrapper around util.Address
114 type Address struct {
115 *atomic.String
116 ForNet *chaincfg.Params
117 }
118
119 // NewAddress creates a Hash.
120 func NewAddress(tt btcaddr.Address, forNet *chaincfg.Params) *Address {
121 t := atomic.NewString(tt.EncodeAddress())
122 return &Address{String: t, ForNet: forNet}
123 }
124
125 // Load atomically loads the wrapped value.
126 func (at *Address) Load() btcaddr.Address {
127 addr, e := btcaddr.Decode(at.String.Load(), at.ForNet)
128 if e != nil {
129 return nil
130 }
131 return addr
132 }
133
134 // Store atomically stores the passed value.
135 // The passed value is copied so further mutations are not propagated.
136 func (at *Address) Store(h btcaddr.Address) {
137 at.String.Store(h.EncodeAddress())
138 }
139
140 // Swap atomically swaps the wrapped util.Address and returns the old value.
141 func (at *Address) Swap(n btcaddr.Address) btcaddr.Address {
142 o := at.Load()
143 at.Store(n)
144 return o
145 }
146
147 // ListTransactionsResult is an atomic wrapper around
148 // []btcjson.ListTransactionsResult
149 type ListTransactionsResult struct {
150 v *Value
151 }
152
153 // NewListTransactionsResult creates a btcjson.ListTransactionsResult.
154 func NewListTransactionsResult(ltr []btcjson.ListTransactionsResult) *ListTransactionsResult {
155 t := &Value{
156 Value: &atomic.Value{},
157 }
158 v := make([]btcjson.ListTransactionsResult, len(ltr))
159 copy(v, ltr)
160 t.Store(v)
161 return &ListTransactionsResult{v: t}
162 }
163
164 // Load atomically loads the wrapped value.
165 // Note that it is copied and the stored value remains as it is
166 func (at *ListTransactionsResult) Load() []btcjson.ListTransactionsResult {
167 ltr := at.v.Load().([]btcjson.ListTransactionsResult)
168 v := make([]btcjson.ListTransactionsResult, len(ltr))
169 copy(v, ltr)
170 return v
171 }
172
173 // Store atomically stores the passed value.
174 // Note that it is copied and the passed value remains as it is
175 func (at *ListTransactionsResult) Store(ltr []btcjson.ListTransactionsResult) {
176 v := make([]btcjson.ListTransactionsResult, len(ltr))
177 copy(v, ltr)
178 at.v.Store(v)
179 }
180
181 // Swap atomically swaps the wrapped chainhash.ListTransactionsResult and
182 // returns the old value.
183 func (at *ListTransactionsResult) Swap(
184 n []btcjson.ListTransactionsResult,
185 ) []btcjson.ListTransactionsResult {
186 o := at.v.Load().([]btcjson.ListTransactionsResult)
187 at.v.Store(n)
188 return o
189 }
190
191 // Len returns the length of the []btcjson.ListTransactionsResult
192 func (at *ListTransactionsResult) Len() int {
193 return len(at.v.Load().([]btcjson.ListTransactionsResult))
194 }
195