misc.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. // License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
  2. package utils
  3. import (
  4. "cmp"
  5. "fmt"
  6. "os"
  7. "path/filepath"
  8. "reflect"
  9. "runtime"
  10. "slices"
  11. "strconv"
  12. "strings"
  13. "sync"
  14. "golang.org/x/exp/constraints"
  15. )
  16. var _ = fmt.Print
  17. func Reverse[T any](s []T) []T {
  18. for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
  19. s[i], s[j] = s[j], s[i]
  20. }
  21. return s
  22. }
  23. func Reversed[T any](s []T) []T {
  24. ans := make([]T, len(s))
  25. for i, x := range s {
  26. ans[len(s)-1-i] = x
  27. }
  28. return ans
  29. }
  30. func Remove[T comparable](s []T, q T) []T {
  31. idx := slices.Index(s, q)
  32. if idx > -1 {
  33. var zero T
  34. s[idx] = zero // if pointer this allows garbage collection
  35. return slices.Delete(s, idx, idx+1)
  36. }
  37. return s
  38. }
  39. func RemoveAll[T comparable](s []T, q T) []T {
  40. ans := s
  41. for {
  42. idx := slices.Index(ans, q)
  43. if idx < 0 {
  44. break
  45. }
  46. ans = slices.Delete(ans, idx, idx+1)
  47. }
  48. return ans
  49. }
  50. func Filter[T any](s []T, f func(x T) bool) []T {
  51. ans := make([]T, 0, len(s))
  52. for _, x := range s {
  53. if f(x) {
  54. ans = append(ans, x)
  55. }
  56. }
  57. return ans
  58. }
  59. func Format_stacktrace_on_panic(r any) (text string, err error) {
  60. pcs := make([]uintptr, 512)
  61. n := runtime.Callers(3, pcs)
  62. lines := []string{}
  63. frames := runtime.CallersFrames(pcs[:n])
  64. err = fmt.Errorf("Panicked: %s", r)
  65. lines = append(lines, fmt.Sprintf("\r\nPanicked with error: %s\r\nStacktrace (most recent call first):\r\n", r))
  66. found_first_frame := false
  67. for frame, more := frames.Next(); more; frame, more = frames.Next() {
  68. if !found_first_frame {
  69. if strings.HasPrefix(frame.Function, "runtime.") {
  70. continue
  71. }
  72. found_first_frame = true
  73. }
  74. lines = append(lines, fmt.Sprintf("%s\r\n\t%s:%d\r\n", frame.Function, frame.File, frame.Line))
  75. }
  76. text = strings.Join(lines, "")
  77. return strings.TrimSpace(text), err
  78. }
  79. // Run the specified function in parallel over chunks from the specified range.
  80. // If the function panics, it is turned into a regular error.
  81. func Run_in_parallel_over_range(num_procs int, f func(int, int) error, start, limit int) (err error) {
  82. num_items := limit - start
  83. if num_procs <= 0 {
  84. num_procs = runtime.NumCPU()
  85. }
  86. num_procs = max(1, min(num_procs, num_items))
  87. if num_procs < 2 {
  88. defer func() {
  89. if r := recover(); r != nil {
  90. stacktrace, e := Format_stacktrace_on_panic(r)
  91. err = fmt.Errorf("%s\n\n%w", stacktrace, e)
  92. }
  93. }()
  94. return f(start, limit)
  95. }
  96. chunk_sz := max(1, num_items/num_procs)
  97. var wg sync.WaitGroup
  98. echan := make(chan error, num_procs)
  99. for start < limit {
  100. end := min(start+chunk_sz, limit)
  101. wg.Add(1)
  102. go func(start, end int) {
  103. defer func() {
  104. if r := recover(); r != nil {
  105. stacktrace, e := Format_stacktrace_on_panic(r)
  106. echan <- fmt.Errorf("%s\n\n%w", stacktrace, e)
  107. }
  108. wg.Done()
  109. }()
  110. if err := f(start, end); err != nil {
  111. echan <- err
  112. }
  113. }(start, end)
  114. start = end
  115. }
  116. wg.Wait()
  117. close(echan)
  118. for qerr := range echan {
  119. return qerr
  120. }
  121. return
  122. }
  123. func Map[T any, O any](f func(x T) O, s []T) []O {
  124. ans := make([]O, 0, len(s))
  125. for _, x := range s {
  126. ans = append(ans, f(x))
  127. }
  128. return ans
  129. }
  130. func Repeat[T any](x T, n int) []T {
  131. ans := make([]T, n)
  132. for i := range n {
  133. ans[i] = x
  134. }
  135. return ans
  136. }
  137. func Sort[T any](s []T, cmp func(a, b T) int) []T {
  138. slices.SortFunc(s, cmp)
  139. return s
  140. }
  141. func StableSort[T any](s []T, cmp func(a, b T) int) []T {
  142. slices.SortStableFunc(s, cmp)
  143. return s
  144. }
  145. func sort_with_key[T any, C constraints.Ordered](stable bool, s []T, key func(a T) C) []T {
  146. type t struct {
  147. key C
  148. val T
  149. }
  150. temp := make([]t, len(s))
  151. for i, x := range s {
  152. temp[i].val, temp[i].key = x, key(x)
  153. }
  154. key_cmp := func(a, b t) int {
  155. return cmp.Compare(a.key, b.key)
  156. }
  157. if stable {
  158. slices.SortStableFunc(temp, key_cmp)
  159. } else {
  160. slices.SortFunc(temp, key_cmp)
  161. }
  162. for i, x := range temp {
  163. s[i] = x.val
  164. }
  165. return s
  166. }
  167. func SortWithKey[T any, C constraints.Ordered](s []T, key func(a T) C) []T {
  168. return sort_with_key(false, s, key)
  169. }
  170. func StableSortWithKey[T any, C constraints.Ordered](s []T, key func(a T) C) []T {
  171. return sort_with_key(true, s, key)
  172. }
  173. func Max[T constraints.Ordered](a T, items ...T) (ans T) {
  174. ans = a
  175. for _, q := range items {
  176. if q > ans {
  177. ans = q
  178. }
  179. }
  180. return ans
  181. }
  182. func Min[T constraints.Ordered](a T, items ...T) (ans T) {
  183. ans = a
  184. for _, q := range items {
  185. if q < ans {
  186. ans = q
  187. }
  188. }
  189. return ans
  190. }
  191. func Memset[T any](dest []T, pattern ...T) []T {
  192. switch len(pattern) {
  193. case 0:
  194. var zero T
  195. switch any(zero).(type) {
  196. case byte: // special case this as the compiler can generate efficient code for memset of a byte slice to zero
  197. bd := any(dest).([]byte)
  198. for i := range bd {
  199. bd[i] = 0
  200. }
  201. default:
  202. for i := range dest {
  203. dest[i] = zero
  204. }
  205. }
  206. return dest
  207. case 1:
  208. val := pattern[0]
  209. for i := range dest {
  210. dest[i] = val
  211. }
  212. default:
  213. bp := copy(dest, pattern)
  214. for bp < len(dest) {
  215. copy(dest[bp:], dest[:bp])
  216. bp *= 2
  217. }
  218. }
  219. return dest
  220. }
  221. type statable interface {
  222. Stat() (os.FileInfo, error)
  223. }
  224. func Samefile(a, b any) bool {
  225. var sta, stb os.FileInfo
  226. var err error
  227. switch v := a.(type) {
  228. case string:
  229. sta, err = os.Stat(v)
  230. if err != nil {
  231. return false
  232. }
  233. case statable:
  234. sta, err = v.Stat()
  235. if err != nil {
  236. return false
  237. }
  238. case *os.FileInfo:
  239. sta = *v
  240. case os.FileInfo:
  241. sta = v
  242. default:
  243. panic(fmt.Sprintf("a must be a string, os.FileInfo or a stat-able object not %T", v))
  244. }
  245. switch v := b.(type) {
  246. case string:
  247. stb, err = os.Stat(v)
  248. if err != nil {
  249. return false
  250. }
  251. case statable:
  252. stb, err = v.Stat()
  253. if err != nil {
  254. return false
  255. }
  256. case *os.FileInfo:
  257. stb = *v
  258. case os.FileInfo:
  259. stb = v
  260. default:
  261. panic(fmt.Sprintf("b must be a string, os.FileInfo or a stat-able object not %T", v))
  262. }
  263. return os.SameFile(sta, stb)
  264. }
  265. func Concat[T any](slices ...[]T) []T {
  266. var total int
  267. for _, s := range slices {
  268. total += len(s)
  269. }
  270. result := make([]T, total)
  271. var i int
  272. for _, s := range slices {
  273. i += copy(result[i:], s)
  274. }
  275. return result
  276. }
  277. func ShiftLeft[T any](s []T, amt int) []T {
  278. leftover := len(s) - amt
  279. if leftover > 0 {
  280. copy(s, s[amt:])
  281. }
  282. return s[:leftover]
  283. }
  284. func SetStructDefaults(v reflect.Value) (err error) {
  285. for _, field := range reflect.VisibleFields(v.Type()) {
  286. if defval := field.Tag.Get("default"); defval != "" {
  287. val := v.FieldByIndex(field.Index)
  288. if val.CanSet() {
  289. switch field.Type.Kind() {
  290. case reflect.String:
  291. if val.String() != "" {
  292. val.SetString(defval)
  293. }
  294. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  295. if d, err := strconv.ParseInt(defval, 10, 64); err == nil {
  296. val.SetInt(d)
  297. } else {
  298. return fmt.Errorf("Could not parse default value for struct field: %#v with error: %s", field.Name, err)
  299. }
  300. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  301. if d, err := strconv.ParseUint(defval, 10, 64); err == nil {
  302. val.SetUint(d)
  303. } else {
  304. return fmt.Errorf("Could not parse default value for struct field: %#v with error: %s", field.Name, err)
  305. }
  306. }
  307. }
  308. }
  309. }
  310. return
  311. }
  312. func IfElse[T any](condition bool, if_val T, else_val T) T {
  313. if condition {
  314. return if_val
  315. }
  316. return else_val
  317. }
  318. func SourceLine(skip_frames ...int) int {
  319. s := 1
  320. if len(skip_frames) > 0 {
  321. s += skip_frames[0]
  322. }
  323. if _, _, ans, ok := runtime.Caller(s); ok {
  324. return ans
  325. }
  326. return -1
  327. }
  328. func SourceLoc(skip_frames ...int) string {
  329. s := 1
  330. if len(skip_frames) > 0 {
  331. s += skip_frames[0]
  332. }
  333. if _, file, line, ok := runtime.Caller(s); ok {
  334. return filepath.Base(file) + ":" + strconv.Itoa(line)
  335. }
  336. return "unknown"
  337. }
  338. func FunctionName(a any) string {
  339. if a == nil {
  340. return "<nil>"
  341. }
  342. p := reflect.ValueOf(a).Pointer()
  343. f := runtime.FuncForPC(p)
  344. if f != nil {
  345. return f.Name()
  346. }
  347. return ""
  348. }
  349. func Abs[T constraints.Integer](x T) T {
  350. if x < 0 {
  351. return -x
  352. }
  353. return x
  354. }