00001 /******************************************************************************* 00002 00003 @file Sprint.d 00004 00005 Copyright (c) 2004 Kris Bell 00006 00007 This software is provided 'as-is', without any express or implied 00008 warranty. In no event will the authors be held liable for damages 00009 of any kind arising from the use of this software. 00010 00011 Permission is hereby granted to anyone to use this software for any 00012 purpose, including commercial applications, and to alter it and/or 00013 redistribute it freely, subject to the following restrictions: 00014 00015 1. The origin of this software must not be misrepresented; you must 00016 not claim that you wrote the original software. If you use this 00017 software in a product, an acknowledgment within documentation of 00018 said product would be appreciated but is not required. 00019 00020 2. Altered source versions must be plainly marked as such, and must 00021 not be misrepresented as being the original software. 00022 00023 3. This notice may not be removed or altered from any distribution 00024 of the source. 00025 00026 4. Derivative works are permitted, but they must carry this notice 00027 in full and credit the original source. 00028 00029 00030 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00031 00032 00033 @version Initial version; Nov 2005 00034 00035 @author Kris 00036 00037 00038 *******************************************************************************/ 00039 00040 module mango.convert.Sprint; 00041 00042 private import std.stdarg; 00043 00044 private import mango.convert.Type, 00045 mango.convert.Format, 00046 mango.convert.Unicode; 00047 00048 /****************************************************************************** 00049 00050 Constructs sprintf-style output. This is a replacement for the 00051 vsprintf() family of functions, and writes it's output into a 00052 lookaside buffer. 00053 00054 This is the stack-based version, used when heap allocation must 00055 be avoided ~ see Sprint for the class version 00056 00057 @code 00058 // output buffer 00059 char[100] tmp; 00060 00061 SprintStruct sprint; 00062 sprint.ctor (tmp); 00063 00064 // write text to the console 00065 Cout (sprint ("%d green bottles, sitting on a wall\n", 10)); 00066 @endcode 00067 00068 State is maintained on the stack only, making this thread-safe. 00069 You may supply a workspace buffer as an optional initialization 00070 argument, which should typically also be allocated on the stack. 00071 00072 Note that Sprint is templated, and can be instantiated for wide 00073 chars through a SprintStructTemplate!(dchar) or wchar. The wide 00074 versions differ in that both the output and the format-string 00075 are of the target type. Variadic string arguments are transcoded 00076 appropriately. 00077 00078 Floating-point support is optional. The second ctor argument is 00079 for hooking up an appropriate formatter, such as Double.format 00080 or DGDouble.format. 00081 00082 See Format.parse() for the list of format specifiers. 00083 00084 ******************************************************************************/ 00085 00086 struct SprintStructTemplate(T) 00087 { 00088 package alias FormatStructTemplate!(T) Format; 00089 00090 private Unicode.Into!(T) into; 00091 protected Format format; 00092 protected T[128] tmp; 00093 protected T[] buffer; 00094 protected T* p, limit; 00095 00096 mixin Type.TextType!(T); 00097 00098 /********************************************************************** 00099 00100 **********************************************************************/ 00101 00102 void ctor (T[] dst, Format.DblFormat df = null, T[] workspace = null) 00103 { 00104 format.ctor (&sink, null, workspace.length ? workspace : tmp, df); 00105 p = buffer = dst; 00106 limit = p + buffer.length; 00107 } 00108 00109 /********************************************************************** 00110 00111 **********************************************************************/ 00112 00113 private uint sink (void[] v, uint type) 00114 { 00115 auto s = cast(T[]) into.convert (v, type); 00116 00117 // if (type != TextType) 00118 // format.error ("Sprint.sink : struct version does not transcode"); 00119 // auto s = cast(T[]) v; 00120 00121 int len = s.length; 00122 if (p+len >= limit) 00123 format.error ("Sprint.sink : output buffer too small"); 00124 00125 p[0..len] = s[0..len]; 00126 p += len; 00127 return len; 00128 } 00129 00130 /********************************************************************** 00131 00132 **********************************************************************/ 00133 00134 T[] opCall (T[] fmt, ...) 00135 { 00136 p = buffer; 00137 return buffer [0 .. format (fmt, _arguments, _argptr)]; 00138 } 00139 } 00140 00141 00142 alias SprintStructTemplate!(char) SprintStruct; 00143 00144 00145 00146 /****************************************************************************** 00147 00148 Constructs sprintf-style output. This is a replacement for the 00149 vsprintf() family of functions, and writes it's output into a 00150 lookaside buffer. 00151 00152 This is the class-based version, used when convenience is a 00153 factor ~ see SprintStruct for the stack-based version 00154 00155 @code 00156 // create a Sprint instance 00157 Sprint sprint = new Sprint (100); 00158 00159 // write text to the console 00160 Cout (sprint ("%d green bottles, sitting on a wall\n", 10)); 00161 @endcode 00162 00163 This can be really handy when you wish to format text for 00164 a Logger. Please note that the class itself is stateful, and 00165 therefore a single instance is not shareable across multiple 00166 threads. 00167 00168 Note that Sprint is templated, and can be instantiated for wide 00169 chars through a SprintStructTemplate!(dchar) or wchar. The wide 00170 versions differ in that both the output and the format-string 00171 are of the target type. Variadic string arguments are transcoded 00172 appropriately. 00173 00174 Floating-point support is optional. The second ctor argument is 00175 for hooking up an appropriate formatter, such as Double.format 00176 or DGDouble.format. 00177 00178 See Format.parse() for the list of format specifiers. 00179 00180 ******************************************************************************/ 00181 00182 class SprintClassTemplate(T) 00183 { 00184 package alias FormatStructTemplate!(T) Format; 00185 00186 private Unicode.Into!(T) into; 00187 private Format format; 00188 private T[128] tmp; 00189 private T[] buffer; 00190 private T* p, limit; 00191 00192 /********************************************************************** 00193 00194 **********************************************************************/ 00195 00196 this (int size, Format.DblFormat df = null, T[] workspace = null) 00197 { 00198 format.ctor (&sink, null, workspace.length ? workspace : tmp, df); 00199 p = buffer = new T[size]; 00200 limit = p + buffer.length; 00201 } 00202 00203 /********************************************************************** 00204 00205 **********************************************************************/ 00206 00207 private uint sink (void[] v, uint type) 00208 { 00209 auto s = cast(T[]) into.convert (v, type); 00210 00211 int len = s.length; 00212 if (p+len >= limit) 00213 format.error ("Sprint.sink : output buffer too small"); 00214 00215 p[0..len] = s[0..len]; 00216 p += len; 00217 return len; 00218 } 00219 00220 /********************************************************************** 00221 00222 **********************************************************************/ 00223 00224 T[] opCall (T[] fmt, ...) 00225 { 00226 p = buffer; 00227 return buffer [0 .. format (fmt, _arguments, _argptr)]; 00228 } 00229 } 00230 00231 alias SprintClassTemplate!(char) Sprint; 00232