0

Firstly,I want to inform you that my overall/main target is to execute certain functions using their function name(string) as an argument,I defined a function as below: (I want to generate a unique number for each string data that I inserted as argument to a function)

    #include <iostream>
    #include <string>
    #include <hash_set>

    using namespace std;
    void Func_Execution(string &s){
        int k=stdext::hash_value(s);
     #if(_MSC_VER ==1500)
        switch (k)
        {
        case -336300864: GETBATTERYCALLSIGNS();
            break;
        case -1859542241:GETGUNIDS();
            break;
        case 323320073:Foo(); // here int k=323320073 for string s="Foo"
            break;
        case 478877555:Bar();
            break;
            defalut :Exit();
               break;
         }
    #endif
    }

Here I call Func_Execution function as below:

void main(){
string s="Foo";
Func_Execution(s);
}

I want to know that is there any efficient(considering perfomance/time consuming) and effective mechanism to generate a unique numerical value for certain string(character pattern) rather than using stdext::hash_value() function?(Also notice I want to implement switch-case too)

Buddhika Chaturanga
  • 957
  • 2
  • 14
  • 29
  • That `#endif` is misplaced. – Some programmer dude Oct 31 '13 at 05:37
  • Also, are you sure that the `hash_value` function will return the same hash for a certain string *always*? Even if you update the compiler/library? On all supported platforms? – Some programmer dude Oct 31 '13 at 05:39
  • yeah you get same int value for a certain string even if you run program on seperate instances -> for VSC++ v9 and VSC++ v10 those(int value) are same, checked those.But for VSC++ v11 and VSC++ v12 too differ,The hashing value does not depends upon the running instance,depends on compiler version if you use Platform Toolset v(90) and v(100) you will get same value for int k,but for v(110) and v(120) has different values. – Buddhika Chaturanga Oct 31 '13 at 05:41
  • Is your primary reason for doing this just to be able to write a nice switch statement on strings? – Charlie Oct 31 '13 at 05:51
  • Kind of,your convenience I'd like to wrap this like this -> think you have 1450 set of functions,all are with non-return(void) and with no arguments(void)-"void foo()"; so your application only requires the name of the function as a string from the user,then your application has a capability to execute certain function who has the samename(do not consider function overloading stuff here),so you could have different approaches:using if-else if;therefore you should have at least 1476 string comparison,rather than doing that using switching it's so easy and has ability to directly call the funct' – Buddhika Chaturanga Oct 31 '13 at 05:59

2 Answers2

1

Have you considered something like

#include <functional>
#include <iostream>
#include <unordered_map>
#include <string>

using std::cout;
using std::endl;
using std::function;
using std::string;
using std::unordered_map;

class Registry {
 public:
  static void Execute(const string& function) {
    if (functions_.find(function) != functions_.end()) {
      functions_[function]();
    }
  }
  static int Register(const string& function_name, function<void()> f) {
    functions_.emplace(function_name, f);
    return functions_.size();
  }
  static void Dump() {
    for (auto& i : functions_) {
      cout << i.first << endl;
    }
  }
 private:
  Registry() {};
  static unordered_map<string, function<void()>> functions_;
};

unordered_map<string, function<void()>> Registry::functions_;

#define REGISTER_FUNCTION(F) \
  namespace { \
   const int REGISTERED__##F = Registry::Register(#F, &F); \
  } 

void foo() {
  cout << "foo" << endl;
}

REGISTER_FUNCTION(foo);

void bar() {
  cout << "bar" << endl;
}

REGISTER_FUNCTION(bar);

int main() {
  Registry::Execute("foo");
  Registry::Execute("foo");
  Registry::Execute("unknown");
  Registry::Dump();
  return 0;
}

It should serve well for your use case. I just hacked it together, there's probably a bug somewhere, but it compiles and runs (c++11).

Charlie
  • 1,487
  • 10
  • 9
  • But It's relies on C++ 11,Here I have to deal with VSC++ v90/v100 :( – Buddhika Chaturanga Oct 31 '13 at 08:29
  • 1
    The only C++11 dependencies are the unordered_map and std::function which can be easily removed. – user1233963 Oct 31 '13 at 09:22
  • @BuddhikaChaturanga Add in a `typedef void (*void_function)(void)` and replace `function` with `void_function`, and use `functions_[function_name] = f;` instead of the emplace variation. you can replace unordered_map with map or one of the many hash_map implemenations that ship with compilers. Everything else works. – Charlie Oct 31 '13 at 09:29
  • thanks,But still I have doubt,that generating unique hashvalue from hash_set library => ` stdext::hash_value()` not a good manner? – Buddhika Chaturanga Oct 31 '13 at 09:33
  • If you implement as a switch with 1450 possible functions, not only do you need to maintain hash values for all of the function names, but you need to maintain the switch statement. On top of that, while small switch statements are often optimized to a jump table, particularly small ones with dense sets of values, a switch statement with 1450 elements will likely be done as a series of comparisons (same code generated as the if/else-if style on the hashes). The registration mechanism falls back to a hash table (~2 compares) or red-black tree lookup with ~12 compares on average. – Charlie Oct 31 '13 at 09:54
  • Oh!,that means switch statement which has more than 100 or something performing as if/else if statements? not exactly following jump table? – Buddhika Chaturanga Nov 01 '13 at 06:18
  • A switch statement with a few elements that are densely packed can sometimes be optimized to a jump table. A switch statement with lots of elements that are sparsely packed will often end up being a cascading if-else set. The compiler could, in theory, do something smarter - binary search or something on the values, but that's about the best you can do. On top of that, you still need to deal with maintaining your switch statement in the face of compiler and library changes, and the code you've got isn't portable at all. The registration technique I gave should work everywhere. – Charlie Nov 01 '13 at 21:49
0

Don't use hash_value() for fingerprinting (which is what you are describing). If you really know all your possible strings ahead of time, use your own perfect hash function and then measure the results to see if it is worth it.

Nevin
  • 4,595
  • 18
  • 24