1 /**
2  Only exists to test the wrapping functionality Contains functions
3  with regular D types that will get wrapped so they can be called by
4  the spreadsheet.
5  */
6 
7 module xlld.test_d_funcs;
8 
9 version(unittest):
10 
11 import xlld;
12 
13 
14 @Register(ArgumentText("Array to add"),
15           HelpTopic("Adds all cells in an array"),
16           FunctionHelp("Adds all cells in an array"),
17           ArgumentHelp(["The array to add"]))
18 double FuncAddEverything(double[][] args) nothrow @nogc {
19     import std.algorithm: fold;
20     import std.math: isNaN;
21 
22     double ret = 0;
23     foreach(row; args)
24         ret += row.fold!((a, b) => b.isNaN ? 0.0 : a + b)(0.0);
25     return ret;
26 }
27 
28 double[][] FuncTripleEverything(double[][] args) nothrow {
29     double[][] ret;
30     ret.length = args.length;
31     foreach(i; 0 .. args.length) {
32         ret[i].length = args[i].length;
33         foreach(j; 0 .. args[i].length)
34             ret[i][j] = args[i][j] * 3;
35     }
36 
37     return ret;
38 }
39 
40 double FuncAllLengths(string[][] args) nothrow @nogc {
41     import std.algorithm: fold;
42 
43     double ret = 0;
44     foreach(row; args)
45         ret += row.fold!((a, b) => a + b.length)(0.0);
46     return ret;
47 }
48 
49 double[][] FuncLengths(string[][] args) nothrow {
50     double[][] ret;
51 
52     ret.length = args.length;
53     foreach(i; 0 .. args.length) {
54         ret[i].length = args[i].length;
55         foreach(j; 0 .. args[i].length)
56             ret[i][j] = args[i][j].length;
57     }
58 
59     return ret;
60 }
61 
62 
63 string[][] FuncBob(string[][] args) nothrow {
64     string[][] ret;
65 
66     ret.length = args.length;
67     foreach(i; 0 .. args.length) {
68         ret[i].length = args[i].length;
69         foreach(j; 0 .. args[i].length)
70             ret[i][j] = args[i][j] ~ "bob";
71     }
72 
73     return ret;
74 }
75 
76 
77 double FuncDoubleSlice(double[] arg) nothrow @nogc {
78     return arg.length;
79 }
80 
81 double FuncStringSlice(string[] arg) nothrow @nogc {
82     return arg.length;
83 }
84 
85 double[] FuncSliceTimes3(double[] arg) nothrow {
86     import std.algorithm;
87     import std.array;
88     return arg.map!(a => a * 3).array;
89 }
90 
91 string[] StringsToStrings(string[] args) nothrow {
92     import std.algorithm;
93     import std.array;
94     return args.map!(a => a ~ "foo").array;
95 }
96 
97 string StringsToString(string[] args) nothrow {
98     import std.string;
99     return args.join(", ");
100 }
101 
102 string StringToString(string arg) nothrow {
103     return arg ~ "bar";
104 }
105 
106 private string shouldNotBeAProblem(string, string[]) nothrow {
107     return "";
108 }
109 
110 string ManyToString(string arg0, string arg1, string arg2) nothrow {
111     return arg0 ~ arg1 ~ arg2;
112 }
113 
114 // shouldn't get wrapped
115 double FuncThrows(double) {
116     throw new Exception("oops");
117 }
118 
119 
120 // @Dispose is used to tell the framework how to free memory that is dynamically
121 // allocated by the D function. After returning, the value is converted to an
122 // Excel type sand the D value is freed using the lambda defined here.
123 // In this example we're using TestAllocator to make sure that there are no
124 // memory leaks.
125 @Dispose!((ret) {
126     import xlld.test_util: gTestAllocator;
127     import std.experimental.allocator: dispose;
128     gTestAllocator.dispose(ret);
129 })
130 double[] FuncReturnArrayNoGc(double[] numbers) @nogc @safe nothrow {
131     import xlld.test_util: gTestAllocator;
132     import std.experimental.allocator: makeArray;
133     import std.algorithm: map;
134 
135     try {
136         return () @trusted { return gTestAllocator.makeArray(numbers.map!(a => a * 2)); }();
137     } catch(Exception _) {
138         return [];
139     }
140 }
141 
142 
143 Any[][] DoubleArrayToAnyArray(double[][] values) @safe nothrow {
144     import std.experimental.allocator.mallocator: Mallocator;
145     import std.conv: to;
146 
147     alias allocator = Mallocator.instance;
148 
149     string third, fourth;
150     try {
151         third = values[1][0].to!string;
152         fourth = values[1][1].to!string;
153     } catch(Exception ex) {
154         third = "oops";
155         fourth = "oops";
156     }
157 
158     return () @trusted {
159         with(allocatorContext(allocator)) {
160             try
161                 return [
162                     [any(values[0][0] * 2), any(values[0][1] * 3)],
163                     [any(third ~ "quux"),   any(fourth ~ "toto")],
164                 ];
165             catch(Exception _) {
166                 Any[][] empty;
167                 return empty;
168             }
169         }
170     }();
171 }
172 
173 
174 double[] AnyArrayToDoubleArray(Any[][] values) nothrow {
175     return [values.length, values.length ? values[0].length : 0];
176 }
177 
178 
179 Any[][] AnyArrayToAnyArray(Any[][] values) nothrow {
180     return values;
181 }
182 
183 Any[][] FirstOfTwoAnyArrays(Any[][] a, Any[][]) nothrow {
184     return a;
185 }
186 
187 string[] EmptyStrings1D(Any) nothrow {
188     string[] empty;
189     return empty;
190 }
191 
192 
193 string[][] EmptyStrings2D(Any) nothrow {
194     string[][] empty;
195     return empty;
196 }
197 
198 string[][] EmptyStringsHalfEmpty2D(Any) nothrow {
199     string[][] empty;
200     empty.length = 1;
201     assert(empty[0].length == 0);
202     return empty;
203 }
204 
205 int Twice(int i) @safe nothrow {
206     return i * 2;
207 }