Mercurial > projects > mde
comparison mde/text/format.d @ 6:dcb24afa0dce
Some fixes from mde/text/format.d unittests plus a few more fixes.
committer: Diggory Hardy <diggory.hardy@gmail.com>
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Thu, 10 Jan 2008 18:33:24 +0000 |
parents | 9a990644948c |
children | b544c3a7c9ca |
comparison
equal
deleted
inserted
replaced
5:76d0adc92f2e | 6:dcb24afa0dce |
---|---|
58 ret[i-1] = ']'; // replaces last comma | 58 ret[i-1] = ']'; // replaces last comma |
59 return ret[0..i]; | 59 return ret[0..i]; |
60 } | 60 } |
61 unittest { | 61 unittest { |
62 char[] X = format!(char[][char]) (['a':cast(char[])"animal", 'b':['b','u','s']]); | 62 char[] X = format!(char[][char]) (['a':cast(char[])"animal", 'b':['b','u','s']]); |
63 char[] Y = `['a':"animal",'b':["bus"]]`; | 63 char[] Y = `['a':"animal",'b':"bus"]`; |
64 assert (X == Y); | 64 assert (X == Y); |
65 } | 65 } |
66 | 66 |
67 // Arrays | 67 // Arrays |
68 char[] format(T : T[]) (T[] val) { | 68 char[] format(T : T[]) (T[] val) { |
86 } | 86 } |
87 char[] format(T : wchar[]) (T val) { | 87 char[] format(T : wchar[]) (T val) { |
88 return format (toUtf8 (val)); | 88 return format (toUtf8 (val)); |
89 } | 89 } |
90 char[] format(T : char[]) (T val) { | 90 char[] format(T : char[]) (T val) { |
91 char[] ret; ret.length = val.length * 2 + 2; // Initial storage. This should ALWAYS be enough. | 91 char[] ret = new char[val.length * 2 + 2]; // Initial storage. This should ALWAYS be enough. |
92 ret[0] = '"'; | 92 ret[0] = '"'; |
93 uint i = 0; | 93 uint i = 1; |
94 for (uint t = 0; t < val.length;) { | 94 for (uint t = 0; t < val.length;) { |
95 // process a block of non-escapable characters | 95 // process a block of non-escapable characters |
96 uint s = t; | 96 uint s = t; |
97 while (t < val.length && !isEscapableChar(val[t])) | 97 while (t < val.length && !isEscapableChar(val[t])) |
98 ++t; // skip all non-escapable chars | 98 ++t; // skip all non-escapable chars |
109 return ret[0..i]; | 109 return ret[0..i]; |
110 } | 110 } |
111 char[] format(T : ubyte[]) (T val) { | 111 char[] format(T : ubyte[]) (T val) { |
112 static const char[16] digits = "0123456789abcdef"; | 112 static const char[16] digits = "0123456789abcdef"; |
113 | 113 |
114 char[val.length * 2] ret = void; // exact length | 114 char[] ret = new char[val.length * 2]; // exact length |
115 uint i = 0; | 115 uint i = 0; |
116 foreach (ubyte x; val) { | 116 foreach (ubyte x; val) { |
117 ret[i++] = digits[x >> 4]; | 117 ret[i++] = digits[x >> 4]; |
118 ret[i++] = digits[x & 0x0F]; | 118 ret[i++] = digits[x & 0x0F]; |
119 } | 119 } |
120 return ret; | 120 return ret; |
121 } | 121 } |
122 unittest { | 122 unittest { |
123 assert (format!(double[]) ([1.0, 1.0e-10]) == `[1,1e-10]`); // generic array stuff | 123 // generic array stuff: |
124 assert (format!(double[]) ([1.0, 1.0e-10]) == `[1.00000000000000000,0.10000000000000000e-09]`); | |
124 assert (format!(double[]) (cast(double[]) []) == `[]`); // empty array | 125 assert (format!(double[]) (cast(double[]) []) == `[]`); // empty array |
125 | 126 |
126 // char[] conversions, with commas, escape sequences and multichar UTF8 characters: | 127 // char[] conversions, with commas, escape sequences and multichar UTF8 characters: |
127 assert (format!(char[][]) ([ ".\""[], [',','\''] ,"!\b€" ]) == `[".\"",",\'","!\b€"]`); | 128 assert (format!(char[][]) ([ ".\""[], [',','\''] ,"!\b€" ]) == `[".\"",",\'","!\b€"]`); |
128 | 129 |
129 assert (format!(ubyte[]) (cast(ubyte[]) [0x01, 0xF2, 0xAC]) == `01F2AC`); // ubyte[] special notation | 130 assert (format!(ubyte[]) (cast(ubyte[]) [0x01, 0xF2, 0xAC]) == `01f2ac`); // ubyte[] special notation |
130 } | 131 } |
131 | 132 |
132 // Support for outputting a wide char... I reccomend against trying to output these though. | 133 // Support for outputting a wide char... I reccomend against trying to output these though. |
133 const char[] WIDE_CHAR_ERROR = "Error: unicode non-ascii character cannot be converted to a single UTF-8 char"; | 134 const char[] WIDE_CHAR_ERROR = "Error: unicode non-ascii character cannot be converted to a single UTF-8 char"; |
134 char[] format(T : dchar) (T val) { | 135 char[] format(T : dchar) (T val) { |
141 } | 142 } |
142 char[] format(T : char) (T val) { | 143 char[] format(T : char) (T val) { |
143 // Note: if (val > 127) "is invalid UTF-8 single char" | 144 // Note: if (val > 127) "is invalid UTF-8 single char" |
144 // However we don't know what this is for, in particular if it will be recombined with other chars later | 145 // However we don't know what this is for, in particular if it will be recombined with other chars later |
145 | 146 |
146 char[4] ret; // max length for an escaped char | 147 // Can't return reference to static array; making dynamic is cheaper than copying. |
148 char[] ret = new char[4]; // max length for an escaped char | |
147 ret[0] = '\''; | 149 ret[0] = '\''; |
148 | 150 |
149 if (!isEscapableChar (val)) { | 151 if (!isEscapableChar (val)) { |
150 ret[1] = val; | 152 ret[1] = val; |
151 ret[2] = '\''; | 153 ret[2] = '\''; |
157 return ret; | 159 return ret; |
158 } | 160 } |
159 assert (false); | 161 assert (false); |
160 } | 162 } |
161 unittest { | 163 unittest { |
162 assert (format!(char) ('\'') == '\''); | 164 assert (format!(char) ('\'') == "\'\\\'\'"); |
163 } | 165 } |
164 | 166 |
165 char[] format(T : bool) (T val) { | 167 char[] format(T : bool) (T val) { |
166 if (T) return "true"; | 168 if (T) return "true"; |
167 else return "false"; | 169 else return "false"; |
192 char[] format(T : ulong) (T val) { | 194 char[] format(T : ulong) (T val) { |
193 if (val > cast(ulong) long.max) throwException ("No handling available for ulong where value > long.max"); | 195 if (val > cast(ulong) long.max) throwException ("No handling available for ulong where value > long.max"); |
194 return formatLong (val); | 196 return formatLong (val); |
195 } | 197 } |
196 unittest { | 198 unittest { |
197 assert (format!(byte) (cast(byte) -5)) == "-5"; | 199 assert (format!(byte) (cast(byte) -5) == "-5"); |
198 // annoyingly, octal syntax differs from D (blame tango): | 200 // annoyingly, octal syntax differs from D (blame tango): |
199 assert (format!(uint[]) ([0b0100u,0724,0xFa59c,0xFFFFFFFF,0]) == "[0b100,0o724,0xFa59c,0xFFFFFFFF,0]"); | 201 assert (format!(uint[]) ([0b0100u,0724,0xFa59c,0xFFFFFFFF,0]) == "[4,468,1025436,4294967295,0]"); |
200 } | 202 } |
201 | 203 |
204 // Old calculation (not used): | |
205 // t.dig+2+4+3 // should be sufficient length (mant + (neg, dot, e, exp neg) + exp (3,4,5 for float,double,real resp.)) | |
202 char[] format(T : float) (T val) { | 206 char[] format(T : float) (T val) { |
203 // t.dig+2+4+3 // should be sufficient length (mant + (neg, dot, e, exp neg) + exp (3,4,5 for float,double,real resp.)) | 207 char[] ret = new char[32]; // minimum allowed by assert in format |
204 char[32] ret; // minimum allowed by assert in format | 208 return cFloat.format (ret, val, T.dig+2, 1); // from old C++ tests, T.dig+2 gives best(?) accuracy |
205 return cFloat.format (ret, val, T.dig+2, true); // from old C++ tests, T.dig+2 gives best(?) accuracy | |
206 } | 209 } |
207 char[] format(T : double) (T val) { | 210 char[] format(T : double) (T val) { |
208 char[32] ret; | 211 char[] ret = new char[32]; |
209 return cFloat.format (ret, val, T.dig+2, true); | 212 return cFloat.format (ret, val, T.dig+2, 1); |
210 } | 213 } |
211 char[] format(T : real) (T val) { | 214 char[] format(T : real) (T val) { |
212 char[32] ret; | 215 char[] ret = new char[32]; |
213 return cFloat.format (ret, val, T.dig+2, true); | 216 return cFloat.format (ret, val, T.dig+2, 1); |
214 } | 217 } |
215 unittest { | 218 unittest { |
216 assert (format!(float) (0.0f) == "0"); | 219 // NOTE: these numbers are not particularly meaningful. |
217 assert (format!(double) (-1e25) == "-1e25"); | 220 assert (format!(float) (0.0f) == "0.00000000"); |
218 assert (format!(real) (cast(real) 5.24e-269) == "5.24e-269"); | 221 assert (format!(double) (-1e25) == "-1.00000000000000000e+25"); |
222 assert (format!(real) (cast(real) 4.918e300) == "4.91800000000000000000e+300"); | |
219 } | 223 } |
220 //END Convert templates | 224 //END Convert templates |
221 | 225 |
222 //BEGIN Length templates | 226 //BEGIN Length templates |
223 /* This template provides the initial length for strings for formatting various types. These strings | 227 /* This template provides the initial length for strings for formatting various types. These strings |
229 } | 233 } |
230 //END Length templates | 234 //END Length templates |
231 | 235 |
232 //BEGIN Utility funcs | 236 //BEGIN Utility funcs |
233 private char[] formatLong (long val) { | 237 private char[] formatLong (long val) { |
234 try return cInt.toString (val, cInt.Style.Unsigned, cInt.Flags.Throw); | 238 try return cInt.toString (val, cInt.Style.Signed, cInt.Flags.Throw); |
235 catch (Exception e) throwException (e.msg); | 239 catch (Exception e) throwException (e.msg); |
236 } | 240 } |
237 private bool isEscapableChar (char c) { | 241 private bool isEscapableChar (char c) { |
238 return ((c <= '\r' && c >= '\a') || c == '\"' || c == '\'' || c == '\\'); | 242 return ((c <= '\r' && c >= '\a') || c == '\"' || c == '\'' || c == '\\'); |
239 } | 243 } |