/dotmars/base/convert.d
http://dotmars.googlecode.com/ · D · 829 lines · 630 code · 133 blank · 66 comment · 178 complexity · 5a88078c7bff166fbcc8a6081cd0f757 MD5 · raw file
- /** Converter & Formatter
-
- Written in the D programming language 1.0
-
- Authors: Wei Li (oldrev@gmail.com)
- License: BSD
- Copyright: Copyright (C) 2007 by Wei Li.
- Date: May 17 2007
- */
-
- /*
- TODO:
- * ???????????
- */
-
- module dotmars.base.convert;
-
- import dotmars.base.typetraits;
- import dotmars.base.stdexcept;
- import dotmars.base.stdtypes;
-
- import dotmars.base.math;
- import dotmars.text.utf;
- import dotmars.base.string;
-
- import dotmars.io.console;
-
- //36????
- const char[36] Digitals = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- const char[36] DigitalsLower = "0123456789abcdefghijklmnopqrstuvwxyz";
-
-
- private static uint charToNumber(char c)
- {
- if(c >= '0' && c <= '9')
- return c - '0';
- else if(c >= 'A' && c <= 'Z')
- return c - 'A' + 10;
- else if(c >= 'a' && c <= 'z')
- return c - 'a' + 10;
-
- throw new FormatException("Invalid digital character");
- }
-
- ////////////////////////////////////////////////////////////////////////////////
-
- final static class BitConverter
- {
- enum Endian
- {
- Little,
- Big
- }
-
- version(LittleEndian)
- public const bool IsLittleEndian = true;
- version(BigEndian)
- public const bool IsLittleEndian = false;
-
- public static T reverseByteOrder(T)(T value)
- {
- static assert(IsIntegerType!(T) || IsCharType!(T) && T.sizeof > 1);
- static if(is(T == ushort))
- return fastReverseByteOrder16(value);
-
- T ret = value;
- ubyte* first = cast(ubyte*)(&ret);
- ubyte* last = first + T.sizeof - 1;
- while (first < last)
- {
- ubyte tmp = *first;
- *first = *last;
- *last = tmp;
- ++first;
- --last;
- }
- return ret;
- }
-
- private static ushort fastReverseByteOrder16(ushort value)
- {
- ushort ret = value >> 8;
- ret += value << 8;
- return ret;
- }
-
- public static bool toBoolean(ubyte[] bytes)
- in {
- assert(bytes !is null);
- }
- body {
- if(bytes.length < 1)
- throw new ArgumentException("toBoolean: Empty array");
- return bytes[0] == 0;
- }
-
- public static ubyte[] getBytes(T)(T value)
- {
- ubyte* ptr = cast(ubyte*)(&value);
- return ptr[0..value.sizeof];
- }
-
- }
-
- ////////////////////////////////////////////////////////////////////////////////
-
- static class Integer
- {
- //format INTs
- static void getChars(T)(T value, Sink!(char) sink, uint radix = 10, uint precision = 0, bool lower = false)
- in {
- static assert(IsIntegerType!(T));
- assert(radix >= 2 && radix <= 36);
- }
- body {
- //????2???
- char[T.sizeof * 8 + 1] a;
- size_t index = a.length - 1;
- T u = abs(value);
- do {
- a[index--] =
- lower ? DigitalsLower[u % radix] : Digitals[u % radix];
- }while(u /= radix)
-
- if(value < 0)a[index--] = '-';
-
- size_t len = a[index + 1 .. $].length;
-
- if(precision > len)
- {
- for(size_t j = 0; j < precision - len; j++)
- sink('0');
- }
-
- foreach(char c; a[index + 1 .. $])
- sink(c);
- }
-
- static string toString(T)(T value, uint radix = 10, uint precision = 0, bool lower = false)
- {
- string result;
- Sink!(char) sink =
- (char c) { result ~= c; };
- getChars!(T)(value, sink, radix, precision, lower);
- return result;
- }
-
- static T parse(T)(string str)
- {
- bool sign = false;
- T value = 0;
- uint radix = 10;
- size_t i = 0;
-
- for(; i < str.length; i++)
- {
- char c = str[i];
- //????
- if(c == ' ') continue;
-
- if(c == '-')
- {
- sign = true;
- continue;
- }
-
- if(c == '+')
- continue;
-
- //???????
-
- //???????
- if(c != '0')break;
-
- //??????? '0'
- if(i >= str.length - 1)
- break;
-
- c = str[++i];
- switch(c)
- {
- case 'x':
- case 'X':
- radix = 16;
- i++;
- break;
-
- case 'b':
- case 'B':
- radix = 2;
- i++;
- break;
-
- //8??
- default:
- radix = 8;
- break;
- }
-
- break;
- }
-
- //??????????
- for(; i < str.length; i++)
- {
- char c = str[i];
-
- uint d = charToNumber(c);
- if(d < radix)
- value = value * radix + d;
- else //???????????
- throw new FormatException("toInteger: invalid character");
- }
-
- if(sign)value = -value;
- return value;
- }
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
-
- static class Float
- {
- static void getChars(T)(T value, Sink!(char) sink, uint precision = 6,
- bool scientific = false, bool lower = false)
- in {
- static assert(IsFloatType!(T));
- assert(sink !is null);
- }
- body {
- T x = abs(value);
-
- const T radix = 10.0;
-
- int exp = cast(int)log10(x);
-
- int intDigits = exp + 1;
- if(exp < 0)
- {
- intDigits = -exp + 1;
- x *= pow(radix, cast(T)-exp);
- }
- else
- x /= pow(radix, cast(T)exp);
-
- if(scientific)
- intDigits = 1;
-
- int digits = intDigits + precision;
-
- if(value < 0)sink('-');
-
- for(size_t i = 0; i < digits; i++)
- {
- if(i == intDigits)
- sink('.');
- int digit = cast(int)x;
- sink('0' + digit);
- x = (x - digit) * radix;
- }
-
- if(scientific)
- {
- if(lower)
- sink('e');
- else
- sink('E');
- if(exp > 9)
- {
- sink('0' + exp / 10);
- sink('0' + exp % 10);
- }
- else
- sink('0' + exp);
- }
- }
-
- static string toString(T)(T value, uint precision = 6, bool scientific = false, bool lower = false)
- {
- string result;
- Sink!(char) sink = (char c) { result ~= c; };
- getChars!(T)(value, sink, precision, scientific, lower);
- return result;
- }
- }
-
- //////////////////////////////////////////////////////////////////////////////
-
- static final class Convert
- {
- public static string toString(byte value, uint radix = 10) {
- return Integer.toString!(int)(value, radix);
- }
-
- public static string toString(short value, uint radix = 10) {
- return Integer.toString!(int)(value, radix);
- }
-
- public static string toString(int value, uint radix = 10) {
- return Integer.toString!(int)(value, radix);
- }
-
- public static string toString(long value, uint radix = 10) {
- return Integer.toString!(long)(value, radix);
- }
-
- public static string toString(ubyte value, uint radix = 10) {
- return Integer.toString!(int)(value, radix);
- }
-
- public static string toString(ushort value, uint radix = 10) {
- return Integer.toString!(int)(value, radix);
- }
-
- public static string toString(uint value, uint radix = 10) {
- return Integer.toString!(uint)(value, radix);
- }
-
- public static string toString(ulong value, uint radix = 10) {
- return Integer.toString!(ulong)(value, radix);
- }
-
- // floats
- public static string toString(float value) {
- return Float.toString!(float)(value);
- }
-
- public static string toString(double value) {
- return Float.toString!(float)(value);
- }
-
- public static string toString(real value) {
- return Float.toString!(real)(value);
- }
-
- //imaginary numbers
- public static string toString(ifloat value) {
- return Float.toString!(float)(cast(float)value) ~ 'i';
- }
-
- public static string toString(idouble value) {
- return Float.toString!(double)(cast(double)value) ~ 'i';
- }
-
- public static string toString(ireal value) {
- return Float.toString!(real)(cast(real)value) ~ 'i';
- }
-
- //complex numbers
- public static string toString(cfloat value){
- return Float.toString!(float)(cast(float)value.re) ~
- '+' ~ Float.toString!(float)(cast(float)value.im) ~ 'i';
- }
-
- public static string toString(cdouble value){
- return Float.toString!(double)(cast(double)value.re) ~
- '+' ~ Float.toString!(double)(cast(double)value.im) ~ 'i';
- }
-
- public static string toString(creal value){
- return Float.toString!(real)(cast(real)value.re) ~
- '+' ~ Float.toString!(real)(cast(real)value.im) ~ 'i';
- }
-
- public static T fromString(T)(string str)
- {
- static if(IsIntegerType!(T))
- {
- return Integer.parse!(T)(str);
- }
- else
- {
- static assert(false, "not implemented");
- }
- }
-
-
- private static bool isDecimalChar(char c)
- {
- if(c >= '0' && c <= '9')return true;
- return false;
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
-
- static class Formatter
- {
- const size_t MaxArguments = 16;
-
- static void format(Sink!(char) sink, string fmt, ...)
- {
- format(sink, fmt, _argptr, _arguments);
- }
-
- static void format(Sink!(char) sink, Argument argPtr, TypeInfo[] argtis, string fmt)
- in {
- assert(sink !is null);
- assert(fmt !is null);
- }
- body {
- assert(argtis.length <= MaxArguments, "Formatter.format(): Too many arguments");
- Argument[MaxArguments] args = void;
- //??????
- foreach (size_t i, ti; argtis)
- {
- args[i] = argPtr;
-
- //??? stdarg.d?????CPU?????????
- argPtr += (ti.tsize + size_t.sizeof - 1) & ~ (size_t.sizeof - 1);
- }
-
- doFormat(sink, fmt, args, argtis);
- }
-
- static string format(string fmt, ...) {
- string ret;
- Sink!(char) sink = (char c){ ret ~= c; } ;
- format(sink, fmt, _argptr, _arguments);
- return ret;
- }
-
- static size_t sprint(string dest, Argument argPtr, TypeInfo[] argtis, string fmt)
- in {
- assert(dest !is null);
- }
- body {
- size_t n = 0;
- Sink!(char) sink =
- (char c) { dest[n++] = c; } ;
- format(sink, fmt, argPtr, argtis);
- return n;
- }
-
- static size_t sprint(string dest, string fmt, ...) {
- return sprint(dest, fmt, _argptr, _arguments);
- }
-
- private static void formatString(T)(Sink!(char) sink, string fmt, T str)
- {
- static assert(is(T == string) || is(T == wstring) || is( T == dstring));
- if(fmt.length > 0)
- throw new FormatException("Not Supported");
-
- static if(is(T == string)) {
- foreach(char c; str)
- sink(c);
- }
- else static if(is(T == wstring)) {
- foreach(wchar c; str)
- .toUtf8(c, sink);
- }
- else static if(is(T == dstring)) {
- foreach(dchar c; str)
- .toUtf8(c, sink);
- }
- }
-
- private static void formatInteger(T)( Sink!(char) sink, string fmtstr, T i)
- in {
- static assert(IsIntegerType!(T));
- }
- body {
-
- bool lower = false;
- uint radix = 10;
- int precision = 0;
-
- if(fmtstr !is null && fmtstr.length >= 1)
- {
- char fmt = fmtstr[0];
-
- switch(fmt)
- {
- case 'x':
- radix = 16;
- lower = true;
- break;
-
- case 'X':
- radix = 16;
- break;
-
- case 'g':
- case 'G':
- case 'D':
- case 'd':
- radix = 10;
- break;
-
- default:
- throw new FormatException("Syntax error");
- break;
- }
-
- if(fmtstr.length > 1)
- {
- size_t l = 0;
- precision = extractDecimal(fmtstr[1..$], l);
- if(precision < 0)
- throw new FormatException("Invalid precision");
- }
- }
-
- Integer.getChars!(T)(i, sink, radix, precision, lower);
- }
-
- private static void formatFloat(T)(Sink!(char) sink, string fmtstr, T f)
- {
- uint precision = 6;
- bool scientific = false;
- bool lower = false;
-
- if(fmtstr !is null && fmtstr.length >= 1)
- {
- char fmt = fmtstr[0];
-
- switch(fmt)
- {
- case 'E':
- scientific = true;
- lower = false;
- break;
-
- case 'e':
- scientific = true;
- lower = true;
- break;
-
- case 'g':
- case 'G':
- case 'd':
- case 'D':
- scientific = false;
- break;
-
- default:
- throw new FormatException("Syntax error");
- break;
- }
-
- if(fmtstr.length > 1)
- {
- size_t l = 0;
- precision = extractDecimal(fmtstr[1..$], l);
- if(precision < 0)
- throw new FormatException("Invalid precision");
- }
- }
-
-
- Float.getChars!(T)(f, sink, precision, scientific, lower);
- }
-
- private static void putSpaces(Sink!(char) sink, uint n) {
- for(uint i = 0; i < n; i++)
- sink(' ');
- }
-
- private static uint extractDecimal(string str, out size_t len) {
- assert(str !is null);
- len = 0;
- foreach(char c; str)
- {
- if(c >= '0' && c <= '9') len++;
- else break;
- }
- if(len == 0)
- throw new FormatException("Format: syntax error");
- return Convert.fromString!(uint)(str[0 .. len]);
- }
-
-
- private static size_t findRightBrach(string str)
- {
- assert(str !is null);
-
- foreach(size_t i, char c; str) {
- if(c == '}')
- return i;
- }
-
- // "{}" have not matched.
- throw new FormatException("Format: Syntax error");
- }
-
- private static void doFormat(Sink!(char) sink, string fmt, Argument[] args, TypeInfo[] ti)
- {
- for(size_t i = 0; i < fmt.length;)
- {
- // skip the escape char
- for(; i < fmt.length && fmt[i] != '{'; i++)
- sink(fmt[i]);
-
- if(i >= fmt.length)break;
-
- // "{{"
- if(i < fmt.length - 1 && fmt[i + 1] == '{')
- {
- i += 2;
- sink('{');
- continue;
- }
-
- size_t beginBrach = i;
- size_t endBrach = i + findRightBrach(fmt[i .. $]);
-
- // parsing the format string
- doParse(sink, fmt[beginBrach + 1 .. endBrach], args, ti);
-
- i = endBrach + 1;
- }
- }
-
-
- //???????????
- private static void doParse(Sink!(char) sink, string fmt, Argument[] args, TypeInfo[] ti)
- in {
- assert(fmt !is null);
- assert(args !is null);
- assert(ti !is null);
- }
- body {
- //{INDEX,+/-ALIGNMENT:FORMAT}
- size_t i = 0, len = 0;
- // skip spaces
- while(i < fmt.length && fmt[i] == ' ') i++;
- // extract the index
- uint index = extractDecimal(fmt[i..$], len);
- if(index >= ti.length)
- throw new FormatException("Invalid index of place holder");
-
- i += len;
-
- //skip spaces
- while(i < fmt.length && fmt[i] == ' ') i++;
-
- //deal with alignment
- int alignment = 0;
- if(i < fmt.length && fmt[i] == ',')
- {
- i++;
- while(i < fmt.length && fmt[i] == ' ') i++;
- bool sign = false;
- if(fmt[i] == '-')
- {
- i++;
- sign = true;
- }
- if(fmt[i] == '+')
- i++;
-
- alignment = extractDecimal(fmt[i..$], len);
- if(sign) alignment = -alignment;
- i += len;
- }
-
- //skip spaces
- while(i < fmt.length && fmt[i] == ' ') i++;
-
- string fmtstr = null;
- if(i < fmt.length && fmt[i] == ':')
- {
- i++;
- while(i < fmt.length && fmt[i] == ' ') i++;
- size_t l = i;
- while(l < fmt.length && fmt[l] != ' ') l++;
- fmtstr = fmt[i .. l];
- }
-
- handleAlignment(sink, alignment, fmtstr, args[index], ti[index]);
- }
-
- private static void formatDisp(Sink!(char) sink, string fmtstr, Argument arg, TypeInfo ti)
- in {
- assert(sink !is null);
- assert(ti !is null);
- }
- body {
- // integers
- if(ti == typeid(byte)) {
- byte* pval = cast(byte*)arg;
- formatInteger!(byte)(sink, fmtstr, *pval);
- }
- else if(ti == typeid(ubyte)) {
- ubyte* pval = cast(ubyte*)arg;
- formatInteger!(ubyte)(sink, fmtstr, *pval);
- }
- else if (ti == typeid(short)) {
- short* pval = cast(short*)arg;
- formatInteger!(short)(sink, fmtstr, *pval);
- }
- else if(ti == typeid(ushort)) {
- ushort* pval = cast(ushort*)arg;
- formatInteger!(ushort)(sink, fmtstr, *pval);
- }
- else if(ti == typeid(int)) {
- int* pval = cast(int*)arg;
- formatInteger!(int)(sink, fmtstr, *pval);
- }
- else if(ti == typeid(uint)) {
- uint* pval = cast(uint*)arg;
- formatInteger!(uint)(sink, fmtstr, *pval);
- }
- else if(ti == typeid(long)) {
- long* pval = cast(long*)arg;
- formatInteger!(long)(sink, fmtstr, *pval);
- }
- else if(ti == typeid(ulong)) {
- ulong* pval = cast(ulong*)arg;
- formatInteger!(ulong)(sink, fmtstr, *pval);
- }
- // floats
- else if(ti == typeid(float)) {
- float* pval = cast(float*)arg;
- formatFloat!(float)(sink, fmtstr, *pval);
- }
- else if(ti == typeid(double)) {
- double* pval = cast(double*)arg;
- formatFloat!(double)(sink, fmtstr,*pval);
- }
- else if(ti == typeid(real)) {
- real* pval = cast(real*)arg;
- formatFloat!(real)(sink, fmtstr, *pval);
- }
- else if(ti == typeid(ifloat))
- {
- float* pval = cast(float*)arg;
- formatFloat!(float)(sink, fmtstr, *pval);
- }
- else if(ti == typeid(idouble))
- {
- double* pval = cast(double*)arg;
- formatFloat!(double)(sink, fmtstr, *pval);
- }
- else if(ti == typeid(ireal))
- {
- real* pval = cast(real*)arg;
- formatFloat!(real)(sink, fmtstr, *pval);
- }
- /*
- else if(ti == typeid(cfloat))
- {
- cfloat* pval = cast(cfloat*)arg;
- formatOne(fmtstr, sink, *pval);
- }
- else if(ti == typeid(cdouble))
- {
- cdouble* pval = cast(cdouble*)arg;
- formatOne(fmtstr, sink, *pval);
- }
- else if(ti == typeid(creal))
- {
- creal* pval = cast(creal*)arg;
- formatOne(fmtstr, sink, *pval);
- }*/
- //string type
- else if(ti == typeid(string)) {
- string *pstr = cast(string*)arg;
- formatString!(string)(sink, fmtstr, *pstr);
- }
- else if(ti == typeid(wstring)) {
- wstring *pstr = cast(wstring*)arg;
- formatString!(wstring)(sink, fmtstr, *pstr);
- }
- else if(ti == typeid(dstring)) {
- dstring *pstr = cast(dstring*)arg;
- formatString!(dstring)(sink, fmtstr, *pstr);
- }
- //character type
- else if(ti == typeid(char)) {
- char *pstr = cast(char*)arg;
- formatString!(string)(sink, fmtstr, pstr[0..1]);
- }
- else if(ti == typeid(wchar)) {
- wchar *pstr = cast(wchar*)arg;
- formatString!(wstring)(sink, fmtstr, pstr[0..1]);
- }
- else if(ti == typeid(dchar)) {
- dchar *pstr = cast(dchar*)arg;
- formatString!(dstring)(sink, fmtstr, pstr[0..1]);
- }
- //boolean
- else if(ti == typeid(bool)) {
- bool *pval = cast(bool*)arg;
- formatString!(string)(sink, fmtstr, *pval ? "true" : "false");
- }
- //class
- else if(ti.classinfo.name == "TypeInfo_Class")
- {
- Object* pobj = cast(Object*) arg;
-
- version(Tango) {
- string str = (*pobj) is null ? "<null>" : (*pobj).toUtf8;
- }
- else {
- string str = (*pobj) is null ? "<null>" : (*pobj).toString;
- }
-
- formatString!(string)(sink, fmtstr, str);
- }
- else {
- throw new FormatException("Unknown type");
- }
-
- }
-
-
- private static void handleAlignment(Sink!(char) sink, int alignment,
- string fmt, Argument arg, TypeInfo ti)
- {
- int count = 0;
- Sink!(char) drySink = (char c) { count++; };
- formatDisp(drySink, fmt, arg, ti);
- int padding = abs(alignment) - count;
-
- if(padding > 0 && alignment > 0)
- putSpaces(sink, padding);
-
- formatDisp(sink, fmt, arg, ti);
-
- //right align
- if(padding > 0 && alignment < 0)
- putSpaces(sink, padding);
- }
-
- }