Skip to content

Commit f043e3e

Browse files
authored
Add Selection Sort in M4 (#4968)
1 parent 0240654 commit f043e3e

File tree

1 file changed

+93
-0
lines changed

1 file changed

+93
-0
lines changed

archive/m/m4/selection-sort.m4

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
divert(-1)
2+
define(`show_usage',
3+
`Usage: please provide a list of at least two integers to sort in the format "1, 2, 3, 4, 5"
4+
m4exit(`1')')
5+
6+
dnl Reference: https://www.gnu.org/software/m4/manual/m4.html#index-array
7+
dnl array_get(var_name, idx)
8+
define(`array_get', `defn(format(``%s[%s]'', `$1', `$2'))')
9+
10+
dnl array_set(var_name, idx, value)
11+
define(`array_set', `define(format(``%s[%s]'', `$1', `$2'), `$3')')
12+
13+
dnl array_swap(var_name, idx1, idx2):
14+
dnl t = var_name[idx1]
15+
dnl var_name[idx1] = var_name[idx2]
16+
dnl var_name[idx] = t
17+
define(`array_swap',
18+
`pushdef(`t', array_get(`$1', `$2'))dnl
19+
array_set(`$1', `$2', array_get(`$1', `$3'))dnl
20+
array_set(`$1', `$3', t)dnl
21+
popdef(`t')'dnl
22+
)
23+
24+
dnl is_valid(n)
25+
define(`is_valid', `eval(regexp(`$1', `^\s*-?[0-9]+\s*$') >= 0)')
26+
27+
dnl parse_int_list(varname, args):
28+
dnl varname[length] = 0
29+
dnl foreach arg in args:
30+
dnl if not is_valid(arg):
31+
dnl Return 0
32+
dnl varname[varname[length]] = arg
33+
dnl varname[length] = varname[length] + 1
34+
dnl Return 1
35+
define(`parse_int_list',
36+
`array_set(`$1', `length', 0)dnl
37+
_parse_int_list(`$1', $2)'dnl
38+
)
39+
define(`_parse_int_list',
40+
`ifelse(is_valid(`$2'), 0, `0',
41+
`array_set(`$1', array_get(`$1', `length'), `$2')dnl
42+
array_set(`$1', `length', incr(array_get(`$1', `length')))dnl
43+
ifelse(eval($# > 2), 1, `_parse_int_list(`$1', shift(shift($@)))', `1')'dnl
44+
)'dnl
45+
)
46+
47+
dnl show_int_list(varname):
48+
dnl for i = 0 to n-1:
49+
dnl if i > 0:
50+
dnl Output ", "
51+
dnl Output varname[i]
52+
define(`show_int_list', `_show_int_list(`$1', 0)')
53+
define(`_show_int_list',
54+
`ifelse(eval($2 < array_get(`$1', `length')), 1,
55+
`ifelse(eval($2 > 0), 1, `, ')dnl
56+
array_get(`$1', $2)`'dnl
57+
_show_int_list(`$1', incr($2))'`'dnl
58+
)'dnl
59+
)
60+
61+
dnl Reference: https://en.wikipedia.org/wiki/Selection_sort#Implementations
62+
dnl selection_sort(varname):
63+
dnl n = varname[length]
64+
dnl for i = 0 to n-2:
65+
dnl jmin = i
66+
dnl for j = i+1 to n-1:
67+
dnl if varname[j] < varname[jmin]:
68+
dnl jmin = j
69+
dnl if jmin != i:
70+
dnl swap(varname, i, jmin)
71+
define(`selection_sort', `_selection_sort_outer(`$1', 0)')
72+
define(`_selection_sort_outer',
73+
`ifelse(eval($2 < decr(array_get(`$1', `length'))), 1,
74+
`_selection_sort_inner(`$1', `$2', incr($2), `$2')dnl
75+
_selection_sort_outer(`$1', incr($2))'dnl
76+
)'dnl
77+
)
78+
dnl varname=$1, i=$2, j=$3, jmin=$4
79+
define(`_selection_sort_inner',
80+
`ifelse(eval($3 >= array_get(`$1', `length')), 1,
81+
`ifelse(eval($4 != $2), 1, array_swap(`$1', `$2', `$4'))',
82+
`ifelse(eval(array_get(`$1', $3) < array_get(`$1', $4)), 1,
83+
`_selection_sort_inner(`$1', `$2', incr($3), `$3')',
84+
`_selection_sort_inner(`$1', `$2', incr($3), `$4')'dnl
85+
)'dnl
86+
)'dnl
87+
)
88+
89+
divert(0)dnl
90+
ifelse(eval(ARGC < 1 || len(ARGV1) < 1 || !parse_int_list(`arr', ARGV1)), 1, `show_usage()')dnl
91+
ifelse(eval(array_get(`arr', `length') < 2), 1, `show_usage()')dnl
92+
selection_sort(`arr')dnl
93+
show_int_list(`arr')

0 commit comments

Comments
 (0)