Changeset 1751
- Timestamp:
- 07/12/10 01:17:37 (14 years ago)
- Files:
-
- trunk/phobos/std/format.d (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/phobos/std/format.d
r1748 r1751 808 808 "\ntrailing = ", trailing, "\n"); 809 809 } 810 810 } 811 811 812 812 /** 813 813 $(D void[]) is formatted like $(D ubyte[]). 814 814 */ 815 815 void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!Char f) 816 816 if (is(const(T) == const(void[]))) 817 817 { 818 w.put(cast(const ubyte[]) val);818 put(w, cast(const ubyte[]) val); 819 819 } 820 820 821 821 unittest 822 822 { 823 823 FormatSpec!char f; 824 824 auto a = appender!string(); 825 825 void[] val; 826 826 formatValue(a, val, f); 827 827 } 828 828 … … 849 849 Unqual!T arg = val; 850 850 if (f.spec == 'r') 851 851 { 852 852 // raw write, skip all else and write the thing 853 853 auto begin = cast(const char*) &arg; 854 854 if (std.system.endian == Endian.LittleEndian && f.flPlus 855 855 || std.system.endian == Endian.BigEndian && f.flDash) 856 856 { 857 857 // must swap bytes 858 858 foreach_reverse (i; 0 .. arg.sizeof) 859 w.put(begin[i]);859 put(w, begin[i]); 860 860 } 861 861 else 862 862 { 863 863 foreach (i; 0 .. arg.sizeof) 864 w.put(begin[i]);864 put(w, begin[i]); 865 865 } 866 866 return; 867 867 } 868 868 if (f.precision == f.UNSPECIFIED) 869 869 { 870 870 // default precision for integrals is 1 871 871 f.precision = 1; 872 872 } 873 873 else 874 874 { … … 916 916 { 917 917 --i; 918 918 buffer[i] = cast(char) (n % base); 919 919 n /= base; 920 920 if (buffer[i] < 10) buffer[i] += '0'; 921 921 else buffer[i] += (f.spec == 'x' ? 'a' : 'A') - 10; 922 922 } while (n); 923 923 digits = buffer[i .. $]; // got the digits without the sign 924 924 } 925 925 // adjust precision to print a '0' for octal if alternate format is on 926 if (base == 8 && f.flHash ()926 if (base == 8 && f.flHash 927 927 && (f.precision <= digits.length)) // too low precision 928 928 { 929 929 //f.precision = digits.length + (arg != 0); 930 930 forcedPrefix = '0'; 931 931 } 932 932 // write left pad; write sign; write 0x or 0X; write digits; 933 933 // write right pad 934 934 // Writing left pad 935 935 int spacesToPrint = 936 936 f.width // start with the minimum width 937 937 - digits.length // take away digits to print 938 938 - (forcedPrefix != 0) // take away the sign if any 939 - (base == 16 && f.flHash ()&& arg ? 2 : 0); // 0x or 0X939 - (base == 16 && f.flHash && arg ? 2 : 0); // 0x or 0X 940 940 const int delta = f.precision - digits.length; 941 941 if (delta > 0) spacesToPrint -= delta; 942 942 //writeln(spacesToPrint); 943 943 if (spacesToPrint > 0) // need to do some padding 944 944 { 945 945 if (leftPad == '0') 946 946 { 947 947 // pad with zeros 948 948 f.precision = 949 949 cast(typeof(f.precision)) (spacesToPrint + digits.length); 950 950 //to!(typeof(f.precision))(spacesToPrint + digits.length); 951 951 } 952 else if (leftPad) foreach (i ; 0 .. spacesToPrint) w.put(' ');952 else if (leftPad) foreach (i ; 0 .. spacesToPrint) put(w, ' '); 953 953 } 954 954 // write sign 955 if (forcedPrefix) w.put(forcedPrefix);955 if (forcedPrefix) put(w, forcedPrefix); 956 956 // write 0x or 0X 957 if (base == 16 && f.flHash ()&& arg) {957 if (base == 16 && f.flHash && arg) { 958 958 // @@@ overcome bug in dmd; 959 959 //w.write(f.spec == 'x' ? "0x" : "0X"); //crashes the compiler 960 w.put('0');961 w.put(f.spec == 'x' ? 'x' : 'X'); // x or X960 put(w, '0'); 961 put(w, f.spec == 'x' ? 'x' : 'X'); // x or X 962 962 } 963 963 // write the digits 964 964 if (arg || f.precision) 965 965 { 966 966 int zerosToPrint = f.precision - digits.length; 967 foreach (i ; 0 .. zerosToPrint) w.put('0');968 w.put(digits);967 foreach (i ; 0 .. zerosToPrint) put(w, '0'); 968 put(w, digits); 969 969 } 970 970 // write the spaces to the right if left-align 971 if (!leftPad) foreach (i ; 0 .. spacesToPrint) w.put(' ');971 if (!leftPad) foreach (i ; 0 .. spacesToPrint) put(w, ' '); 972 972 } 973 973 974 974 /** 975 975 * Floating-point values are formatted like $(D printf) does. 976 976 */ 977 977 void formatValue(Writer, D, Char)(Writer w, D obj, 978 978 ref FormatSpec!Char f) 979 979 if (isFloatingPoint!D) 980 980 { 981 981 if (f.spec == 'r') 982 982 { 983 983 // raw write, skip all else and write the thing 984 984 auto begin = cast(const char*) &obj; 985 985 if (std.system.endian == Endian.LittleEndian && f.flPlus 986 986 || std.system.endian == Endian.BigEndian && f.flDash) 987 987 { 988 988 // must swap bytes 989 989 foreach_reverse (i; 0 .. obj.sizeof) 990 w.put(begin[i]);990 put(w, begin[i]); 991 991 } 992 992 else 993 993 { 994 994 foreach (i; 0 .. obj.sizeof) 995 w.put(begin[i]);995 put(w, begin[i]); 996 996 } 997 997 return; 998 998 } 999 999 if (std.string.indexOf("fgFGaAeEs", f.spec) < 0) { 1000 1000 throw new FormatError("floating"); 1001 1001 } 1002 1002 if (f.spec == 's') f.spec = 'g'; 1003 1003 char sprintfSpec[1 /*%*/ + 5 /*flags*/ + 3 /*width.prec*/ + 2 /*format*/ 1004 1004 + 1 /*\0*/] = void; 1005 1005 sprintfSpec[0] = '%'; … … 1017 1017 //printf("format: '%s'; geeba: %g\n", sprintfSpec.ptr, obj); 1018 1018 char[512] buf; 1019 1019 //writeln("Spec is: ", sprintfSpec); 1020 1020 immutable n = snprintf(buf.ptr, buf.length, 1021 1021 sprintfSpec.ptr, 1022 1022 f.width, 1023 1023 // negative precision is same as no precision specified 1024 1024 f.precision == f.UNSPECIFIED ? -1 : f.precision, 1025 1025 obj); 1026 1026 if (n < 0) throw new FormatError("floating point formatting failure"); 1027 w.put(buf[0 .. strlen(buf.ptr)]);1027 put(w, buf[0 .. strlen(buf.ptr)]); 1028 1028 } 1029 1029 1030 1030 unittest 1031 1031 { 1032 1032 auto a = appender!(string)(); 1033 1033 immutable real x = 5.5; 1034 1034 FormatSpec!char f; 1035 1035 formatValue(a, x, f); 1036 1036 assert(a.data == "5.5"); 1037 1037 } 1038 1038 1039 1039 /** 1040 1040 $(D bool) is formatted as "true" or "false" with %s and as "1" or 1041 1041 "0" with integral-specific format specs. 1042 1042 */ 1043 1043 void formatValue(Writer, T, Char)(Writer w, T val, 1044 1044 ref FormatSpec!Char f) 1045 1045 if (is(T : bool)) 1046 1046 { 1047 1047 if (f.spec == 's') { 1048 w.put(val ? "true" : "false");1048 put(w, val ? "true" : "false"); 1049 1049 } else { 1050 1050 formatValue(w, cast(int) val, f); 1051 1051 } 1052 1052 } 1053 1053 1054 1054 /** 1055 1055 Individual characters ($(D char), $(D wchar), or $(D dchar)) are 1056 1056 formatted as Unicode characters with %s and as integers with 1057 1057 integral-specific format specs. 1058 1058 */ 1059 1059 void formatValue(Writer, T, Char)(Writer w, T val, 1060 1060 ref FormatSpec!Char f) 1061 1061 if (isSomeChar!T) 1062 1062 { 1063 1063 if (f.spec == 's') { 1064 w.put(val);1064 put(w, val); 1065 1065 } else { 1066 1066 formatValue(w, cast(uint) val, f); 1067 1067 } 1068 1068 } 1069 1069 1070 1070 /** 1071 1071 Strings are formatted like printf does. 1072 1072 */ 1073 1073 void formatValue(Writer, T, Char)(Writer w, T val, 1074 1074 ref FormatSpec!Char f) 1075 1075 if (isSomeString!T && !isStaticArray!T) 1076 1076 { 1077 1077 auto s = val[0 .. f.precision < $ ? f.precision : $]; 1078 1078 if (!f.flDash) 1079 1079 { 1080 1080 // right align 1081 1081 if (f.width > s.length) 1082 foreach (i ; 0 .. f.width - s.length) w.put(' ');1083 w.put(s);1082 foreach (i ; 0 .. f.width - s.length) put(w, ' '); 1083 put(w, s); 1084 1084 } 1085 1085 else 1086 1086 { 1087 1087 // left align 1088 w.put(s);1088 put(w, s); 1089 1089 if (f.width > s.length) 1090 foreach (i ; 0 .. f.width - s.length) w.put(' ');1090 foreach (i ; 0 .. f.width - s.length) put(w, ' '); 1091 1091 } 1092 1092 } 1093 1093 1094 1094 /** 1095 1095 Input ranges are formatted like arrays. 1096 1096 */ 1097 1097 void formatValue(Writer, T, Char)(Writer w, T val, 1098 1098 ref FormatSpec!Char f) 1099 1099 if (isInputRange!T && !isSomeChar!(ElementType!T)) 1100 1100 { … … 1114 1114 formatValue(w, arr.front, f); 1115 1115 } 1116 1116 } 1117 1117 } 1118 1118 else 1119 1119 { 1120 1120 if (arr.empty) return; 1121 1121 // formatted writes 1122 1122 if (!f.nested) 1123 1123 { 1124 w.put(f.seqBefore);1125 scope(exit) w.put(f.seqAfter);1124 put(w, f.seqBefore); 1125 scope(exit) put(w, f.seqAfter); 1126 1126 formatValue(w, arr.front, f); 1127 1127 arr.popFront(); 1128 1128 for (size_t i; !arr.empty; arr.popFront(), ++i) 1129 1129 { 1130 w.put(f.seqSeparator);1130 put(w, f.seqSeparator); 1131 1131 formatValue(w, arr.front, f); 1132 1132 } 1133 1133 } 1134 1134 else 1135 1135 { 1136 1136 // Nested specifier is to be used 1137 1137 for (;;) 1138 1138 { 1139 1139 auto f = FormatSpec!Char(f.nested); 1140 1140 f.writeUpToNextSpec(w); … … 1159 1159 // itemFormatString = itemFormatString[i .. $]; 1160 1160 // auto itemFmt = FormatSpec(itemFormatString); 1161 1161 // auto tail = itemFormatString; 1162 1162 // for (;;) 1163 1163 // { 1164 1164 // auto headCopy = head; 1165 1165 // writeUpToFormatSpec(w, headCopy); 1166 1166 // formatValue(w, arr.front, itemFmt); 1167 1167 // arr.popFront(); 1168 1168 // if (arr.empty) break; 1169 // w.put(tail);1169 // put(w, tail); 1170 1170 // } 1171 1171 } 1172 1172 } 1173 1173 } 1174 1174 1175 1175 /** 1176 1176 $(D void[0]) is formatted as "[]". 1177 1177 */ 1178 1178 void formatValue(Writer, T, Char)(Writer w, T val, 1179 1179 ref FormatSpec!Char f) 1180 1180 if (is(D == void[0])) 1181 1181 { 1182 w.put(seqBefore);1183 w.put(seqAfter);1182 put(w, seqBefore); 1183 put(w, seqAfter); 1184 1184 } 1185 1185 1186 1186 /** 1187 1187 Pointers are formatted as hex integers. 1188 1188 */ 1189 1189 void formatValue(Writer, T, Char)(Writer w, T val, 1190 1190 ref FormatSpec!Char f) 1191 1191 if (isPointer!T) 1192 1192 { 1193 1193 const void * p = val; … … 1195 1195 formatValue(w, cast(ulong) p, f); 1196 1196 } 1197 1197 1198 1198 /** 1199 1199 Objects are formatted by calling $(D toString). 1200 1200 */ 1201 1201 void formatValue(Writer, T, Char)(Writer w, T val, 1202 1202 ref FormatSpec!Char f) 1203 1203 if (is(T == class)) 1204 1204 { 1205 if (val is null) w.put("null");1206 else w.put(val.toString);1205 if (val is null) put(w, "null"); 1206 else put(w, val.toString); 1207 1207 } 1208 1208 1209 1209 /** 1210 1210 Associative arrays are formatted by using $(D ':') and $(D ' ') as 1211 1211 separators. 1212 1212 */ 1213 1213 void formatValue(Writer, T, Char)(Writer w, T val, 1214 1214 ref FormatSpec!Char f) 1215 1215 if (isAssociativeArray!T) 1216 1216 { 1217 1217 bool firstTime = true; 1218 1218 foreach (ref k, v; val) 1219 1219 { 1220 1220 if (firstTime) firstTime = false; 1221 else w.put(' ');1221 else put(w, ' '); 1222 1222 formatValue(w, k, f); 1223 w.put(':');1223 put(w, ':'); 1224 1224 formatValue(w, v, f); 1225 1225 } 1226 1226 } 1227 1227 1228 1228 /** 1229 1229 Associative arrays are formatted by using $(D ':') and $(D ' ') as 1230 1230 separators. 1231 1231 */ 1232 1232 void formatValue(Writer, T, Char)(Writer w, T val, 1233 1233 ref FormatSpec!Char f) 1234 1234 if (is(T == struct) && !isInputRange!T) 1235 1235 { 1236 if (is(typeof( w.put(val.toString))))1237 { 1238 w.put(val.toString);1236 if (is(typeof(put(w, val.toString)))) 1237 { 1238 put(w, val.toString); 1239 1239 } 1240 1240 else 1241 1241 { 1242 w.put(S.stringof);1242 put(w, S.stringof); 1243 1243 } 1244 1244 } 1245 1245 1246 1246 /** 1247 1247 Static-size arrays are formatted just like arrays. 1248 1248 */ 1249 1249 void formatValue(Writer, T, Char)(Writer w, ref T val, 1250 1250 ref FormatSpec!Char f) 1251 1251 if (isStaticArray!T) 1252 1252 {
