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