-
Notifications
You must be signed in to change notification settings - Fork 7
/
random-image-v31.diff
84 lines (80 loc) · 2.43 KB
/
random-image-v31.diff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
diff --git a/commands.c b/commands.c
index a4ae38d..3798d38 100644
--- a/commands.c
+++ b/commands.c
@@ -476,3 +476,35 @@ bool ct_select(arg_t _)
return dirty;
}
+
+/*
+ * NOTE(NRK): could be faster with __builtin_clz(), but i've opted for portibility instead.
+ * ref: https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ */
+static unsigned int next_power_of_2_modmask(unsigned int v)
+{
+ --v;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ return v;
+}
+
+/*
+ * rejects any baised samples with the bitmask approach described in:
+ * https://www.pcg-random.org/posts/bounded-rands.html
+ */
+bool cg_random(arg_t _)
+{
+ if (filecnt >= 2) {
+ int n;
+ unsigned int mask = next_power_of_2_modmask(filecnt);
+ do {
+ n = rand() & mask;
+ } while (n >= filecnt || n == fileidx);
+ return navigate_to(n);
+ }
+ return false;
+}
diff --git a/commands.h b/commands.h
index 76b1330..82e2aef 100644
--- a/commands.h
+++ b/commands.h
@@ -22,6 +22,7 @@ bool cg_toggle_fullscreen(arg_t);
bool cg_toggle_image_mark(arg_t);
bool cg_unmark_all(arg_t);
bool cg_zoom(arg_t);
+bool cg_random(arg_t);
/* image mode */
bool ci_alternate(arg_t);
bool ci_cursor_navigate(arg_t);
@@ -67,6 +68,7 @@ bool ct_select(arg_t);
#define g_toggle_image_mark { cg_toggle_image_mark, MODE_ALL }
#define g_unmark_all { cg_unmark_all, MODE_ALL }
#define g_zoom { cg_zoom, MODE_ALL }
+#define g_random { cg_random, MODE_ALL }
/* image mode */
#define i_alternate { ci_alternate, MODE_IMAGE }
diff --git a/config.def.h b/config.def.h
index a0935f6..610b79c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -98,6 +98,7 @@ static const keymap_t keys[] = {
{ ControlMask, XK_x, g_prefix_external, None },
{ 0, XK_g, g_first, None },
{ 0, XK_G, g_n_or_last, None },
+ { ControlMask, XK_r, g_random, None },
{ 0, XK_r, g_reload_image, None },
{ 0, XK_D, g_remove_image, None },
{ ControlMask, XK_h, g_scroll_screen, DIR_LEFT },
diff --git a/main.c b/main.c
index eed945c..04ceb9e 100644
--- a/main.c
+++ b/main.c
@@ -863,6 +863,7 @@ int main(int argc, char *argv[])
setup_signal(SIGCHLD, SIG_DFL, SA_RESTART|SA_NOCLDSTOP|SA_NOCLDWAIT);
setup_signal(SIGPIPE, SIG_IGN, 0);
+ srand(time(NULL));
setlocale(LC_COLLATE, "");
parse_options(argc, argv);