alphanum.hpp
Go to the documentation of this file.
00001 #ifndef ALPHANUM__HPP
00002 #define ALPHANUM__HPP
00003 
00004 /*
00005 The Alphanum Algorithm is an improved sorting algorithm for strings
00006 containing numbers.  Instead of sorting numbers in ASCII order like a
00007 standard sort, this algorithm sorts numbers in numeric order.
00008 
00009 The Alphanum Algorithm is discussed at http://www.DaveKoelle.com
00010 
00011 This implementation is Copyright (c) 2008 Dirk Jagdmann <doj@cubic.org>.
00012 It is a cleanroom implementation of the algorithm and not derived by
00013 other's works. In contrast to the versions written by Dave Koelle this
00014 source code is distributed with the libpng/zlib license.
00015 
00016 This software is provided 'as-is', without any express or implied
00017 warranty. In no event will the authors be held liable for any damages
00018 arising from the use of this software.
00019 
00020 Permission is granted to anyone to use this software for any purpose,
00021 including commercial applications, and to alter it and redistribute it
00022 freely, subject to the following restrictions:
00023 
00024     1. The origin of this software must not be misrepresented; you
00025        must not claim that you wrote the original software. If you use
00026        this software in a product, an acknowledgment in the product
00027        documentation would be appreciated but is not required.
00028 
00029     2. Altered source versions must be plainly marked as such, and
00030        must not be misrepresented as being the original software.
00031 
00032     3. This notice may not be removed or altered from any source
00033        distribution. */
00034 
00035 /* $Header: /code/doj/alphanum.hpp,v 1.3 2008/01/28 23:06:47 doj Exp $ */
00036 
00037 #include <cassert>
00038 #include <functional>
00039 #include <string>
00040 #include <sstream>
00041 
00042 #ifdef ALPHANUM_LOCALE
00043 #include <cctype>
00044 #endif
00045 
00046 #ifdef DOJDEBUG
00047 #include <iostream>
00048 #include <typeinfo>
00049 #endif
00050 
00051 // TODO: make comparison with hexadecimal numbers. Extend the alphanum_comp() function by traits to choose between decimal and hexadecimal.
00052 
00053 namespace doj
00054 {
00055 
00056   // anonymous namespace for functions we use internally. But if you
00057   // are coding in C, you can use alphanum_impl() directly, since it
00058   // uses not C++ features.
00059   namespace {
00060 
00061     // if you want to honour the locale settings for detecting digit
00062     // characters, you should define ALPHANUM_LOCALE
00063 #ifdef ALPHANUM_LOCALE
00064 
00065     bool alphanum_isdigit(int c)
00066     {
00067       return isdigit(c);
00068     }
00069 #else
00070 
00074     bool alphanum_isdigit(const char c)
00075     {
00076       return c>='0' && c<='9';
00077     }
00078 #endif
00079 
00095     int alphanum_impl(const char *l, const char *r)
00096     {
00097       enum mode_t { STRING, NUMBER } mode=STRING;
00098 
00099       while(*l && *r)
00100         {
00101           if(mode == STRING)
00102             {
00103               char l_char, r_char;
00104               while((l_char=*l) && (r_char=*r))
00105                 {
00106                   // check if this are digit characters
00107                   const bool l_digit=alphanum_isdigit(l_char), r_digit=alphanum_isdigit(r_char);
00108                   // if both characters are digits, we continue in NUMBER mode
00109                   if(l_digit && r_digit)
00110                     {
00111                       mode=NUMBER;
00112                       break;
00113                     }
00114                   // if only the left character is a digit, we have a result
00115                   if(l_digit) return -1;
00116                   // if only the right character is a digit, we have a result
00117                   if(r_digit) return +1;
00118                   // compute the difference of both characters
00119                   const int diff=l_char - r_char;
00120                   // if they differ we have a result
00121                   if(diff != 0) return diff;
00122                   // otherwise process the next characters
00123                   ++l;
00124                   ++r;
00125                 }
00126             }
00127           else // mode==NUMBER
00128             {
00129 #ifdef ALPHANUM_LOCALE
00130               // get the left number
00131               char *end;
00132               unsigned long l_int=strtoul(l, &end, 0);
00133               l=end;
00134 
00135               // get the right number
00136               unsigned long r_int=strtoul(r, &end, 0);
00137               r=end;
00138 #else
00139               // get the left number
00140               unsigned long l_int=0;
00141               while(*l && alphanum_isdigit(*l))
00142                 {
00143                   // TODO: this can overflow
00144                   l_int=l_int*10 + *l-'0';
00145                   ++l;
00146                 }
00147 
00148               // get the right number
00149               unsigned long r_int=0;
00150               while(*r && alphanum_isdigit(*r))
00151                 {
00152                   // TODO: this can overflow
00153                   r_int=r_int*10 + *r-'0';
00154                   ++r;
00155                 }
00156 #endif
00157 
00158               // if the difference is not equal to zero, we have a comparison result
00159               const long diff=l_int-r_int;
00160               if(diff != 0)
00161                 return diff;
00162 
00163               // otherwise we process the next substring in STRING mode
00164               mode=STRING;
00165             }
00166         }
00167 
00168       if(*r) return -1;
00169       if(*l) return +1;
00170       return 0;
00171     }
00172 
00173   }
00174 
00183   template <typename lT, typename rT>
00184   int alphanum_comp(const lT& left, const rT& right)
00185   {
00186 #ifdef DOJDEBUG
00187     std::clog << "alphanum_comp<" << typeid(left).name() << "," << typeid(right).name() << "> " << left << "," << right << std::endl;
00188 #endif
00189     std::ostringstream l; l << left;
00190     std::ostringstream r; r << right;
00191     return alphanum_impl(l.str().c_str(), r.str().c_str());
00192   }
00193 
00201   template <>
00202   int alphanum_comp<std::string>(const std::string& l, const std::string& r)
00203   {
00204 #ifdef DOJDEBUG
00205     std::clog << "alphanum_comp<std::string,std::string> " << l << "," << r << std::endl;
00206 #endif
00207     return alphanum_impl(l.c_str(), r.c_str());
00208   }
00209 
00211 
00212   // now follow a lot of overloaded alphanum_comp() functions to get a
00213   // direct call to alphanum_impl() upon the various combinations of c
00214   // and c++ strings.
00215 
00223   int alphanum_comp(char* l, char* r)
00224   {
00225     assert(l);
00226     assert(r);
00227 #ifdef DOJDEBUG
00228     std::clog << "alphanum_comp<char*,char*> " << l << "," << r << std::endl;
00229 #endif
00230     return alphanum_impl(l, r);
00231   }
00232 
00233   int alphanum_comp(const char* l, const char* r)
00234   {
00235     assert(l);
00236     assert(r);
00237 #ifdef DOJDEBUG
00238     std::clog << "alphanum_comp<const char*,const char*> " << l << "," << r << std::endl;
00239 #endif
00240     return alphanum_impl(l, r);
00241   }
00242 
00243   int alphanum_comp(char* l, const char* r)
00244   {
00245     assert(l);
00246     assert(r);
00247 #ifdef DOJDEBUG
00248     std::clog << "alphanum_comp<char*,const char*> " << l << "," << r << std::endl;
00249 #endif
00250     return alphanum_impl(l, r);
00251   }
00252 
00253   int alphanum_comp(const char* l, char* r)
00254   {
00255     assert(l);
00256     assert(r);
00257 #ifdef DOJDEBUG
00258     std::clog << "alphanum_comp<const char*,char*> " << l << "," << r << std::endl;
00259 #endif
00260     return alphanum_impl(l, r);
00261   }
00262 
00263   int alphanum_comp(const std::string& l, char* r)
00264   {
00265     assert(r);
00266 #ifdef DOJDEBUG
00267     std::clog << "alphanum_comp<std::string,char*> " << l << "," << r << std::endl;
00268 #endif
00269     return alphanum_impl(l.c_str(), r);
00270   }
00271 
00272   int alphanum_comp(char* l, const std::string& r)
00273   {
00274     assert(l);
00275 #ifdef DOJDEBUG
00276     std::clog << "alphanum_comp<char*,std::string> " << l << "," << r << std::endl;
00277 #endif
00278     return alphanum_impl(l, r.c_str());
00279   }
00280 
00281   int alphanum_comp(const std::string& l, const char* r)
00282   {
00283     assert(r);
00284 #ifdef DOJDEBUG
00285     std::clog << "alphanum_comp<std::string,const char*> " << l << "," << r << std::endl;
00286 #endif
00287     return alphanum_impl(l.c_str(), r);
00288   }
00289 
00290   int alphanum_comp(const char* l, const std::string& r)
00291   {
00292     assert(l);
00293 #ifdef DOJDEBUG
00294     std::clog << "alphanum_comp<const char*,std::string> " << l << "," << r << std::endl;
00295 #endif
00296     return alphanum_impl(l, r.c_str());
00297   }
00298 
00300 
00306   template<class Ty>
00307   struct alphanum_less : public std::binary_function<Ty, Ty, bool>
00308   {
00309     bool operator()(const Ty& left, const Ty& right) const
00310     {
00311       return alphanum_comp(left, right) < 0;
00312     }
00313   };
00314 
00315 }
00316 
00317 
00318 #endif


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:55