Search code examples
c++stlcase-insensitive

Case-Insensitive STL Containers (e.g. std::unordered_set)


What is the shortest, most cross-platform way to make a std::unordered_set CASE-INSENSITIVE container?

my_set.insert("Apples");  
my_set.insert("apples"); //Insert doesn't occur because of duplicate item

I know STL provides Hash and Pred. What should Hash be? What should Pred be? if they are not-builtins then please provide the code for them along with an example of their use (i.e. how do I declare std::unordered_set?).

Due to the Criticism I will elaborate on what I am trying to do. I need a high performance transparent HTTP proxy server, one of the things it does is looks up HTTP header fields quickly. HTTP header fields are defined as being case-insensitive so I need a case-insensitive container.


Solution

  • The definition of unordered_set is

      template <class Value,
                class Hash = hash<Value>,
                class Pred = std::equal_to<Value>,
                class Alloc = std::allocator<Value> >
      class unordered_set;
    

    If you provide Hash and Pred functors that are case-insensitive, then the set will become so too.

    This is a simple example, the string hash function is simplistic but you can change it to your needs

    struct MyHash
    {
        size_t operator()(const std::string& Keyval) const
        {
            //You might need a better hash function than this
            size_t h = 0;
            std::for_each( Keyval.begin() , Keyval.end() , [&](char c )
            {
                h += tolower(c);
            });
            return h;
        }
    };
    
    struct MyEqual
    {
        bool operator()(const std::string& Left, const std::string& Right) const
        {
            return Left.size() == Right.size() 
                 && std::equal ( Left.begin() , Left.end() , Right.begin() ,
                []( char a , char b )
            {
                return tolower(a) == tolower(b); 
            }
            );
        }
    };
    
    
    int main()
    {
        std::unordered_set< std::string , MyHash , MyEqual > m;
    
        m.insert( "Apple" );
        m.insert( "apple" );
    
        return 0;
    }