00001 /******************************************************************************* 00002 00003 @file Atoi.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.Atoi; 00041 00042 /****************************************************************************** 00043 00044 ******************************************************************************/ 00045 00046 struct AtoiTemplate(T) 00047 { 00048 static if (!is (T == char) && !is (T == wchar) && !is (T == dchar)) 00049 pragma (msg, "Template type must be char, wchar, or dchar"); 00050 00051 00052 /********************************************************************** 00053 00054 Strip leading whitespace, extract an optional +/- sign, 00055 and an optional radix prefix. 00056 00057 This can be used as a precursor to the conversion of digits 00058 into a number. 00059 00060 Returns the number of matching characters. 00061 00062 **********************************************************************/ 00063 00064 static uint trim (T[] digits, out bool sign, out uint radix) 00065 { 00066 T c; 00067 T* p = digits; 00068 int len = digits.length; 00069 00070 // set default radix 00071 radix = 10; 00072 00073 // strip off whitespace and sign characters 00074 for (c = *p; len; c = *++p, --len) 00075 if (c == ' ' || c == '\t') 00076 {} 00077 else 00078 if (c == '-') 00079 sign = true; 00080 else 00081 if (c == '+') 00082 sign = false; 00083 else 00084 break; 00085 00086 // strip off a radix specifier also? 00087 if (c == '0' && len) 00088 switch (*++p) 00089 { 00090 case 'x': 00091 case 'X': 00092 ++p; 00093 radix = 16; 00094 break; 00095 00096 case 'b': 00097 case 'B': 00098 ++p; 00099 radix = 2; 00100 break; 00101 00102 case 'o': 00103 case 'O': 00104 ++p; 00105 radix = 8; 00106 break; 00107 00108 default: 00109 break; 00110 } 00111 00112 // return number of characters eaten 00113 return (p - digits.ptr); 00114 } 00115 00116 /********************************************************************** 00117 00118 Convert the provided 'digits' into an integer value, 00119 without looking for a sign or radix. 00120 00121 Returns the value and updates 'ate' with the number 00122 of characters parsed. 00123 00124 **********************************************************************/ 00125 00126 static ulong convert (T[] digits, int radix=10, uint* ate=null) 00127 { 00128 ulong value; 00129 uint eaten; 00130 00131 foreach (T c; digits) 00132 { 00133 if (c >= '0' && c <= '9') 00134 {} 00135 else 00136 if (c >= 'a' && c <= 'f') 00137 c -= 39; 00138 else 00139 if (c >= 'A' && c <= 'F') 00140 c -= 7; 00141 else 00142 break; 00143 00144 value = value * radix + (c - '0'); 00145 ++eaten; 00146 } 00147 00148 if (ate) 00149 *ate = eaten; 00150 00151 return value; 00152 } 00153 00154 /********************************************************************** 00155 00156 Parse an integer value from the provided 'src' string. The 00157 string is also inspected for a sign and radix (defaults to 00158 10), which can be overridden by setting 'radix' to non-zero. 00159 00160 Returns the value and updates 'ate' with the number of 00161 characters parsed. 00162 00163 **********************************************************************/ 00164 00165 static long parse (T[] digits, uint radix=0, uint* ate=null) 00166 { 00167 uint rdx; 00168 bool sign; 00169 00170 int eaten = trim (digits, sign, rdx); 00171 00172 if (radix) 00173 rdx = radix; 00174 00175 ulong result = convert (digits[eaten..length], rdx, ate); 00176 00177 if (ate) 00178 ate += eaten; 00179 00180 return cast(long) (sign ? -result : result); 00181 } 00182 } 00183 00184 00185 /****************************************************************************** 00186 00187 Default instance of this template 00188 00189 ******************************************************************************/ 00190 00191 alias AtoiTemplate!(char) Atoi;