1
1
package trit
2
2
3
3
import (
4
+ "context"
4
5
"reflect"
6
+ "runtime"
7
+ "sync"
8
+ )
9
+
10
+ var (
11
+ // The parallelTasks the number of parallel tasks.
12
+ parallelTasks = 1
13
+
14
+ // The maxParallelTasks is the maximum number of parallel tasks.
15
+ maxParallelTasks = runtime .NumCPU () * 3
5
16
)
6
17
7
18
// Logicable is a special data type from which to determine the state of Trit
@@ -13,6 +24,66 @@ type Logicable interface {
13
24
float32 | float64
14
25
}
15
26
27
+ // The logicFoundValue is a helper struct that holds a boolean value
28
+ // and a Mutex to protect it from concurrent access.
29
+ //
30
+ // They are used in the In function to detect the desired result
31
+ // in a separate goroutine.
32
+ type logicFoundValue struct {
33
+ m sync.Mutex
34
+ value Trit
35
+ }
36
+
37
+ // SetValue sets a new value for the Found. It locks the Mutex before
38
+ // changing the value and unlocks it after the change is complete.
39
+ func (f * logicFoundValue ) SetValue (value Trit ) {
40
+ f .m .Lock ()
41
+ defer f .m .Unlock ()
42
+ f .value = value
43
+ }
44
+
45
+ // GetValue retrieves the current value of the Found. It locks the Mutex
46
+ // before reading the value and unlocks it after the read is complete.
47
+ func (f * logicFoundValue ) GetValue () Trit {
48
+ f .m .Lock ()
49
+ defer f .m .Unlock ()
50
+ return f .value
51
+ }
52
+
53
+ // The init initializes the randomGenerator variable.
54
+ func init () {
55
+ parallelTasks = runtime .NumCPU () * 2
56
+ }
57
+
58
+ // ParallelTasks returns the number of parallel tasks.
59
+ //
60
+ // If the function is called without parameters, it returns the
61
+ // current value of parallelTasks.
62
+ //
63
+ // A function can receive one or more values for parallelTasks,
64
+ // these values are added together to form the final result for
65
+ // parallelTasks. If the new value for parallelTasks is less than
66
+ // or equal to zero - it will be set to 1, if it is greater than
67
+ // maxParallelTasks - it will be set to maxParallelTasks.
68
+ func ParallelTasks (v ... int ) int {
69
+ if len (v ) > 0 {
70
+ n := 0
71
+ for _ , value := range v {
72
+ n += value
73
+ }
74
+
75
+ if n <= 0 {
76
+ parallelTasks = 1
77
+ } else if n > maxParallelTasks {
78
+ parallelTasks = maxParallelTasks
79
+ } else {
80
+ parallelTasks = n
81
+ }
82
+ }
83
+
84
+ return parallelTasks
85
+ }
86
+
16
87
// The logicToTrit function converts any logic type to Trit.
17
88
func logicToTrit [T Logicable ](v T ) Trit {
18
89
switch any (v ).(type ) {
@@ -133,14 +204,65 @@ func Convert[T Logicable](v T) Trit {
133
204
// t := trit.All(trit.True, trit.True, trit.True)
134
205
// fmt.Println(t.String()) // Output: True
135
206
func All [T Logicable ](t ... T ) Trit {
136
- for _ , v := range t {
137
- trit := logicToTrit (v )
138
- if trit .IsFalse () {
139
- return False
207
+ var wg sync.WaitGroup
208
+
209
+ // Will use context to stop the rest of the goroutines
210
+ // if the value has already been found.
211
+ ctx , cancel := context .WithCancel (context .Background ())
212
+ defer cancel ()
213
+
214
+ p := parallelTasks
215
+ found := & logicFoundValue {value : True }
216
+
217
+ // If the length of the slice is less than or equal to
218
+ // the number of parallel tasks, then we do not need
219
+ // to use goroutines.
220
+ if l := len (t ); l == 0 {
221
+ return False
222
+ } else if l < p * 2 {
223
+ for _ , v := range t {
224
+ trit := logicToTrit (v )
225
+ if trit .IsFalse () || trit .IsUnknown () {
226
+ return False
227
+ }
140
228
}
229
+
230
+ return True
141
231
}
142
232
143
- return True
233
+ chunkSize := len (t ) / p
234
+ for i := 0 ; i < p ; i ++ {
235
+ wg .Add (1 )
236
+
237
+ start := i * chunkSize
238
+ end := start + chunkSize
239
+ if i == p - 1 {
240
+ end = len (t )
241
+ }
242
+
243
+ go func (start , end int ) {
244
+ defer wg .Done ()
245
+
246
+ for _ , b := range t [start :end ] {
247
+ trit := logicToTrit (b )
248
+ // Check if the context has been cancelled.
249
+ select {
250
+ case <- ctx .Done ():
251
+ return
252
+ default :
253
+ }
254
+
255
+ if trit .IsFalse () || trit .IsUnknown () {
256
+ found .SetValue (False )
257
+ cancel () // stop all other goroutines
258
+ return
259
+ }
260
+ }
261
+ }(start , end )
262
+ }
263
+
264
+ wg .Wait ()
265
+ return found .GetValue ()
144
266
}
145
267
146
268
// Any returns True if any of the trit-objects are True.
@@ -150,14 +272,66 @@ func All[T Logicable](t ...T) Trit {
150
272
// t := trit.Any(trit.True, trit.False, trit.False)
151
273
// fmt.Println(t.String()) // Output: True
152
274
func Any [T Logicable ](t ... T ) Trit {
153
- for _ , v := range t {
154
- trit := logicToTrit (v )
155
- if trit .IsTrue () {
156
- return True
275
+ var wg sync.WaitGroup
276
+
277
+ // Will use context to stop the rest of the goroutines
278
+ // if the value has already been found.
279
+ ctx , cancel := context .WithCancel (context .Background ())
280
+ defer cancel ()
281
+
282
+ p := parallelTasks
283
+ found := & logicFoundValue {value : False }
284
+
285
+ // If the length of the slice is less than or equal to
286
+ // the number of parallel tasks, then we do not need
287
+ // to use goroutines.
288
+ if l := len (t ); l == 0 {
289
+ return False
290
+ } else if l < p * 2 {
291
+ for _ , v := range t {
292
+ trit := logicToTrit (v )
293
+ if trit .IsTrue () {
294
+ return True
295
+ }
157
296
}
297
+
298
+ return False
158
299
}
159
300
160
- return False
301
+ chunkSize := len (t ) / p
302
+ for i := 0 ; i < p ; i ++ {
303
+ wg .Add (1 )
304
+
305
+ start := i * chunkSize
306
+ end := start + chunkSize
307
+ if i == p - 1 {
308
+ end = len (t )
309
+ }
310
+
311
+ go func (start , end int ) {
312
+ defer wg .Done ()
313
+
314
+ for _ , b := range t [start :end ] {
315
+ trit := logicToTrit (b )
316
+
317
+ // Check if the context has been cancelled.
318
+ select {
319
+ case <- ctx .Done ():
320
+ return
321
+ default :
322
+ }
323
+
324
+ if trit .IsTrue () {
325
+ found .SetValue (True )
326
+ cancel () // stop all other goroutines
327
+ return
328
+ }
329
+ }
330
+ }(start , end )
331
+ }
332
+
333
+ wg .Wait ()
334
+ return found .GetValue ()
161
335
}
162
336
163
337
// None returns True if none of the trit-objects are True.
@@ -333,6 +507,79 @@ func Neq[T, U Logicable](a T, b U) Trit {
333
507
return ta .Neq (tb )
334
508
}
335
509
510
+ // Known returns boolean true if all Trit-Like values has definiteness,
511
+ // i.e. is either True or False.
512
+ //
513
+ // Example usage:
514
+ //
515
+ // a := trit.Known(trit.True, trit.False, trit.Unknown)
516
+ // fmt.Println(a.String()) // Output: False
517
+ //
518
+ // b := trit.Known(trit.True, trit.True, trit.False)
519
+ // fmt.Println(b.String()) // Output: True
520
+ func Known [T Logicable ](ts ... T ) Trit {
521
+ var wg sync.WaitGroup
522
+
523
+ // Will use context to stop the rest of the goroutines
524
+ // if the value has already been found.
525
+ ctx , cancel := context .WithCancel (context .Background ())
526
+ defer cancel ()
527
+
528
+ p := parallelTasks
529
+ found := & logicFoundValue {value : True }
530
+
531
+ // If the length of the slice is less than or equal to
532
+ // the number of parallel tasks, then we do not need
533
+ // to use goroutines.
534
+ if l := len (ts ); l == 0 {
535
+ return False
536
+ } else if l < p * 2 {
537
+ for _ , t := range ts {
538
+ trit := logicToTrit (t )
539
+ if trit == Unknown {
540
+ return False
541
+ }
542
+ }
543
+
544
+ return True
545
+ }
546
+
547
+ chunkSize := len (ts ) / p
548
+ for i := 0 ; i < p ; i ++ {
549
+ wg .Add (1 )
550
+
551
+ start := i * chunkSize
552
+ end := start + chunkSize
553
+ if i == p - 1 {
554
+ end = len (ts )
555
+ }
556
+
557
+ go func (start , end int ) {
558
+ defer wg .Done ()
559
+
560
+ for _ , b := range ts [start :end ] {
561
+ trit := logicToTrit (b )
562
+
563
+ // Check if the context has been cancelled.
564
+ select {
565
+ case <- ctx .Done ():
566
+ return
567
+ default :
568
+ }
569
+
570
+ if trit .IsUnknown () {
571
+ found .SetValue (False )
572
+ cancel () // stop all other goroutines
573
+ return
574
+ }
575
+ }
576
+ }(start , end )
577
+ }
578
+
579
+ wg .Wait ()
580
+ return found .GetValue ()
581
+ }
582
+
336
583
// IsConfidence returns boolean true if all Trit-Like values has definiteness,
337
584
// i.e. is either True or False.
338
585
//
0 commit comments