]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/hashcomp.h
Update copyrights for 2009.
[user/henk/code/inspircd.git] / include / hashcomp.h
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *          the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #ifndef _HASHCOMP_H_
15 #define _HASHCOMP_H_
16
17 #include <cstring>
18 #include "hash_map.h"
19
20 /*******************************************************
21  * This file contains classes and templates that deal
22  * with the comparison and hashing of 'irc strings'.
23  * An 'irc string' is a string which compares in a
24  * case insensitive manner, and as per RFC 1459 will
25  * treat [ identical to {, ] identical to }, and \
26  * as identical to |.
27  *
28  * Our hashing functions are designed  to accept
29  * std::string and compare/hash them as type irc::string
30  * by converting them internally. This makes them
31  * backwards compatible with other code which is not
32  * aware of irc::string.
33  *******************************************************/
34
35 #ifndef LOWERMAP
36 #define LOWERMAP
37
38 /** A mapping of uppercase to lowercase, including scandinavian
39  * 'oddities' as specified by RFC1459, e.g. { -> [, and | -> \
40  */
41 unsigned const char rfc_case_insensitive_map[256] = {
42         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,                                   /* 0-19 */
43         20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,                         /* 20-39 */
44         40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,                         /* 40-59 */
45         60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,             /* 60-79 */
46         112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 94, 95, 96, 97, 98, 99,           /* 80-99 */
47         100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,     /* 100-119 */
48         120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,     /* 120-139 */
49         140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,     /* 140-159 */
50         160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,     /* 160-179 */
51         180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,     /* 180-199 */
52         200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,     /* 200-219 */
53         220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,     /* 220-239 */
54         240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255                          /* 240-255 */
55 };
56
57 /** Seperate from the other casemap tables so that code *can* still exclusively rely on RFC casemapping
58  * if it must.
59  *
60  * This is provided as a pointer so that modules can change it to their custom mapping tables,
61  * e.g. for national character support.
62  */
63 extern unsigned const char *national_case_insensitive_map;
64
65 /** Case insensitive map, ASCII rules.
66  * That is;
67  * [ != {, but A == a.
68  */
69 unsigned const char ascii_case_insensitive_map[256] = {
70         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,                                   /* 0-19 */
71         20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,                         /* 20-39 */
72         40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,                         /* 40-59 */
73         60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,             /* 60-79 */
74         112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,              /* 80-99 */
75         100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,     /* 100-119 */
76         120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,     /* 120-139 */
77         140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,     /* 140-159 */
78         160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,     /* 160-179 */
79         180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,     /* 180-199 */
80         200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,     /* 200-219 */
81         220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,     /* 220-239 */
82         240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255                          /* 240-255 */
83 };
84
85 /** Case sensitive map.
86  * Can technically also be used for ASCII case sensitive comparisons, as [ != {, etc.
87  */
88 unsigned const char rfc_case_sensitive_map[256] = {
89         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
90         21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
91         41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
92         61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
93         81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
94         101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
95         121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
96         141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
97         161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
98         181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
99         201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220,
100         221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
101         241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
102 };
103
104 #endif
105
106 /** The irc namespace contains a number of helper classes.
107  */
108 namespace irc
109 {
110
111         /** This class returns true if two strings match.
112          * Case sensitivity is ignored, and the RFC 'character set'
113          * is adhered to
114          */
115         struct StrHashComp
116         {
117                 /** The operator () does the actual comparison in hash_map
118                  */
119                 bool operator()(const std::string& s1, const std::string& s2) const;
120         };
121
122         /** The irc_char_traits class is used for RFC-style comparison of strings.
123          * This class is used to implement irc::string, a case-insensitive, RFC-
124          * comparing string class.
125          */
126         struct irc_char_traits : std::char_traits<char> {
127
128                 /** Check if two chars match.
129                  * @param c1st First character
130                  * @param c2nd Second character
131                  * @return true if the characters are equal
132                  */
133                 static bool eq(char c1st, char c2nd);
134
135                 /** Check if two chars do NOT match.
136                  * @param c1st First character
137                  * @param c2nd Second character
138                  * @return true if the characters are unequal
139                  */
140                 static bool ne(char c1st, char c2nd);
141
142                 /** Check if one char is less than another.
143                  * @param c1st First character
144                  * @param c2nd Second character
145                  * @return true if c1st is less than c2nd
146                  */
147                 static bool lt(char c1st, char c2nd);
148
149                 /** Compare two strings of size n.
150                  * @param str1 First string
151                  * @param str2 Second string
152                  * @param n Length to compare to
153                  * @return similar to strcmp, zero for equal, less than zero for str1
154                  * being less and greater than zero for str1 being greater than str2.
155                  */
156                 static CoreExport int compare(const char* str1, const char* str2, size_t n);
157
158                 /** Find a char within a string up to position n.
159                  * @param s1 String to find in
160                  * @param n Position to search up to
161                  * @param c Character to search for
162                  * @return Pointer to the first occurance of c in s1
163                  */
164                 static CoreExport const char* find(const char* s1, int  n, char c);
165         };
166
167         /** Compose a hex string from raw data.
168          * @param raw The raw data to compose hex from
169          * @pram rawsz The size of the raw data buffer
170          * @return The hex string.
171          */
172         CoreExport std::string hex(const unsigned char *raw, size_t rawsz);
173
174         /** This typedef declares irc::string based upon irc_char_traits.
175          */
176         typedef std::basic_string<char, irc_char_traits, std::allocator<char> > string;
177
178         /** irc::stringjoiner joins string lists into a string, using
179          * the given seperator string.
180          * This class can join a vector of std::string, a deque of
181          * std::string, or a const char* const* array, using overloaded
182          * constructors.
183          */
184         class CoreExport stringjoiner : public classbase
185         {
186          private:
187
188                 /** Output string
189                  */
190                 std::string joined;
191
192          public:
193
194                 /** Join elements of a vector, between (and including) begin and end
195                  * @param seperator The string to seperate values with
196                  * @param sequence One or more items to seperate
197                  * @param begin The starting element in the sequence to be joined
198                  * @param end The ending element in the sequence to be joined
199                  */
200                 stringjoiner(const std::string &seperator, const std::vector<std::string> &sequence, int begin, int end);
201
202                 /** Join elements of a deque, between (and including) begin and end
203                  * @param seperator The string to seperate values with
204                  * @param sequence One or more items to seperate
205                  * @param begin The starting element in the sequence to be joined
206                  * @param end The ending element in the sequence to be joined
207                  */
208                 stringjoiner(const std::string &seperator, const std::deque<std::string> &sequence, int begin, int end);
209
210                 /** Join elements of an array of char arrays, between (and including) begin and end
211                  * @param seperator The string to seperate values with
212                  * @param sequence One or more items to seperate
213                  * @param begin The starting element in the sequence to be joined
214                  * @param end The ending element in the sequence to be joined
215                  */
216                 stringjoiner(const std::string &seperator, const char* const* sequence, int begin, int end);
217
218                 /** Get the joined sequence
219                  * @return A reference to the joined string
220                  */
221                 std::string& GetJoined();
222         };
223
224         /** irc::modestacker stacks mode sequences into a list.
225          * It can then reproduce this list, clamped to a maximum of MAXMODES
226          * values per line.
227          */
228         class CoreExport modestacker : public classbase
229         {
230          private:
231                 InspIRCd* ServerInstance;
232
233                 /** The mode sequence and its parameters
234                  */
235                 std::deque<std::string> sequence;
236
237                 /** True if the mode sequence is initially adding
238                  * characters, false if it is initially removing
239                  * them
240                  */
241                 bool adding;
242          public:
243
244                 /** Construct a new modestacker.
245                  * @param add True if the stack is adding modes,
246                  * false if it is removing them
247                  */
248                 modestacker(InspIRCd* Instance, bool add);
249
250                 /** Push a modeletter and its parameter onto the stack.
251                  * No checking is performed as to if this mode actually
252                  * requires a parameter. If you stack invalid mode
253                  * sequences, they will be tidied if and when they are
254                  * passed to a mode parser.
255                  * @param modeletter The mode letter to insert
256                  * @param parameter The parameter for the mode
257                  */
258                 void Push(char modeletter, const std::string &parameter);
259
260                 /** Push a modeletter without parameter onto the stack.
261                  * No checking is performed as to if this mode actually
262                  * requires a parameter. If you stack invalid mode
263                  * sequences, they will be tidied if and when they are
264                  * passed to a mode parser.
265                  * @param modeletter The mode letter to insert
266                  */
267                 void Push(char modeletter);
268         
269                 /** Push a '+' symbol onto the stack.
270                  */
271                 void PushPlus();
272         
273                 /** Push a '-' symbol onto the stack.
274                  */
275                 void PushMinus();
276                 
277                 /** Return zero or more elements which form the
278                  * mode line. This will be clamped to a max of
279                  * MAXMODES items (MAXMODES-1 mode parameters and
280                  * one mode sequence string), and max_line_size
281                  * characters. As specified below, this function
282                  * should be called in a loop until it returns zero,
283                  * indicating there are no more modes to return.
284                  * @param result The deque to populate. This will
285                  * be cleared before it is used.
286                  * @param max_line_size The maximum size of the line
287                  * to build, in characters, seperate to MAXMODES.
288                  * @return The number of elements in the deque.
289                  * The function should be called repeatedly until it
290                  * returns 0, in case there are multiple lines of
291                  * mode changes to be obtained.
292                  */
293                 int GetStackedLine(std::deque<std::string> &result, int max_line_size = 360);
294         };
295
296         /** irc::tokenstream reads a string formatted as per RFC1459 and RFC2812.
297          * It will split the string into 'tokens' each containing one parameter
298          * from the string.
299          * For instance, if it is instantiated with the string:
300          * "PRIVMSG #test :foo bar baz qux"
301          * then each successive call to tokenstream::GetToken() will return
302          * "PRIVMSG", "#test", "foo bar baz qux", "".
303          * Note that if the whole string starts with a colon this is not taken
304          * to mean the string is all one parameter, and the first item in the
305          * list will be ":item". This is to allow for parsing 'source' fields
306          * from data.
307          */
308         class CoreExport tokenstream : public classbase
309         {
310          private:
311         
312                 /** Original string
313                  */
314                 std::string tokens;
315
316                 /** Last position of a seperator token
317                  */
318                 std::string::iterator last_starting_position;
319
320                 /** Current string position
321                  */
322                 std::string::iterator n;
323
324                 /** True if the last value was an ending value
325                  */
326                 bool last_pushed;
327          public:
328
329                 /** Create a tokenstream and fill it with the provided data
330                  */
331                 tokenstream(const std::string &source);
332
333                 /** Destructor
334                  */
335                 ~tokenstream();
336
337                 /** Fetch the next token from the stream as a std::string
338                  * @param token The next token available, or an empty string if none remain
339                  * @return True if tokens are left to be read, false if the last token was just retrieved.
340                  */
341                 bool GetToken(std::string &token);
342
343                 /** Fetch the next token from the stream as an irc::string
344                  * @param token The next token available, or an empty string if none remain
345                  * @return True if tokens are left to be read, false if the last token was just retrieved.
346                  */
347                 bool GetToken(irc::string &token);
348
349                 /** Fetch the next token from the stream as an integer
350                  * @param token The next token available, or undefined if none remain
351                  * @return True if tokens are left to be read, false if the last token was just retrieved.
352                  */
353                 bool GetToken(int &token);
354
355                 /** Fetch the next token from the stream as a long integer
356                  * @param token The next token available, or undefined if none remain
357                  * @return True if tokens are left to be read, false if the last token was just retrieved.
358                  */
359                 bool GetToken(long &token);
360         };
361
362         /** irc::sepstream allows for splitting token seperated lists.
363          * Each successive call to sepstream::GetToken() returns
364          * the next token, until none remain, at which point the method returns
365          * an empty string.
366          */
367         class CoreExport sepstream : public classbase
368         {
369          private:
370                 /** Original string.
371                  */
372                 std::string tokens;
373                 /** Last position of a seperator token
374                  */
375                 std::string::iterator last_starting_position;
376                 /** Current string position
377                  */
378                 std::string::iterator n;
379                 /** Seperator value
380                  */
381                 char sep;
382          public:
383                 /** Create a sepstream and fill it with the provided data
384                  */
385                 sepstream(const std::string &source, char seperator);
386
387                 /** Destructor
388                  */
389                 virtual ~sepstream();
390
391                 /** Fetch the next token from the stream
392                  * @param token The next token from the stream is placed here
393                  * @return True if tokens still remain, false if there are none left
394                  */
395                 virtual bool GetToken(std::string &token);
396
397                 /** Fetch the entire remaining stream, without tokenizing
398                  * @return The remaining part of the stream
399                  */
400                 virtual const std::string GetRemaining();
401
402                 /** Returns true if the end of the stream has been reached
403                  * @return True if the end of the stream has been reached, otherwise false
404                  */
405                 virtual bool StreamEnd();
406         };
407
408         /** A derived form of sepstream, which seperates on commas
409          */
410         class CoreExport commasepstream : public sepstream
411         {
412          public:
413                 /** Initialize with comma seperator
414                  */
415                 commasepstream(const std::string &source) : sepstream(source, ',')
416                 {
417                 }
418         };
419
420         /** A derived form of sepstream, which seperates on spaces
421          */
422         class CoreExport spacesepstream : public sepstream
423         {
424          public:
425                 /** Initialize with space seperator
426                  */
427                 spacesepstream(const std::string &source) : sepstream(source, ' ')
428                 {
429                 }
430         };
431
432         /** The portparser class seperates out a port range into integers.
433          * A port range may be specified in the input string in the form
434          * "6660,6661,6662-6669,7020". The end of the stream is indicated by
435          * a return value of 0 from portparser::GetToken(). If you attempt
436          * to specify an illegal range (e.g. one where start >= end, or
437          * start or end < 0) then GetToken() will return the first element
438          * of the pair of numbers.
439          */
440         class CoreExport portparser : public classbase
441         {
442          private:
443
444                 /** Used to split on commas
445                  */
446                 commasepstream* sep;
447         
448                 /** Current position in a range of ports
449                  */
450                 long in_range;
451         
452                 /** Starting port in a range of ports
453                  */
454                 long range_begin;
455         
456                 /** Ending port in a range of ports
457                  */
458                 long range_end;
459         
460                 /** Allow overlapped port ranges
461                  */
462                 bool overlapped;
463         
464                 /** Used to determine overlapping of ports
465                  * without O(n) algorithm being used
466                  */
467                 std::map<long, bool> overlap_set;
468         
469                 /** Returns true if val overlaps an existing range
470                  */
471                 bool Overlaps(long val);
472          public:
473         
474                 /** Create a portparser and fill it with the provided data
475                  * @param source The source text to parse from
476                  * @param allow_overlapped Allow overlapped ranges
477                  */
478                 portparser(const std::string &source, bool allow_overlapped = true);
479         
480                 /** Frees the internal commasepstream object
481                  */
482                 ~portparser();
483         
484                 /** Fetch the next token from the stream
485                  * @return The next port number is returned, or 0 if none remain
486                  */
487                 long GetToken();
488         };
489
490         /** Turn _ characters in a string into spaces
491          * @param n String to translate
492          * @return The new value with _ translated to space.
493          */
494         CoreExport const char* Spacify(const char* n);
495 }
496
497 /* Define operators for using >> and << with irc::string to an ostream on an istream. */
498 /* This was endless fun. No. Really. */
499 /* It was also the first core change Ommeh made, if anyone cares */
500
501 /** Operator << for irc::string
502  */
503 inline std::ostream& operator<<(std::ostream &os, const irc::string &str) { return os << str.c_str(); }
504
505 /** Operator >> for irc::string
506  */
507 inline std::istream& operator>>(std::istream &is, irc::string &str)
508 {
509         std::string tmp;
510         is >> tmp;
511         str = tmp.c_str();
512         return is;
513 }
514
515 /* Define operators for + and == with irc::string to std::string for easy assignment
516  * and comparison
517  *
518  * Operator +
519  */
520 inline std::string operator+ (std::string& leftval, irc::string& rightval)
521 {
522         return leftval + std::string(rightval.c_str());
523 }
524
525 /* Define operators for + and == with irc::string to std::string for easy assignment
526  * and comparison
527  *
528  * Operator +
529  */
530 inline irc::string operator+ (irc::string& leftval, std::string& rightval)
531 {
532         return leftval + irc::string(rightval.c_str());
533 }
534
535 /* Define operators for + and == with irc::string to std::string for easy assignment
536  * and comparison
537  *
538  * Operator ==
539  */
540 inline bool operator== (const std::string& leftval, const irc::string& rightval)
541 {
542         return (leftval.c_str() == rightval);
543 }
544
545 /* Define operators for + and == with irc::string to std::string for easy assignment
546  * and comparison
547  *
548  * Operator ==
549  */
550 inline bool operator== (const irc::string& leftval, const std::string& rightval)
551 {
552         return (leftval == rightval.c_str());
553 }
554
555 /* Define operators != for irc::string to std::string for easy comparison
556  */
557 inline bool operator!= (const irc::string& leftval, const std::string& rightval)
558 {
559         return !(leftval == rightval.c_str());
560 }
561
562 /* Define operators != for std::string to irc::string for easy comparison
563  */
564 inline bool operator!= (const std::string& leftval, const irc::string& rightval)
565 {
566         return !(leftval.c_str() == rightval);
567 }
568
569 // FIXME MAXBUF messes up these
570 #if 0
571 template<std::size_t N>
572 static inline bool operator == (std::string const &lhs, char const (&rhs)[N])
573 {
574         return lhs.length() == N - 1 && !std::memcmp(lhs.data(), rhs, N - 1);
575 }
576
577 template<std::size_t N>
578 static inline bool operator != (std::string const &lhs, char const (&rhs)[N])
579 {
580         return !(lhs == rhs);
581 }
582 #endif
583
584 /** Assign an irc::string to a std::string.
585  */
586 inline std::string assign(const irc::string &other) { return other.c_str(); }
587
588 /** Assign a std::string to an irc::string.
589  */
590 inline irc::string assign(const std::string &other) { return other.c_str(); }
591
592 /** Trim the leading and trailing spaces from a std::string.
593  */
594 inline std::string& trim(std::string &str)
595 {
596         std::string::size_type start = str.find_first_not_of(" ");
597         std::string::size_type end = str.find_last_not_of(" ");
598         if (start == std::string::npos || end == std::string::npos)
599                 str = "";
600         else
601                 str = str.substr(start, end-start+1);
602
603         return str;
604 }
605
606 /** Hashing stuff is totally different on vc++'s hash_map implementation, so to save a buttload of
607  * #ifdefs we'll just do it all at once
608  */
609 BEGIN_HASHMAP_NAMESPACE
610
611         /** Hashing function to hash irc::string
612          */
613 #ifdef WINDOWS
614         template<> class CoreExport hash_compare<irc::string, std::less<irc::string> >
615         {
616         public:
617                 enum { bucket_size = 4, min_buckets = 8 }; /* Got these numbers from the CRT source, if anyone wants to change them feel free. */
618
619                 /** Compare two irc::string values for hashing in hash_map
620                  */
621                 bool operator()(const irc::string & s1, const irc::string & s2) const
622                 {
623                         if(s1.length() != s2.length()) return true;
624                         return (irc::irc_char_traits::compare(s1.c_str(), s2.c_str(), (size_t)s1.length()) < 0);
625                 }
626
627                 /** Hash an irc::string value for hash_map
628                  */
629                 size_t operator()(const irc::string & s) const;
630         };
631
632         template<> class CoreExport hash_compare<std::string, std::less<std::string> >
633         {
634         public:
635                 enum { bucket_size = 4, min_buckets = 8 }; /* Again, from the CRT source */
636
637                 /** Compare two std::string values for hashing in hash_map
638                  */
639                 bool operator()(const std::string & s1, const std::string & s2) const
640                 {
641                         if(s1.length() != s2.length()) return true;
642                         return (irc::irc_char_traits::compare(s1.c_str(), s2.c_str(), (size_t)s1.length()) < 0);
643                 }
644
645                 /** Hash a std::string using RFC1459 case sensitivity rules
646                 * @param s A string to hash
647                 * @return The hash value
648                 */
649                 size_t operator()(const std::string & s) const;
650         };
651 #else
652
653         template<> struct hash<irc::string>
654         {
655                 /** Hash an irc::string using RFC1459 case sensitivity rules
656                  * @param s A string to hash
657                  * @return The hash value
658                  */
659                 size_t operator()(const irc::string &s) const;
660         };
661
662         /* XXX FIXME: Implement a hash function overriding std::string's that works with TR1! */
663
664 #ifdef HASHMAP_DEPRECATED
665         struct insensitive
666 #else
667         template<> struct hash<std::string>
668 #endif
669         {
670                 size_t operator()(const std::string &s) const;
671         };
672
673 #endif
674
675         /** Convert a string to lower case respecting RFC1459
676         * @param n A string to lowercase
677         */
678         void strlower(char *n);
679
680 END_HASHMAP_NAMESPACE
681
682 #endif
683