github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/stdlib/table/sort.go (about) 1 package table 2 3 import ( 4 "github.com/hirochachacha/plua/internal/arith" 5 "github.com/hirochachacha/plua/internal/limits" 6 "github.com/hirochachacha/plua/object" 7 "github.com/hirochachacha/plua/object/fnutil" 8 ) 9 10 func sort(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 11 ap := fnutil.NewArgParser(th, args) 12 13 t, err := ap.ToTable(0) 14 if err != nil { 15 return nil, err 16 } 17 18 var lt object.Value 19 20 if len(args) > 1 { 21 lt, err = ap.ToFunctionOrNil(1) 22 if err != nil { 23 return nil, err 24 } 25 } 26 27 tlen, err := callLen(th, t) 28 if err != nil { 29 return nil, err 30 } 31 32 if tlen >= int(limits.MaxInt) { 33 return nil, ap.ArgError(0, "array too big") 34 } 35 36 err = quickSort(th, t, lt, 1, tlen) 37 if err != nil { 38 return nil, err 39 } 40 41 return nil, nil 42 } 43 44 func quickSort(th object.Thread, t object.Table, lt object.Value, lo, hi int) *object.RuntimeError { 45 if lo < hi { 46 p, err := partition(th, t, lt, lo, hi) 47 if err != nil { 48 return err 49 } 50 err = quickSort(th, t, lt, lo, p) 51 if err != nil { 52 return err 53 } 54 err = quickSort(th, t, lt, p+1, hi) 55 if err != nil { 56 return err 57 } 58 } 59 return nil 60 } 61 62 func partition(th object.Thread, t object.Table, lt object.Value, lo, hi int) (int, *object.RuntimeError) { 63 pivot, err := arith.CallGettable(th, t, object.Integer(lo)) 64 if err != nil { 65 return 0, err 66 } 67 68 i := lo - 1 69 j := hi + 1 70 71 var xi, xj object.Value 72 73 for { 74 for { 75 i++ 76 xi, err = arith.CallGettable(th, t, object.Integer(i)) 77 if err != nil { 78 return 0, err 79 } 80 b, err := callLessThan(th, lt, xi, pivot) 81 if err != nil { 82 return 0, err 83 } 84 if !b { 85 break 86 } 87 if i == hi { 88 return 0, object.NewRuntimeError("invalid order function for sorting") 89 } 90 } 91 for { 92 j-- 93 xj, err = arith.CallGettable(th, t, object.Integer(j)) 94 if err != nil { 95 return 0, err 96 } 97 b, err := callLessThan(th, lt, pivot, xj) 98 if err != nil { 99 return 0, err 100 } 101 if !b { 102 break 103 } 104 if j < i { 105 return 0, object.NewRuntimeError("invalid order function for sorting") 106 } 107 } 108 if i >= j { 109 return j, nil 110 } 111 err = tabSwap(th, t, i, j) 112 if err != nil { 113 return 0, err 114 } 115 } 116 } 117 118 func tabSwap(th object.Thread, t object.Table, i, j int) *object.RuntimeError { 119 x, err := arith.CallGettable(th, t, object.Integer(i)) 120 if err != nil { 121 return err 122 } 123 y, err := arith.CallGettable(th, t, object.Integer(j)) 124 if err != nil { 125 return err 126 } 127 err = arith.CallSettable(th, t, object.Integer(j), x) 128 if err != nil { 129 return err 130 } 131 err = arith.CallSettable(th, t, object.Integer(i), y) 132 if err != nil { 133 return err 134 } 135 return nil 136 } 137 138 func callLessThan(th object.Thread, lt, x, y object.Value) (bool, *object.RuntimeError) { 139 if lt == nil { 140 b, err := arith.CallLessThan(th, false, x, y) 141 if err != nil { 142 return false, err 143 } 144 145 return b, nil 146 } 147 148 rets, err := th.Call(lt, x, y) 149 if err != nil { 150 return false, err 151 } 152 if len(rets) == 0 { 153 return false, nil 154 } 155 return object.ToGoBool(rets[0]), nil 156 }