Completed
Push — master ( a1ea93...617d0b )
by Hayrullah
14s queued 13s
created

sort.go   A

Size/Duplication

Total Lines 69
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
dl 0
loc 69
rs 10
c 0
b 0
f 0
1
package gotil
2
3
import (
4
	"fmt"
5
	"reflect"
6
	"strings"
7
8
	"github.com/gotilty/gotil/internal/errs"
9
)
10
11
// Sort returns a new array of ordered values as ascending, using a version of Merge Algorithm.
12
//	data := []int64{100, 30, -100, -5}
13
//	newData := gotil.Sort(data)
14
//	// Output: [-100 -5 30 100]
15
func Sort[T any](s []T) []T {
16
	return SortBy(s, "")
17
}
18
19
// SortDesc returns a new array of ordered values as descending, using a version of Merge Algorithm.
20
//	data := []int64{100, 30, -100, -5}
21
//	newData := gotilSortDesc(data)
22
//	// Output: [100 30 -5 -100]
23
func SortDesc[T any](s []T) []T {
24
	return SortDescBy(s, "")
25
}
26
27
// SortBy returns a new array of ordered values as ascending, using a version of Merge Algorithm with a given property path and list of struct
28
// First param is slice of any type
29
// Second param is path delimited by dot. More information please check documentation.
30
//
31
// Example:
32
//	SortBy(data, "location.city")
33
//	data := []user{
34
//		{
35
//			name: "Micheal",
36
// 			age:  27,
37
// 			location: location{
38
// 				city: "New York",
39
// 			},
40
//		},
41
//		{
42
// 			name: "Joe",
43
// 			age:  30,
44
// 			location: location{
45
// 				city: "Detroit",
46
// 			},
47
//  	},
48
//	}
49
//	newData, _ := SortBy(data, "location.city")
50
//	// Output: [{Joe 30 {Detroit}} {Micheal 27 {New York}}]
51
func SortBy[T any](s []T, path string) []T {
52
	sr := sortResult[T]{
53
		p:   path,
54
		asc: true,
55
	}
56
	sr = sr.sortByThen(s, path)
57
	r, _ := sr.getResult()
58
	return r
59
}
60
61
// SortDescBy returns a new array of ordered values as descending, using a version of Merge Algorithm with a given property path and list of struct
62
// First param is slice of any type
63
// Second param is path delimited by dot. More information please check documentation.
64
//
65
// Example: gotil.SortDescBy(data, "location.city")
66
//	data := []user{
67
//  	{
68
// 			name: "Micheal",
69
// 			age:  27,
70
// 			location: location{
71
// 				city: "New York",
72
// 			},
73
// 		},
74
//		{
75
// 			name: "Joe",
76
// 			age:  30,
77
// 			location: location{
78
// 				city: "Detroit",
79
// 			},
80
// 		 },
81
//	}
82
//	newData, _ := gotil.SortDescBy(data, "location.city")
83
//	// Output: [{Micheal 27 {New York}} {Joe 30 {Detroit}}]
84
func SortDescBy[T any](s []T, path string) []T {
85
	sr := sortResult[T]{
86
		p:   path,
87
		asc: false,
88
	}
89
	sr = sr.sortByThen(s, path)
90
	r, _ := sr.getResult()
91
	return r
92
}
93
94
type sortResult[T any] struct {
95
	r   []T
96
	p   string
97
	e   error
98
	asc bool
99
}
100
101
func (s sortResult[T]) getResult() ([]T, error) {
102
	return s.r, s.e
103
}
104
105
func (sr sortResult[T]) sortByThen(s []T, path string) sortResult[T] {
106
	newSlice := copySlice(s)
107
	if len(newSlice) < 2 {
108
		sr.r = newSlice
109
		sr.e = nil
110
		return sr
111
	}
112
	k := newSlice[0]
113
	c, errc := getcomparer(&k, path)
114
	if errc != nil {
115
		sr.r = nil
116
		sr.e = errc
117
		return sr
118
	}
119
	if mr, errm := mergeSort(&newSlice, c, sr.asc); errm == nil {
120
		sr.r = (*mr)
121
		sr.e = nil
122
		return sr
123
	} else {
124
		sr.r = nil
125
		sr.e = errm
126
		return sr
127
	}
128
}
129
130
func mergeSort[T any](val *[]T, c icomparable[*T], asc bool) (*[]T, error) {
131
	if len(*val) < 2 {
132
		return (val), nil
133
	}
134
	li := len(*val) / 2
135
	left := (*val)[0:li]
136
	first, errf := mergeSort(&left, c, asc)
137
	if errf != nil {
138
		return nil, errf
139
	}
140
	right := (*val)[li:len(*val)]
141
	second, errs := mergeSort(&right, c, asc)
142
	if errs != nil {
143
		return nil, errs
144
	}
145
	return merge(first, second, c, asc)
146
}
147
148
func merge[T any](a *[]T, b *[]T, c icomparable[*T], asc bool) (*[]T, error) {
149
	final := make([]T, 0, len(*a)+len(*b))
150
	i := 0
151
	j := 0
152
153
	for i < len(*a) && j < len(*b) {
154
		ii := (*a)[i]
155
		ij := (*b)[j]
156
		if ok, err := c.compare(&ii, &ij); err == nil {
157
			if asc == false {
158
				ok = !ok
159
			}
160
			if ok {
161
				final = append(final, ii)
162
				i++
163
			} else {
164
				final = append(final, ij)
165
				j++
166
			}
167
		} else {
168
			return nil, err
169
		}
170
	}
171
	for ; i < len(*a); i++ {
172
		ii := (*a)[i]
173
		final = append(final, ii)
174
	}
175
176
	for ; j < len(*b); j++ {
177
		ij := (*b)[j]
178
		final = append(final, ij)
179
	}
180
	return &final, nil
181
}
182
183
type icomparable[T any] interface {
184
	compare(a T, b T) (bool, error)
185
}
186
187
type stringComparer struct {
188
	icomparable[*string]
189
}
190
191
type intComparer struct {
192
	icomparable[*int]
193
}
194
195
type int8Comparer struct {
196
	icomparable[*int8]
197
}
198
type int16Comparer struct {
199
	icomparable[*int16]
200
}
201
202
type int32Comparer struct {
203
	icomparable[*int32]
204
}
205
206
type int64Comparer struct {
207
	icomparable[*int64]
208
}
209
210
type uIntComparer struct {
211
	icomparable[*uint]
212
}
213
214
type uInt8Comparer struct {
215
	icomparable[*uint8]
216
}
217
type uInt16Comparer struct {
218
	icomparable[*uint16]
219
}
220
221
type uInt32Comparer struct {
222
	icomparable[*uint32]
223
}
224
225
type uInt64Comparer struct {
226
	icomparable[*uint64]
227
}
228
229
type float32Comparer struct {
230
	icomparable[*float32]
231
}
232
type float64Comparer struct {
233
	icomparable[*float64]
234
}
235
236
type boolComparer struct {
237
	icomparable[*bool]
238
}
239
240
type Integer interface {
241
	int | int8 | int16 | int32 | int64
242
}
243
244
type structComparer[T any] struct {
245
	icomparable[*T]
246
	property string
247
	path     string
248
	child    icomparable[*T]
249
}
250
251
type reflectComparer struct {
252
	icomparable[*reflect.Value]
253
	property string
254
	path     string
255
	child    icomparable[*reflect.Value]
256
}
257
258
func (s stringComparer) compare(a *string, b *string) (bool, error) {
259
	return strings.Compare((*a), (*b)) == -1, nil
260
}
261
262
func (s intComparer) compare(a *int, b *int) (bool, error) {
263
	return (*a) < (*b), nil
264
}
265
func (s int8Comparer) compare(a *int8, b *int8) (bool, error) {
266
	return (*a) < (*b), nil
267
}
268
func (s int16Comparer) compare(a *int16, b *int16) (bool, error) {
269
	return (*a) < (*b), nil
270
}
271
272
func (s int32Comparer) compare(a *int32, b *int32) (bool, error) {
273
	return (*a) < (*b), nil
274
}
275
func (s int64Comparer) compare(a *int64, b *int64) (bool, error) {
276
	return (*a) < (*b), nil
277
}
278
279
func (s uIntComparer) compare(a *uint, b *uint) (bool, error) {
280
	return (*a) < (*b), nil
281
}
282
func (s uInt8Comparer) compare(a *uint8, b *uint8) (bool, error) {
283
	return (*a) < (*b), nil
284
}
285
func (s uInt16Comparer) compare(a *uint16, b *uint16) (bool, error) {
286
	return (*a) < (*b), nil
287
}
288
289
func (s uInt32Comparer) compare(a *uint32, b *uint32) (bool, error) {
290
	return (*a) < (*b), nil
291
}
292
func (s uInt64Comparer) compare(a *uint64, b *uint64) (bool, error) {
293
	return (*a) < (*b), nil
294
}
295
296
func (s float32Comparer) compare(a *float32, b *float32) (bool, error) {
297
	return (*a) < (*b), nil
298
}
299
300
func (s float64Comparer) compare(a *float64, b *float64) (bool, error) {
301
	return (*a) < (*b), nil
302
}
303
304
func (s boolComparer) compare(a *bool, b *bool) (bool, error) {
305
	return (*a) != true, nil
306
}
307
308
func (s reflectComparer) compare(ar *reflect.Value, br *reflect.Value) (bool, error) {
309
	var a, b reflect.Value
310
	if (*ar).Kind() == reflect.Ptr || (*ar).Kind() == reflect.Pointer {
311
		a = (*ar).Elem()
312
		b = (*br).Elem()
313
	} else {
314
		a = (*ar)
315
		b = (*br)
316
	}
317
318
	switch (a).Kind() {
319
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
320
		iv := (a).Int()
321
		iv2 := (b).Int()
322
		if cn, err := getcomparer(&iv, s.path); err == nil {
323
			return cn.compare(&iv, &iv2)
324
		} else {
325
			return false, err
326
		}
327
	case reflect.Float32, reflect.Float64:
328
		fv := (a).Float()
329
		fv2 := (b).Float()
330
		if cn, err := getcomparer(&fv, s.path); err == nil {
331
			return cn.compare(&fv, &fv2)
332
		} else {
333
			return false, err
334
		}
335
	case reflect.String:
336
		sv := (a).String()
337
		sv2 := (b).String()
338
		if cn, err := getcomparer(&sv, s.path); err == nil {
339
			return cn.compare(&sv, &sv2)
340
		} else {
341
			return false, err
342
		}
343
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
344
		uiv := (a).Uint()
345
		uiv2 := (b).Uint()
346
		if cn, err := getcomparer(&uiv, s.path); err == nil {
347
			return cn.compare(&uiv, &uiv2)
348
		} else {
349
			return false, err
350
		}
351
	case reflect.Bool:
352
		bv := (a).Bool()
353
		bv2 := (b).Bool()
354
		if cn, err := getcomparer(&bv, s.path); err == nil {
355
			return cn.compare(&bv, &bv2)
356
		} else {
357
			return false, err
358
		}
359
	case reflect.Struct:
360
		if s.path == "" {
361
			return false, errs.NewMissingParameterError("path", "")
362
		}
363
		properties := strings.SplitN(s.path, ".", 2)
364
		property := ""
365
		path := ""
366
		if len(properties) >= 2 {
367
			property = properties[0]
368
			path = properties[1]
369
		} else {
370
			property = properties[0]
371
			path = ""
372
		}
373
		ap := a.FieldByName(property)
374
		bp := b.FieldByName(property)
375
		apr := ap
376
		bpr := bp
377
378
		apk := ap.Kind()
379
		bpk := bp.Kind()
380
		if apk.String() != bpk.String() {
381
			return false, errs.NewUnsupportedParameterTypeError(
382
				fmt.Sprintf("%s [%v]: %s [%v]",
383
					apk.String(),
384
					ap.Interface(),
385
					bpk.String(),
386
					bp.Interface()),
387
				"they must be the same type",
388
			)
389
		}
390
		rl := reflectComparer{
391
			path: path,
392
		}
393
		return rl.compare(&apr, &bpr)
394
	default:
395
		return false, errs.ErrUnsupportedType
396
	}
397
}
398
399
func (s structComparer[T]) compare(a T, b T) (bool, error) {
400
	comparer := reflectComparer{
401
		path:     s.path,
402
		property: s.property,
403
	}
404
	a1 := reflect.ValueOf(a)
405
	b1 := reflect.ValueOf(b)
406
	return comparer.compare(&a1, &b1)
407
}
408
409
func getcomparer[T any](k T, path string) (icomparable[T], error) {
410
	var comparer interface{}
411
	switch any(k).(type) {
412
	case *int:
413
		comparer = intComparer{}
414
		return comparer.(icomparable[T]), nil
415
	case *int8:
416
		comparer = int8Comparer{}
417
		return comparer.(icomparable[T]), nil
418
	case *int16:
419
		comparer = int16Comparer{}
420
		return comparer.(icomparable[T]), nil
421
	case *int32:
422
		comparer = int32Comparer{}
423
		return comparer.(icomparable[T]), nil
424
	case *int64:
425
		comparer = int64Comparer{}
426
		return comparer.(icomparable[T]), nil
427
	case *uint:
428
		comparer = uIntComparer{}
429
		return comparer.(icomparable[T]), nil
430
	case *uint8:
431
		comparer = uInt8Comparer{}
432
		return comparer.(icomparable[T]), nil
433
	case *uint16:
434
		comparer = uInt16Comparer{}
435
		return comparer.(icomparable[T]), nil
436
	case *uint32:
437
		comparer = uInt32Comparer{}
438
		return comparer.(icomparable[T]), nil
439
	case *uint64:
440
		comparer = uInt64Comparer{}
441
		return comparer.(icomparable[T]), nil
442
	case *string:
443
		comparer = stringComparer{}
444
		return (comparer).(icomparable[T]), nil
445
	default:
446
		krf := reflect.ValueOf(k).Kind()
447
		if krf == reflect.Ptr {
448
			e := reflect.ValueOf(k).Elem()
449
			switch e.Kind() {
450
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
451
				iv := e.Int()
452
				if cn, err := getcomparer(&iv, ""); err == nil {
453
					var c2 interface{}
454
					c2 = cn
455
					return c2.(icomparable[T]), err
456
				} else {
457
					return nil, err
458
				}
459
			case reflect.Float32, reflect.Float64:
460
				fv := e.Float()
461
				if cn, err := getcomparer(&fv, ""); err == nil {
462
					var c2 interface{}
463
					c2 = cn
464
					return c2.(icomparable[T]), err
465
				} else {
466
					return nil, err
467
				}
468
			case reflect.String:
469
				sv := e.String()
470
				if cn, err := getcomparer(&sv, ""); err == nil {
471
					var c2 interface{}
472
					c2 = cn
473
					return c2.(icomparable[T]), err
474
				} else {
475
					return nil, err
476
				}
477
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
478
				uiv := e.Uint()
479
				if cn, err := getcomparer(&uiv, ""); err == nil {
480
					var c2 interface{}
481
					c2 = cn
482
					return c2.(icomparable[T]), err
483
				} else {
484
					return nil, err
485
				}
486
			case reflect.Bool:
487
				bv := e.Bool()
488
				if cn, err := getcomparer(&bv, ""); err == nil {
489
					var c2 interface{}
490
					c2 = cn
491
					return c2.(icomparable[T]), err
492
				} else {
493
					return nil, err
494
				}
495
			case reflect.Struct:
496
497
				if path == "" {
498
					return nil, errs.NewMissingParameterError("path", "")
499
				}
500
501
				comparer = structComparer[T]{
502
					path: path,
503
				}
504
				return (comparer).(icomparable[T]), nil
505
			default:
506
				return nil, errs.ErrUnsupportedType
507
			}
508
509
		} else {
510
			return nil, errs.ErrUnsupportedType
511
		}
512
	}
513
}
514
515
func copySlice[T any](src []T) []T {
516
	new := make([]T, len(src))
517
	copy(new, src)
518
	return new
519
}
520
521
func checkKind(k reflect.Kind, t reflect.Kind) bool {
522
	return k == t
523
}
524
525
func checkKindMultiple(k reflect.Kind, t ...reflect.Kind) bool {
526
	r := FindBy(t, func(val reflect.Kind) bool {
527
		return k == val
528
	})
529
	return r.String() == k.String()
530
}
531