(file) Return to strhash.cpp CVS log (file) (dir) Up to [OMI] / omi / strhash

Diff for /omi/strhash/strhash.cpp between version 1.2 and 1.3

version 1.2, 2015/04/20 18:10:35 version 1.3, 2015/04/20 18:20:35
Line 35 
Line 35 
 using namespace std; using namespace std;
 const char* arg0; const char* arg0;
  
 typedef pair<string, string> Pair;  struct Tuple
 typedef vector<Pair> Vector;  {
       Tuple(char ch_, const string& str_, const string& tag_) :
           ch(ch_), str(str_), tag(tag_)
       {
       }
   
       char ch;
       string str;
       string tag;
   };
   
   typedef vector<Tuple> Vector;
   
   string BaseName(const string& name)
   {
       string base = name;
   
       size_t pos = base.rfind('/');
   
       if (pos != string::npos)
           base = base.substr(pos + 1);
   
       pos = base.rfind('.');
   
       if (pos != string::npos)
           base = base.substr(0, pos);
  
 void LoadSpecFile(const char* path, Vector& pairs)      return base;
   }
   
   void LoadSpecFile(const char* path, Vector& tuples)
 { {
     // Open input file:     // Open input file:
     FILE* is = fopen(path, "r");     FILE* is = fopen(path, "r");
Line 59 
Line 87 
         vector<string> toks;         vector<string> toks;
         char* str;         char* str;
         char* tag;         char* tag;
           char ch;
  
         // Skip leading spaces:         // Skip leading spaces:
         for (p = buf; isspace(*p); p++)         for (p = buf; isspace(*p); p++)
Line 75 
Line 104 
                 *--end = '\0';                 *--end = '\0';
         }         }
  
         // Expect string          // Ignore empty lines:
   
           if (*p == '\0')
               continue;
   
           // Get tag:
         {         {
             str = p;              ch = *p++;
   
               if (!isalpha(ch) && ch != '0')
               {
                   fprintf(stderr, "%s: expected character identifier: %u\n", arg0, line);
                   exit(1);
               }
  
             while (*p && *p != ',')             while (*p && *p != ',')
                 p++;                 p++;
         }  
  
         // Skip spaces:         // Skip spaces:
         while (isspace(*p))         while (isspace(*p))
             p++;             p++;
  
         if (!*p)              // Expect ','
               if (*p != ',')
         {         {
             char buf[32];                  fprintf(stderr, "%s: expected comma and then string: %u\n", arg0, line);
             sprintf(buf, "TAG%u", line);                  exit(1);
             pairs.push_back(Pair(str, buf));  
             continue;  
         }         }
  
         // Expect ':'              p++;
           }
   
           // Skip spaces:
           while (isspace(*p))
               p++;
   
           // Get string:
           {
               str = p;
   
               while (*p && *p != ',')
                   p++;
   
               // Skip spaces:
               while (isspace(*p))
                   p++;
   
               // Expect ','
         if (*p != ',')         if (*p != ',')
         {         {
             fprintf(stderr, "%s: syntax error on line %u\n", arg0, line);                  fprintf(stderr, "%s: expected comman and then tag name: %u\n", arg0, line);
             exit(1);             exit(1);
         }         }
  
         *p++ = '\0';         *p++ = '\0';
           }
  
         // Skip spaces:         // Skip spaces:
         while (isspace(*p))         while (isspace(*p))
Line 134 
Line 191 
             exit(1);             exit(1);
         }         }
  
         pairs.push_back(Pair(str, tag));          tuples.push_back(Tuple(ch, str, tag));
     }     }
 } }
  
 static void _GenEnum(FILE* f, const Vector& pairs)  static void _GenEnum(FILE* f, const Vector& tuples)
 { {
     // Generate enumeration:     // Generate enumeration:
     {     {
         fprintf(f, "enum\n");         fprintf(f, "enum\n");
         fprintf(f, "{\n");         fprintf(f, "{\n");
  
         for (size_t i = 0; i < pairs.size(); i++)          for (size_t i = 0; i < tuples.size(); i++)
         {         {
             fprintf(f, "    %s = %u%s\n", pairs[i].second.c_str(), (int)(i + 1), ((i+1) == pairs.size() ? "" : ","));              fprintf(f, "    %s = %u%s\n",
                   tuples[i].tag.c_str(),
                   (int)(i + 1),
                   ((i+1) == tuples.size() ? "" : ","));
         }         }
  
         fprintf(f, "};\n");         fprintf(f, "};\n");
Line 155 
Line 215 
     }     }
 } }
  
 #if 0  typedef multimap<unsigned int, Tuple> Map;
 static void GenSimpleFunction(const char* fileName, const Vector& pairs)  typedef pair<unsigned int, Tuple> MTuple;
 {  static void _GenStringCmp(FILE* f, const Tuple& p)
     FILE* f = fopen(fileName, "w");  {
       char ch = p.ch;
     if (!f)      const string& str = p.str.c_str();
     {      const string& tok = p.tag.c_str();
         fprintf(stderr, "%s: failed to open: %s\n", arg0, fileName);  
         exit(1);  
     }  
   
   
     //_GenEnum(f, pairs);  
   
     /* header */  
     fprintf(f, "static int SimpleStr(const char* s, size_t n)\n");  
     fprintf(f, "{\n");  
   
     /* generate function body */  
     fprintf(f, "n=n;\n   ");  
     for (size_t i = 0; i < pairs.size(); i++)  
     {  
         const string& str = pairs[i].first.c_str();  
         const string& tok = pairs[i].second.c_str();  
   
         fprintf(f, " if (strcmp(s, \"%s\") == 0)\n",  
                str.c_str());  
  
         fprintf(f, "        ");         fprintf(f, "        ");
         fprintf(f, "return %s;\n", tok.c_str());  
         fprintf(f, "    else");  
     }  
   
     fprintf(f, "\n        return 0; /* not found */\n");  
   
     /* close the function */  
     //fprintf(f, "\n");  
     fprintf(f, "}\n\n");  
   
   
     fclose(f);  
 }  
 #endif  
   
 #if 0  
 static void GenHashFunction(const char* fileName, const Vector& pairs)  
 {  
     FILE* f = fopen(fileName, "w");  
   
     if (!f)  
     {  
         fprintf(stderr, "%s: failed to open: %s\n", arg0, fileName);  
         exit(1);  
     }  
   
   
     //_GenEnum(f, pairs);  
   
     // Generate function  
     {  
         typedef pair<unsigned int, Vector> MPair;  
         typedef map<unsigned int, Vector> Map;  
         Map m;  
   
         fprintf(f, "int HashStr(const char* s, size_t n)\n");  
         fprintf(f, "{\n");  
         fprintf(f, "    unsigned int h = (unsigned int)(n ^ s[0] ^ s[n-1]);\n");  
         fprintf(f, "\n");  
         fprintf(f, "    switch (h)\n");  
         fprintf(f, "    {\n");  
  
         // Conslidate pairs with like hash codes      if (ch == '0')
         for (size_t i = 0; i < pairs.size(); i++)  
         {         {
             const char* s = pairs[i].first.c_str();          fprintf(f, "if (HASHSTR_STRCMP(s, HASHSTR_T(\"%s\")) == 0)\n",
             size_t n = pairs[i].first.size();              str.c_str());
             unsigned int h = n ^ s[0] ^ s[n-1];  
   
             Map::iterator pos = m.find(h);  
   
             if (pos == m.end())  
             {  
                 Vector v;  
                 v.push_back(pairs[i]);  
                 m.insert(MPair(h,v));  
             }             }
             else             else
             {             {
                 (*pos).second.push_back(pairs[i]);          fprintf(f, "if (c == '%c' && HASHSTR_STRCMP(s, HASHSTR_T(\"%s\")) == 0)\n",
               ch, str.c_str());
             }             }
         }  
   
         // Print cases:  
         for (Map::iterator p = m.begin(); p != m.end(); p++)  
         {  
             const Vector& v = (*p).second;  
   
             fprintf(f, "        case %u:\n", (*p).first);  
   
             for (size_t i = 0; i < v.size(); i++)  
             {  
                 const string& str = v[i].first.c_str();  
                 const string& tok = v[i].second.c_str();  
   
                 fprintf(f, "            ");  
                 fprintf(f, "if (n == %u && memcmp(s, \"%s\", n) == 0)\n",  
                     (int)str.size(), str.c_str());  
   
                 fprintf(f, "                ");  
                 fprintf(f, "return %s;\n", tok.c_str());  
             }  
   
             fprintf(f, "            break;\n");  
         }  
   
         fprintf(f, "    }\n");  
         fprintf(f, "    /* Not found */\n");  
         fprintf(f, "    return 0;\n");  
         fprintf(f, "}\n");  
     }  
     fclose(f);  
 }  
 #endif  
   
 typedef multimap<unsigned int, Pair> Map;  
 typedef pair<unsigned int, Pair> MPair;  
 static void _GenStringCmp(FILE* f, const Pair& p)  
 {  
     const string& str = p.first.c_str();  
     const string& tok = p.second.c_str();  
   
     fprintf(f, "            ");  
     fprintf(f, "if (strcmp(s, \"%s\") == 0)\n",  
             str.c_str());  
  
     fprintf(f, "                ");     fprintf(f, "                ");
     fprintf(f, "return %s;\n", tok.c_str());     fprintf(f, "return %s;\n", tok.c_str());
Line 313 
Line 259 
  
         for ( Map::const_iterator it = pos; it != range_end; it++ )         for ( Map::const_iterator it = pos; it != range_end; it++ )
         {         {
             unsigned char c = it->second.first[index];              unsigned char c = it->second.str[index];
             collisions[c]++;             collisions[c]++;
             if (collisions[c] > currentMax)             if (collisions[c] > currentMax)
                 currentMax = collisions[c];                 currentMax = collisions[c];
Line 345 
Line 291 
  
     for ( Map::const_iterator it = pos; it != range_end; it++ )     for ( Map::const_iterator it = pos; it != range_end; it++ )
     {     {
         unsigned char c = it->second.first[bestIndex];          unsigned char c = it->second.str[bestIndex];
  
         subMap.insert(MPair(c, it->second));          subMap.insert(MTuple(c, it->second));
     }     }
  
     fprintf(f, "        switch (s[%u])\n", bestIndex);     fprintf(f, "        switch (s[%u])\n", bestIndex);
Line 382 
Line 328 
  
 } }
  
   static void GenDoNotEditMessage(
       FILE* f)
   {
       fprintf(f, "/*\n");
       fprintf(f, "**==============================================================================\n");
       fprintf(f, "**\n");
       fprintf(f, "** DO NOT EDIT THIS FILE!!! IT WAS AUTOMATICALLY GENERATED\n");
       fprintf(f, "**\n");
       fprintf(f, "**==============================================================================\n");
       fprintf(f, "*/\n");
       fprintf(f, "\n");
   }
   
 static void GenHashStrHeader( static void GenHashStrHeader(
     const string& fileName,     const string& fileName,
     const Vector& pairs)      const Vector& tuples)
 { {
     FILE* f = fopen(fileName.c_str(), "w");     FILE* f = fopen(fileName.c_str(), "w");
  
Line 394 
Line 353 
         exit(1);         exit(1);
     }     }
  
     _GenEnum(f, pairs);      GenDoNotEditMessage(f);
   
       string base = BaseName(fileName);
   
       fprintf(f, "#ifndef _%s_h\n", base.c_str());
       fprintf(f, "#define _%s_h\n", base.c_str());
       fprintf(f, "\n");
   
       _GenEnum(f, tuples);
   
       fprintf(f, "#if !defined(HASHSTR_CHAR)\n");
       fprintf(f, "# define HASHSTR_CHAR char\n");
       fprintf(f, "#endif\n\n");
   
       fprintf(f, "#if !defined(HASHSTR_T)\n");
       fprintf(f, "# define HASHSTR_T(STR) STR\n");
       fprintf(f, "#endif\n\n");
   
       fprintf(f, "#if !defined(HASHSTR_STRCMP)\n");
       fprintf(f, "# define HASHSTR_STRCMP strcmp\n");
       fprintf(f, "#endif\n\n");
  
     /* file header */     /* file header */
     fprintf(f, "int HashStr(const char* s, size_t n);\n");      fprintf(f, "int HashStr(HASHSTR_CHAR c, const HASHSTR_CHAR* s, size_t n);\n");
     fprintf(f, "\n");     fprintf(f, "\n");
  
       fprintf(f, "#endif /* %s_h */\n", base.c_str());
   
     printf("Created %s\n", fileName.c_str());     printf("Created %s\n", fileName.c_str());
 } }
  
 static void GenHashStrFunction(  static void GenFastHashStrFunction(
     const string& fileName,     const string& fileName,
     const Vector& pairs)      const string& base,
       const Vector& tuples)
 { {
     FILE* f = fopen(fileName.c_str(), "w");     FILE* f = fopen(fileName.c_str(), "w");
  
Line 415 
Line 397 
         exit(1);         exit(1);
     }     }
  
     //_GenEnum(f, pairs);      GenDoNotEditMessage(f);
   
       fprintf(f, "#include \"%s.h\"\n", base.c_str());
       fprintf(f, "\n");
  
     /* file header */     /* file header */
     fprintf(f, "int HashStr(const char* s, size_t n)\n");      fprintf(f, "int HashStr(HASHSTR_CHAR c, const HASHSTR_CHAR* s, size_t n)\n");
     fprintf(f, "{\n");     fprintf(f, "{\n");
     fprintf(f, "\n");     fprintf(f, "\n");
     fprintf(f, "    switch (n)\n");     fprintf(f, "    switch (n)\n");
Line 427 
Line 412 
  
     Map m;     Map m;
  
     // Conslidate pairs with like str length      // Conslidate tuples with like str length
     for (size_t i = 0; i < pairs.size(); i++)      for (size_t i = 0; i < tuples.size(); i++)
     {     {
         size_t n = pairs[i].first.size();          size_t n = tuples[i].str.size();
  
         m.insert(MPair(n, pairs[i]));          m.insert(MTuple(n, tuples[i]));
     }     }
  
   
     // generate cases for each length     // generate cases for each length
     Map::const_iterator pos = m.begin();     Map::const_iterator pos = m.begin();
  
Line 479 
Line 463 
     printf("Created %s\n", fileName.c_str());     printf("Created %s\n", fileName.c_str());
 } }
  
 #if 0  static void GenSmallHashStrFunction(
 static void GenUnittest(const char* fileName, const Vector& pairs)      const string& fileName,
       const string& base,
       const Vector& tuples)
 { {
     FILE* f = fopen(fileName, "w");      FILE* f = fopen(fileName.c_str(), "w");
  
     if (!f)     if (!f)
     {     {
         fprintf(stderr, "%s: failed to open: %s\n", arg0, fileName);          fprintf(stderr, "%s: failed to open: %s\n", arg0, fileName.c_str());
         exit(1);         exit(1);
     }     }
  
     /* file header */      GenDoNotEditMessage(f);
     fprintf(f, "#include <ut/ut.h>\n");  
     fprintf(f, "#include <string.h>\n");  
     fprintf(f, "#include \"../quickstr.h\"\n");  
     fprintf(f, "#include \"../quickstr.inc\"\n");  
     fprintf(f, "#include \"hash.inc\"\n");  
     fprintf(f, "#include \"simple.inc\"\n");  
  
       fprintf(f, "#include \"%s.h\"\n", base.c_str());
     fprintf(f, "\n");     fprintf(f, "\n");
     fprintf(f, "static void setUp()\n{\n}\n");  
     fprintf(f, "static void cleanup()\n{\n}\n");  
   
     fprintf(f, "typedef int (*FN)(const char* s, size_t n);\n");  
  
     fprintf(f, "static void testAllStrings(FN f)\n{\n");      Map m;
  
     /* generate all tests */      // Conslidate tuples with like hash code:
     for (size_t i = 0; i < pairs.size(); i++)      for (size_t i = 0; i < tuples.size(); i++)
     {     {
         const string& str = pairs[i].first.c_str();          const string& s = tuples[i].str;
         const string& tok = pairs[i].second.c_str();  
  
         fprintf(f, "    UT_ASSERT((*f)(\"%s\", %u) == %s);\n",          size_t n = tuples[i].str.size();
                 str.c_str(), (int)str.size(), tok.c_str() );  
  
      }          unsigned char h = (unsigned char)s[0] ^ (unsigned char)s[n-1] ^ (unsigned char)n;
  
     /* add comparison with not-exisitng strings */          m.insert(MTuple(h, tuples[i]));
     fprintf(f, "    UT_ASSERT((*f)(\"*\", 1) == 0);\n") ;      }
     fprintf(f, "    UT_ASSERT((*f)(\"**\", 2) == 0);\n") ;  
     fprintf(f, "    UT_ASSERT((*f)(\"***\", 3) == 0);\n") ;  
     fprintf(f, "    UT_ASSERT((*f)(\"****\", 4) == 0);\n") ;  
     fprintf(f, "    UT_ASSERT((*f)(\"*****\", 5) == 0);\n") ;  
     fprintf(f, "    UT_ASSERT((*f)(\"******\", 6) == 0);\n") ;  
  
       // generate cases for each length
       Map::const_iterator pos = m.begin();
  
     /* Generate end of unittest file  */      fprintf(f, "typedef struct _HashStrTuple\n");
     fprintf(f, "}\n\n");  
     fprintf(f, "static void TestSimple()\n");  
     fprintf(f, "{\n");     fprintf(f, "{\n");
     fprintf(f, "    for(int i=0; i< 10000; i++) testAllStrings(SimpleStr);\n");      fprintf(f, "    unsigned char code;\n");
       fprintf(f, "    char ch;\n");
       fprintf(f, "    unsigned short tag;\n");
       fprintf(f, "    const HASHSTR_CHAR* str;\n");
     fprintf(f, "}\n");     fprintf(f, "}\n");
       fprintf(f, "HashStrTuple;\n");
     fprintf(f, "\n");     fprintf(f, "\n");
  
     fprintf(f, "static void TestHash()\n");      fprintf(f, "static const HashStrTuple _tuples[] =\n");
     fprintf(f, "{\n");     fprintf(f, "{\n");
     fprintf(f, "    for(int i=0; i< 10000; i++) testAllStrings(HashStr);\n");  
       while (pos != m.end())
       {
           unsigned int h = pos->first;
           const Tuple& t = pos->second;
   
           // Lookup tag id:
   
           size_t tag = size_t(-1);
   
           for (size_t i = 0; i < tuples.size(); i++)
           {
               if (tuples[i].tag == t.tag)
               {
                   tag = i + 1;
               }
           }
   
           if (tag == size_t(-1))
           {
               fprintf(stderr, "%s: tag not found: %s\n", arg0, t.tag.c_str());
               exit(1);
           }
   
           fprintf(f, "    {\n");
           fprintf(f, "        0x%02X, /* code */\n", h);
   
           if (t.ch == '0')
               fprintf(f, "        0, /* ch */\n");
           else
               fprintf(f, "        '%c', /* ch */\n", t.ch);
   
           fprintf(f, "        %s,\n", t.tag.c_str());
           fprintf(f, "        HASHSTR_T(\"%s\")\n", t.str.c_str());
           fprintf(f, "    },\n");
   
           pos++;
       }
   
       fprintf(f, "    {\n");
       fprintf(f, "        0xFF, /* code */\n");
     fprintf(f, "}\n");     fprintf(f, "}\n");
   
       fprintf(f, "};\n");
       fprintf(f, "\n");
       fprintf(f, "static const size_t _ntuples = sizeof(_tuples) / sizeof(_tuples[0]) - 1;\n");
     fprintf(f, "\n");     fprintf(f, "\n");
  
     fprintf(f, "static void TestHashStr()\n");      /* file header */
       fprintf(f, "int HashStr(HASHSTR_CHAR c, const HASHSTR_CHAR* s, size_t n)\n");
     fprintf(f, "{\n");     fprintf(f, "{\n");
     fprintf(f, "    for(int i=0; i< 10000; i++) testAllStrings(HashStr);\n");      fprintf(f, "\n");
     fprintf(f, "}\n");      fprintf(f, "    size_t i;\n");
       fprintf(f, "    size_t j;\n");
       fprintf(f, "    unsigned char h = (unsigned char)s[0] ^ (unsigned char)s[n-1] ^ (unsigned char)n;\n");
     fprintf(f, "\n");     fprintf(f, "\n");
  
     fprintf(f, "static void RunTests()\n");      fprintf(f, "    for (i = 0; h > _tuples[i].code; i++)\n");
       fprintf(f, "        ;\n");
       fprintf(f, "\n");
       fprintf(f, "    for (j = i; j < _ntuples && h == _tuples[j].code; j++)\n");
     fprintf(f, "{\n");     fprintf(f, "{\n");
     fprintf(f, "    UT_TEST(TestSimple);\n");      fprintf(f, "        if (c == _tuples[j].ch && HASHSTR_STRCMP(s, _tuples[j].str) == 0)\n");
     fprintf(f, "    UT_TEST(TestHash);\n");      fprintf(f, "            return _tuples[j].tag;\n");
     fprintf(f, "    UT_TEST(TestHashStr);\n");  
     fprintf(f, "}\n");     fprintf(f, "}\n");
   
     fprintf(f, "\n");     fprintf(f, "\n");
     fprintf(f, "UT_ENTRY_POINT(RunTests);\n");  
  
       // ATTN:
   
       fprintf(f, "    /* Not found */\n");
       fprintf(f, "    return 0;\n");
       fprintf(f, "}\n");
  
     fclose(f);     fclose(f);
   
       printf("Created %s\n", fileName.c_str());
 } }
 #endif  
  
 int main(int argc, char** argv) int main(int argc, char** argv)
 { {
Line 570 
Line 599 
         exit(1);         exit(1);
     }     }
  
     Vector pairs;      Vector tuples;
     LoadSpecFile(argv[1], pairs);      LoadSpecFile(argv[1], tuples);
  
     if (pairs.empty())  #if 0
       for (size_t i = 0; i < tuples.size(); i++)
     {     {
         fprintf(stderr, "no data for building hash function\n");          const Tuple& t = tuples[i];
         exit(1);          printf("{%c}{%s}{%s}\n", t.ch, t.str.c_str(), t.tag.c_str());
     }     }
   
 #if 0  
     GenSimpleFunction("simple.inc", pairs);  
     GenHashFunction("hash.inc", pairs);  
 #endif #endif
  
     // Determine the base filename:      if (tuples.empty())
     string base = argv[1];  
     {     {
         size_t pos = base.rfind('/');          fprintf(stderr, "no data for building hash function\n");
           exit(1);
         if (pos != string::npos)  
             base = base.substr(pos + 1);  
   
         pos = base.rfind('.');  
   
         if (pos != string::npos)  
             base = base.substr(0, pos);  
     }     }
  
     GenHashStrHeader(base + ".h", pairs);      // Determine the base filename:
     GenHashStrFunction(base + ".inc", pairs);      string base = BaseName(argv[1]);
  
 #if 0      GenHashStrHeader(base + ".h", tuples);
     GenUnittest("tests/test_strhash.cpp", pairs);      GenFastHashStrFunction(base + "_quick.inc", base, tuples);
 #endif      GenSmallHashStrFunction(base + "_small.inc", base, tuples);
  
     return 0;     return 0;
 } }


Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3

ViewCVS 0.9.2