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 }