1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18// Date: Sun Dec 4 14:57:27 CST 2016
19
20#ifndef BUTIL_CASE_IGNORED_FLAT_MAP_H
21#define BUTIL_CASE_IGNORED_FLAT_MAP_H
22
23#include "butil/containers/flat_map.h"
24
25namespace butil {
26
27// NOTE: Using ascii_tolower instead of ::tolower shortens 150ns in
28// FlatMapTest.perf_small_string_map (with -O2 added, -O0 by default)
29inline char ascii_tolower(char c) {
30 extern const char* const g_tolower_map;
31 return g_tolower_map[(int)c];
32}
33
34struct CaseIgnoredHasher {
35 size_t operator()(const std::string& s) const {
36 std::size_t result = 0;
37 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
38 result = result * 101 + ascii_tolower(*i);
39 }
40 return result;
41 }
42 size_t operator()(const char* s) const {
43 std::size_t result = 0;
44 for (; *s; ++s) {
45 result = result * 101 + ascii_tolower(*s);
46 }
47 return result;
48 }
49};
50
51struct CaseIgnoredEqual {
52 // NOTE: No overload for butil::StringPiece. It needs strncasecmp
53 // which is much slower than strcasecmp in micro-benchmarking. As a
54 // result, methods in HttpHeader does not accept StringPiece as well.
55 bool operator()(const std::string& s1, const std::string& s2) const {
56 return s1.size() == s2.size() &&
57 strcasecmp(s1.c_str(), s2.c_str()) == 0;
58 }
59 bool operator()(const std::string& s1, const char* s2) const
60 { return strcasecmp(s1.c_str(), s2) == 0; }
61};
62
63template <typename T>
64class CaseIgnoredFlatMap : public butil::FlatMap<
65 std::string, T, CaseIgnoredHasher, CaseIgnoredEqual> {};
66
67class CaseIgnoredFlatSet : public butil::FlatSet<
68 std::string, CaseIgnoredHasher, CaseIgnoredEqual> {};
69
70} // namespace butil
71
72#endif // BUTIL_CASE_IGNORED_FLAT_MAP_H
73