LCOV - code coverage report
Current view: top level - src - misc.h (source / functions) Hit Total Coverage
Test: test_coverage.info Lines: 99 117 84.6 %
Date: 2017-06-21 14:32:49 Functions: 13 15 86.7 %

          Line data    Source code
       1             : 
       2             : //////////////////////////////////////////////////////////////////////
       3             : //
       4             : //  FILE:       misc.h
       5             : //              Miscellaneous routines (File I/O, etc)
       6             : //
       7             : //  Part of:    Scid (Shane's Chess Information Database)
       8             : //  Version:    3.5
       9             : //
      10             : //  Notice:     Copyright (c) 2001-2003  Shane Hudson.  All rights reserved.
      11             : //              Copyright (C) 2015  Fulvio Benini
      12             : //
      13             : //  Author:     Shane Hudson (sgh@users.sourceforge.net)
      14             : //
      15             : //////////////////////////////////////////////////////////////////////
      16             : 
      17             : 
      18             : #ifndef SCID_MISC_H
      19             : #define SCID_MISC_H
      20             : 
      21             : #include "common.h"
      22             : #include <string>
      23             : #include <cstring>
      24             : #include <stdio.h>
      25             : #include <ctype.h>   // For isspace(), etc
      26             : #include <cstdlib>
      27             : #include <vector>
      28             : 
      29             : /**
      30             :  * class StrRange - parse a string interpreting its content as 1 or 2 integers
      31             :  *                  separated by whitespace.
      32             :  * The integers represent the min and max value of a range.
      33             :  * If only one integer is provided it will represent both the min and max value.
      34             :  *
      35             :  * inRange()  :  Return true if @val is >= min and <= max
      36             :  */
      37             : class StrRange {
      38             : protected:
      39             :         long min_;
      40             :         long max_;
      41             : 
      42             : protected:
      43             :         StrRange()
      44             :         : min_(0), max_(0) {}
      45             : 
      46             : public:
      47             :         explicit StrRange(const char* range) {
      48             :                 char* next;
      49             :                 min_ = std::strtol(range, &next, 10);
      50             :                 char* end;
      51             :                 max_ = std::strtol(next, &end, 10);
      52             :                 if (next == end) max_ = min_;
      53             :                 if (min_ > max_) std::swap(min_, max_);
      54             :         }
      55             : 
      56             :         bool inRange(long val) const {
      57             :                 if (val < min_ || val > max_) return false;
      58             :                 return true;
      59             :         }
      60             : };
      61             : 
      62             : 
      63             : /**
      64             :  * class VectorBig - store data into chunks to avoid (or minimize) reallocations
      65             :  * @CHUNKSHIFT: is the base-2 logarithm of the number of T entries per chunk.
      66             :  *              Total size of a chunk: (2^CHUNKSHIFT)*sizeof(T)
      67             :  * resize()   : Used to avoid reallocations.
      68             :  *              Very efficient because it allocates space only for chunk pointers
      69             :  *              i.e with @count==16777214 and @CHUNKSHIFT==16 will use 256 pointers
      70             :  */
      71             : template <class T, size_t CHUNKSHIFT>
      72             : class VectorBig {
      73             :         std::vector<T*> index_;
      74             :         size_t size_;
      75             : 
      76             : public:
      77         106 :         VectorBig() : size_(0) {}
      78             :         VectorBig(const VectorBig&);
      79             :         VectorBig& operator=(const VectorBig&);
      80         106 :         ~VectorBig() { resize(0); }
      81             : 
      82             :         const T& operator[] (size_t idx) const {
      83     1152494 :                 const size_t low_mask = ((1 << CHUNKSHIFT) - 1);
      84     2304987 :                 return index_[idx >> CHUNKSHIFT][idx & low_mask];
      85             :         }
      86             :         T& operator[] (size_t idx) {
      87       21385 :                 const size_t low_mask = ((1 << CHUNKSHIFT) - 1);
      88       42769 :                 return index_[idx >> CHUNKSHIFT][idx & low_mask];
      89             :         }
      90             : 
      91             :         size_t size() const {
      92             :                 return size_;
      93             :         }
      94             : 
      95             :         void reserve(size_t count) {
      96          53 :                 index_.reserve(1 + (count >> CHUNKSHIFT));
      97             :         }
      98             : 
      99       12238 :         void resize(size_t count) {
     100       12238 :                 size_ = count;
     101       12238 :                 size_t index_NewSize = (count > 0) ? 1 + (count >> CHUNKSHIFT) : 0;
     102             : 
     103       24534 :                 while (index_.size() > index_NewSize) {
     104          58 :                         delete [] index_.back();
     105          29 :                         index_.pop_back();
     106             :                 }
     107       24563 :                 while (index_.size() < index_NewSize) {
     108          58 :                         index_.push_back(new T[1 << CHUNKSHIFT]);
     109             :                 }
     110       12238 :         }
     111       12039 :         void resize(size_t count, const T& defaulVal) {
     112       12039 :                 size_t i = size_;
     113       12039 :                 resize(count);
     114       36117 :                 while (i < count) (*this)[i++] = defaulVal;
     115       12039 :         }
     116             : 
     117             :         void push_back(const T& e) {
     118       12039 :                 resize(size_ + 1, e);
     119             :         }
     120             : };
     121             : 
     122             : 
     123             : 
     124             : class Progress {
     125             : public:
     126             :         struct Impl {
     127             :                 virtual ~Impl() {}
     128             :                 virtual bool report(size_t done, size_t total, const char* msg) = 0;
     129             :         };
     130             : 
     131          52 :         Progress(Impl* f = NULL) : f_(f) {}
     132             :         Progress(const Progress&);
     133             :         Progress& operator=(const Progress&);
     134          51 :         ~Progress() { delete f_; }
     135             : 
     136             :         bool report(size_t done, size_t total) const {
     137          19 :                 return operator()(done, total);
     138             :         }
     139             :         bool operator()(size_t done, size_t total, const char* msg = NULL) const {
     140          30 :                 if (f_) return f_->report(done, total, msg);
     141             :                 return true;
     142             :         }
     143             : 
     144             : private:
     145             :         Impl* f_;
     146             : };
     147             : 
     148             : 
     149             : #if CPP11_SUPPORT
     150             : using std::to_string;
     151             : #else
     152             : #include <sstream>
     153             : inline std::string to_string(int val) {
     154             :         std::ostringstream res;
     155             :         res << std::dec << val;
     156             :         return res.str();
     157             : }
     158             : #endif
     159             : 
     160             : 
     161             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     162             : // strGetFilterOp:
     163             : //    Converts a string value to a filter operation value.
     164             : enum filterOpT { FILTEROP_AND, FILTEROP_OR, FILTEROP_RESET };
     165             : 
     166             : inline filterOpT strGetFilterOp (const char * str)
     167             : {
     168             :     switch (*str) {
     169             :         // AND:
     170             :         case 'A': case 'a': case '0': return FILTEROP_AND;
     171             :         // OR:
     172             :         case 'O': case 'o': case '1': return FILTEROP_OR;
     173             :         // RESET:
     174             :         case 'R': case 'r': case '2': return FILTEROP_RESET;
     175             :     }
     176             :     // Default is RESET.
     177             :     return FILTEROP_RESET;
     178             : }
     179             : 
     180             : // ECO string routines
     181             : //
     182             : void eco_ToString (ecoT ecoCode, char * ecoStr, bool extensions = true);
     183             : inline void eco_ToBasicString (ecoT ecoCode, char * ecoStr) {
     184             :     eco_ToString (ecoCode, ecoStr, false);
     185             : }
     186             : inline void eco_ToExtendedString (ecoT ecoCode, char * ecoStr) {
     187           0 :     eco_ToString (ecoCode, ecoStr, true);
     188             : }
     189             : ecoT eco_FromString (const char * ecoStr);
     190             : ecoT eco_LastSubCode (ecoT ecoCode);
     191             : ecoT eco_BasicCode (ecoT ecoCode);
     192             : ecoT eco_Reduce(ecoT eco);
     193             : 
     194             : // String routines. Some are identical to ANSI standard functions, but
     195             : //      I have included them:
     196             : //      (a) to keep nice consistent naming conventions, e.g. strCopy.
     197             : //      (b) so stats can easily be kept by modifying the functions.
     198             : //      (c) so some can be made inline for speed if necessary.
     199             : 
     200    18029458 : inline uint32_t strStartHash(const char* str) {
     201    18029458 :         ASSERT(str != 0);
     202    18029458 :         const unsigned char* s = reinterpret_cast<const unsigned char*>(str);
     203             : 
     204    18029458 :         uint32_t tmp = static_cast<unsigned char>(tolower(*s));
     205    18029458 :         uint32_t result = tmp << 24;
     206    18029458 :         if (*s == '\0') return result;
     207    17963448 :         tmp = static_cast<unsigned char>(tolower(*++s));
     208    17963448 :         result += tmp << 16;
     209    17963448 :         if (*s == '\0') return result;
     210    17896388 :         tmp = static_cast<unsigned char>(tolower(*++s));
     211    17896388 :         result += tmp << 8;
     212    17896388 :         if (*s == '\0') return result;
     213    17812108 :         result += static_cast<unsigned char>(tolower(*++s));
     214    17812108 :         return result;
     215             : }
     216             : 
     217             : char * strDuplicate (const char * str);
     218             : 
     219             : void   strCopyExclude (char * target, const char * original,
     220             :                        const char * excludeChars);
     221             : char * strAppend (char * target, const char * extra);
     222             : uint   strPad (char * target, const char * orig, int length, char pad);
     223             : const char * strFirstChar (const char * target, char matchChar);
     224             : const char * strLastChar (const char * target, char matchChar);
     225             : void   strStrip (char * str, char ch);
     226             : 
     227             : static const char WHITESPACE[6] = " \t\r\n";
     228             : const char * strTrimLeft (const char * target, const char * trimChars);
     229             : inline const char * strTrimLeft (const char * target) {
     230             :     return strTrimLeft (target, WHITESPACE);
     231             : }
     232             : uint   strTrimRight (char * target, const char * trimChars);
     233             : inline uint strTrimRight (char * target) {
     234          26 :     return strTrimRight (target, WHITESPACE);
     235             : }
     236             : uint   strTrimSuffix (char * target, char suffixChar);
     237             : void   strTrimDate (char * str);
     238             : void   strTrimMarkCodes (char * str);
     239             : void   strTrimMarkup (char * str);
     240             : void   strTrimSurname (char * str, uint initials);
     241             : inline void strTrimSurname (char * str) { strTrimSurname (str, 0); }
     242             : const char * strFirstWord (const char * str);
     243             : const char * strNextWord (const char * str);
     244             : 
     245             : // strPlural:
     246             : //    Returns the empty string if its parameter is 1, or "s" otherwise.
     247             : inline const char *
     248             : strPlural (uint x) {
     249             :     return (x == 1 ? "" : "s");
     250             : }
     251             : 
     252             : bool   strIsAllWhitespace (const char * str);
     253             : bool   strIsUnknownName (const char * str);
     254             : 
     255             : // strIsSurnameOnly: returns true if a string appears to only
     256             : //    contain a surname.
     257             : bool   strIsSurnameOnly (const char * name);
     258             : 
     259             : bool   strGetBoolean (const char * str);
     260             : 
     261             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     262             : // strGetInteger():
     263             : //    Extracts a signed base-10 value from a string.
     264             : //    Defaults to zero (as strtol does) for non-numeric strings.
     265             : inline int
     266             : strGetInteger(const char * str)
     267             : {
     268           0 :         return std::strtol(str, NULL, 10);
     269             : }
     270             : 
     271             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     272             : // strGetUnsigned():
     273             : //    Extracts an unsigned base-10 value from a string.
     274             : //    Defaults to zero (as strtoul does) for non-numeric strings.
     275             : //
     276      354583 : inline uint32_t strGetUnsigned(const char* str) {
     277      354583 :         ASSERT(str != NULL);
     278      354583 :         return static_cast<uint32_t>(std::strtoul(str, NULL, 10));
     279             : }
     280             : 
     281    19212628 : inline int strCaseCompare(const char* str1, const char* str2) {
     282    19212628 :         ASSERT(str1 != NULL && str2 != NULL);
     283             :         const unsigned char* s1 = reinterpret_cast<const unsigned char*>(str1);
     284             :         const unsigned char* s2 = reinterpret_cast<const unsigned char*>(str2);
     285             :         int c1, c2;
     286             :         do {
     287    21807213 :                 c1 = tolower(*s1++);
     288    21807213 :                 c2 = tolower(*s2++);
     289    21807213 :                 if (c1 == '\0')
     290             :                         break;
     291    21578025 :         } while (c1 == c2);
     292             : 
     293    19212628 :         return c1 - c2;
     294             : }
     295             : 
     296      175729 : inline int strCompareRound(const char* str1, const char* str2) {
     297      175729 :         ASSERT(str1 != NULL && str2 != NULL);
     298      175729 :         uint32_t a = strGetUnsigned(str1);
     299      176119 :         uint32_t b = strGetUnsigned(str2);
     300      176501 :         if (a == b)
     301       42128 :                 return strCaseCompare(str1, str2);
     302      134373 :         return (a < b) ? -1 : 1;
     303             : }
     304             : 
     305       56000 : inline bool strEqual(const char* str1, const char* str2) {
     306       56000 :         ASSERT(str1 != NULL && str2 != NULL);
     307       56000 :         return (std::strcmp(str1, str2) == 0);
     308             : }
     309             : 
     310             : void   strGetIntegers (const char * str, int * results, uint nResults);
     311             : void   strGetUnsigneds (const char * str, uint * results, uint nResults);
     312             : resultT strGetResult (const char * str);
     313             : 
     314             : typedef uint flagT;
     315             : const flagT FLAG_EMPTY = 0;
     316             : const flagT FLAG_YES = 1;
     317             : const flagT FLAG_NO = 2;
     318             : const flagT FLAG_BOTH = 3;
     319             : inline bool flag_Yes (flagT t) { return (t & FLAG_YES); }
     320             : inline bool flag_No (flagT t) { return (t & FLAG_NO); }
     321             : flagT  strGetFlag (const char * str);
     322             : 
     323             : squareT strGetSquare (const char * str);
     324             : 
     325             : inline uint
     326             : strTrimFileSuffix (char * target) { return strTrimSuffix (target, '.'); }
     327             : 
     328             : inline const char *
     329          12 : strFileSuffix (const char * target) { return strLastChar (target, '.'); }
     330             : 
     331             : 
     332             : 
     333             : int strUniqueExactMatch (const char * keyStr, const char ** strTable,
     334             :                          bool exact);
     335             : 
     336             : inline int strUniqueMatch (const char * keyStr, const char ** strTable) {
     337             :     return strUniqueExactMatch (keyStr, strTable, false);
     338             : }
     339             : inline int strExactMatch (const char * keyStr, const char ** strTable) {
     340             :     return strUniqueExactMatch (keyStr, strTable, true);
     341             : }
     342             : 
     343             : inline bool
     344             : strContainsChar (const char * str, char ch)
     345             : {
     346         220 :     while (*str) {
     347         185 :         if (*str == ch) { return true; }
     348         155 :         str++;
     349             :     }
     350             :     return false;
     351             : }
     352             : 
     353             : // WARNING: Avoid this function!
     354             : // Considering that the sign of a char is implementation-defined [3.9.1], the
     355             : // int conversion ("[4.7.3] If the destination type is signed, the value is
     356             : // unchanged if it can be represented in the destination type") can yield
     357             : // different results on different architectures or compilers.
     358             : // A better alternative is the standard function strcmp() that returns the
     359             : // difference between the values of the first pair of characters (both
     360             : // interpreted as unsigned char) that differ in the strings being compared.
     361   148701911 : inline int strCompare(const char* s1, const char* s2)
     362             : {
     363   148701911 :     ASSERT (s1 != NULL  &&  s2 != NULL);
     364             :     while (1) {
     365  1002012321 :         if (*s1 != *s2) {
     366   148541658 :             return ((int) *s1) - ((int) *s2);
     367             :         }
     368   426815458 :         if (*s1 == 0)
     369             :             break;
     370   426655205 :         s1++; s2++;
     371             :     }
     372             :     return 0;
     373             : }
     374             : 
     375             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     376             : // strCopy(): same as strcpy().
     377             : //
     378             : inline void
     379        4141 : strCopy (char * target, const char * original)
     380             : {
     381        4141 :     ASSERT (target != NULL  &&  original != NULL);
     382       50139 :     while (*original != 0) {
     383       22999 :         *target = *original;
     384       22999 :         target++;
     385       22999 :         original++;
     386             :     }
     387        4141 :     *target = 0;
     388        4141 : }
     389             : 
     390             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     391             : // strPrefix():
     392             : //       Returns the length of the common prefix of two strings.
     393             : //
     394             : inline uint
     395        2386 : strPrefix (const char * s1, const char * s2)
     396             : {
     397        2386 :     ASSERT (s1 != NULL  &&  s2 != NULL);
     398             :     uint count = 0;
     399       17472 :     while (*s1 == *s2) {
     400        7543 :         if (*s1 == 0) { // seen end of string, strings are identical
     401             :             return count;
     402             :         }
     403        7543 :         count++; s1++; s2++;
     404             :     }
     405             :     return count;
     406             : }
     407             : 
     408             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     409             : // strIsPrefix():
     410             : //      Returns true if the prefix string is a prefix of longStr.
     411             : inline bool
     412             : strIsPrefix (const char * prefix, const char * longStr)
     413             : {
     414        6000 :     while (*prefix) {
     415        6000 :         if (*longStr == 0) { return false; }
     416        6000 :         if (*prefix != *longStr) { return false; }
     417           0 :         prefix++;
     418           0 :         longStr++;
     419             :     }
     420             :     return true;
     421             : }
     422             : 
     423             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     424             : // strIsCasePrefix():
     425             : //      Returns true if the prefix string is a case-insensitive
     426             : //      prefix of longStr.
     427             : inline bool
     428           0 : strIsCasePrefix (const char * prefix, const char * longStr)
     429             : {
     430             :     typedef unsigned char U;
     431           0 :     while (*prefix) {
     432           0 :         if (*longStr == 0) { return false; }
     433           0 :         if (tolower(U(*prefix)) != tolower(U(*longStr))) { return false; }
     434           0 :         prefix++;
     435           0 :         longStr++;
     436             :     }
     437             :     return true;
     438             : }
     439             : 
     440             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     441             : // strIsAlphaPrefix():
     442             : //      Returns true if the prefix string is a prefix of longStr.
     443             : //      Unlike strIsPrexix(), this version is case-insensitive and
     444             : //      spaces are ignored.
     445             : //      Example: strIsAlphaPrefix ("smith,j", "Smith, John") == true.
     446             : inline bool
     447           0 : strIsAlphaPrefix (const char * prefix, const char * longStr)
     448             : {
     449             :     typedef unsigned char U;
     450           0 :     while (*prefix) {
     451           0 :         while (*prefix == ' ') { prefix++; }
     452           0 :         while (*longStr == ' ') { longStr++; }
     453           0 :         if (*longStr == 0) { return false; }
     454           0 :         if (tolower(U(*prefix)) != tolower(U(*longStr))) { return false; }
     455           0 :         prefix++;
     456           0 :         longStr++;
     457             :     }
     458             :     return true;
     459             : }
     460             : 
     461             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     462             : // strContains():
     463             : //      Returns true if longStr contains an occurrence of keyStr,
     464             : //      case-sensitive and NOT ignoring any characters such as spaces.
     465             : inline bool
     466             : strContains (const char * longStr, const char * keyStr)
     467             : {
     468             :     while (*longStr) {
     469             :         if (strIsPrefix (keyStr, longStr)) { return true; }
     470             :         longStr++;
     471             :     }
     472             :     return false;
     473             : }
     474             : 
     475             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     476             : // strAlphaContains():
     477             : //      Returns true if longStr contains an occurrence of keyStr,
     478             : //      case-insensitive and ignoring spaces.
     479             : //      Example: strAlphaContains ("Smith, John", "th,j") == true.
     480             : //
     481             : inline bool
     482             : strAlphaContains (const char * longStr, const char * keyStr)
     483             : {
     484             :     while (*longStr) {
     485             :         if (strIsAlphaPrefix (keyStr, longStr)) { return true; }
     486             :         longStr++;
     487             :     }
     488             :     return false;
     489             : }
     490             : 
     491             : inline uint
     492     3417995 : strLength (const char * str)
     493             : {
     494     3417995 :     ASSERT(str != NULL);
     495             :     uint len = 0;
     496    46971939 :     while (*str != 0) { len++; str++; }
     497     3417995 :     return len;
     498             : }
     499             : 
     500             : 
     501             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     502             : // strTrimRight():
     503             : //      Trims the provided string in-place, removing the
     504             : //      end characters that match the trimChars.
     505             : //      Returns the number of characters trimmed.
     506             : //      E.g., strTrimRight("abcyzyz", "yz") would leave the string
     507             : //      as "abc" and return 4.
     508        4026 : inline uint strTrimRight (char* target, const char* trimChars)
     509             : {
     510        4026 :         int oldSz = strlen(target);
     511        4026 :         int sz = oldSz;
     512        4064 :         while (--sz >= 0) {
     513        4116 :                 if (std::strchr(trimChars, target[sz]) == 0) break;
     514             :         }
     515        4026 :         if (++sz == oldSz) return 0;
     516          18 :         target[sz] = 0;
     517          18 :         return oldSz - sz;
     518             : }
     519             : 
     520             : 
     521             : //////////////////////////////////////////////////////////////////////
     522             : //   FILE I/O Routines.
     523             : // TODO: remove this functions
     524             : 
     525             : uint    fileSize (const char * name, const char * suffix);
     526             : uint    rawFileSize (const char * name);
     527             : uint    gzipFileSize (const char * name);
     528             : 
     529             : #endif  // #ifdef SCID_MISC_H
     530             : 
     531             : //////////////////////////////////////////////////////////////////////
     532             : //  EOF: misc.h
     533             : //////////////////////////////////////////////////////////////////////
     534             : 

Generated by: LCOV version 1.12