1 module nxt.show;
2 
3 import nxt.algorithm_ex: overlap;
4 
5 /** Show Format. */
6 enum Format { Text, HTML, };
7 
8 @trusted void browse(Args...)(string[] names, inout (Args) args) {
9     return fshow(Format.HTML, names, args);
10 }
11 @trusted void show(Args...)(string[] names, inout (Args) args) {
12     return fshow(Format.Text, names, args);
13 }
14 
15 /** Group-Aligned Show of Slices `args`.
16 
17     Copyright: Per Nordlöw 2014-.
18     License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
19     Authors: $(WEB Per Nordlöw)
20 
21     Use as debug print in algorithms where we need to present slices and their
22     relations.
23 
24     TODO Calculate `names` from `args` or `args` from `names` using Mixins.
25     TODO Generalize to Ranges other than slices!?
26     TODO Support HTML
27 */
28 @trusted void fshow(Args...)(Format format, string[] names, inout (Args) args)
29 {
30     import std.stdio: wr = write, wrln = writeln;
31     import std.algorithm: map, reduce, min, max;
32     import std.range : repeat, join;
33     import std.string: leftJustify, rightJustify;
34     import std.conv: to;
35 
36     // determine overlap
37     static if (args.length == 2) {
38         const a01 = overlap(args[0], args[1]);
39     }
40 
41     // maximum variable name length
42     const namesLengthMax = names.map!"a.length".reduce!max;
43 
44     // smallest slice pointer
45     static if (true) { // if all args of same type
46     }
47     static if (args.length == 2) { auto unionPtr = min(args[0].ptr, args[1].ptr); }
48     static if (args.length == 3) { auto unionPtr = min(args[0].ptr, args[1].ptr, args[2].ptr); }
49     static if (args.length == 4) { auto unionPtr = min(args[0].ptr, args[1].ptr, args[2].ptr, args[3].ptr); }
50 
51     // calculate maximum length of number
52     auto elementLengthMax = size_t.min;
53     size_t[][args.length] elementOffsets; // element offsets
54     string[][args.length] elementStrings_;
55     foreach (ix, arg; args) {
56         auto elementStrings = arg.map!(to!string); // calculate lengths of elements as strings
57         elementLengthMax = elementStrings.map!"a.length".reduce!max; // length of longest number as string
58         elementOffsets[ix] = new size_t[arg.length];
59     }
60 
61     // print arguments
62     foreach (ix, arg; args) { // for each argument
63         enum sep = ", ";      // separator
64         const off = arg.ptr - unionPtr; // offset
65         wr(names[ix].leftJustify(namesLengthMax), ": "); // name header
66         if (off) {
67             wr(" ".repeat(1 + (off + 1) * sep.length +
68                           off * namesLengthMax).join);
69         }
70         foreach (elt; arg) {
71             wr(to!string(elt).rightJustify(namesLengthMax), sep);
72         }
73         wrln("");
74     }
75 
76     // print overlaps
77     static if (args.length == 2) {
78         /* wrln("overlap(", names[0], ",", names[1], "): ", a01); */
79     }
80     static if (args.length == 3) {
81         foreach (i, arg; args) {
82             enum j = (i+1) % args.length;
83             /* wrln("overlap(" ~ names[i].leftJustify(namesLengthMax) ~ ", " ~ names[j].leftJustify(namesLengthMax) ~ "): ", overlap(args[i], args[j])); */
84         }
85     }
86     wrln("");
87 }
88 unittest {
89     auto x = [-11111, -11, 22, 333333];
90 
91     auto x01 = x[0..1];
92     auto x12 = x[1..2];
93     auto x23 = x[2..3];
94     auto x34 = x[3..4];
95 
96     show(["x12", "x"], x12, x);
97     show(["x", "x12"], x, x12);
98     show(["x", "x12", "x23"], x, x12, x23);
99     show(["x", "x23", "x12", "x34"], x, x23, x12, x34);
100 }