aboutsummaryrefslogtreecommitdiff
path: root/include/casemap.h
blob: 74c2b01c5d212897300e5eb067933759fc1feaae (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
 * InspIRCd -- Internet Relay Chat Daemon
 *
 *   Copyright (C) 2026 Sadie Powell <sadie@witchery.services>
 *
 * This file is part of InspIRCd.  InspIRCd is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, version 2.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#pragma once

namespace insp
{
	template<typename, typename>
	struct casemapped_equals_obj;
	template<typename>
	struct casemapped_hash_obj;
	template<typename, typename>
	struct casemapped_less_obj;

	/** Holds a list of characters and the value they map to. */
	using casemap = unsigned char;

	/** A flat map where the key is a case insensitive string using the IRC casemapping. */
	template<typename Value, typename Key = std::string>
	using casemapped_flat_map = insp::flat_map<std::string, Value, casemapped_less_obj<Key, Key>>;

	/** A flat multimap where the key is a case insensitive string using the IRC casemapping. */
	template<typename Value, typename Key = std::string>
	using casemapped_flat_multimap = insp::flat_multimap<std::string, Value, casemapped_less_obj<Key, Key>>;

	/** A flat set where the key is a case insensitive string using the IRC casemapping. */
	template<typename Key = std::string>
	using casemapped_flat_set = insp::flat_set<Key, casemapped_less_obj<Key, Key>>;

	/** A map where the key is a case insensitive string using the IRC casemapping. */
	template<typename Value, typename Key = std::string>
	using casemapped_map = std::map<Key, Value, casemapped_less_obj<Key, Key>>;

	/** A flat multimap where the key is a case insensitive string using the IRC casemapping. */
	template<typename Value, typename Key = std::string>
	using casemapped_multimap = std::multimap<Key, Value, casemapped_less_obj<Key, Key>>;

	/** An unordered map where the key is a case insensitive string using the IRC casemapping. */
	template<typename Value, typename Key = std::string>
	using casemapped_unordered_map = std::unordered_map<Key, Value, casemapped_hash_obj<Key>, casemapped_equals_obj<Key, Key>>;

	/** Determines if \p str1 and \p str2 are equivalent when compared case insensitively using the
	 * specified IRC casemapping.
	 * @param str1 The first string to compare.
	 * @param str2 The second string to compare.
	 * @return True if \p str1 and \p str2 are equivalent; otherwise, false.
	 */
	CoreExport bool casemapped_equals(const std::string_view& str1, const std::string_view& str2, const casemap* map = nullptr);

	/** Determines if \p str1 is lexographically less than \p str2 when compared insensitively using
	 * the specified IRC casemapping.
	 * @param str1 The first string to compare.
	 * @param str2 The second string to compare.
	 * @return True if \p str1 is ranked lower than \p str2; otherwise, false.
	 */
	CoreExport bool casemapped_less(const std::string_view& str1, const std::string_view& str2, const casemap* map = nullptr);

	/** Determines the unique hash of \p str for use in a hash map when hashed insensitively using
	 * the configured IRC casemapping.
	 * @param str The string to hash.
	 * @return The unique hash of \p str.
	 */
	CoreExport size_t casemapped_hash(const std::string_view& str);
}

/** A casemapping that uses ASCII rules, i.e. A-Z are mapped to a-z. */
extern CoreExport const insp::casemap ascii_case_insensitive_map[256];

/** The currently configured casemapping. This defaults to \ref ascii_case_insensitive_map. */
extern CoreExport const insp::casemap* national_case_insensitive_map;

namespace insp
{
	/** Determines if \p str1 and \p str2 are equivalent when compared case insensitively using
	 * ASCII casemapping.
	 * @param str1 The first string to compare.
	 * @param str2 The second string to compare.
	 * @return True if \p str1 and \p str2 are equivalent; otherwise, false.
	 */
	inline bool ascii_equals(const std::string_view& str1, const std::string_view& str2)
	{
		return casemapped_equals(str1, str2, ascii_case_insensitive_map);
	}

	/** Determines if \p str1 is lexographically less than \p str2 when compared insensitively using
	 * ASCII casemapping.
	 * @param str1 The first string to compare.
	 * @param str2 The second string to compare.
	 * @return True if \p str1 is ranked lower than \p str2; otherwise, false.
	 */
	inline bool ascii_less(const std::string_view& str1, const std::string_view& str2)
	{
		return casemapped_less(str1, str2, ascii_case_insensitive_map);
	}
}

/** IRC casemapping variant of \p std::equal_to<String>. */
template<typename String1, typename String2>
struct insp::casemapped_equals_obj
{
	/** @copydoc insp::casemapped_equals */
	inline bool operator()(const String1& str1, const String2& str2) const
	{
		return insp::casemapped_equals(str1, str2);
	}
};

/** IRC casemapping variant of std::hash<String>. */
template<typename String>
struct insp::casemapped_hash_obj
{
	/** @copydoc insp::casemapped_hash */
	inline size_t operator()(const String& str) const
	{
		return insp::casemapped_hash(str);
	}
};

/** IRC casemapping variant of std::less<String>. */
template<typename String1, typename String2>
struct insp::casemapped_less_obj
{
	/** @copydoc insp::casemapped_less */
	inline bool operator()(const String1& str1, const String2& str2) const
	{
		return insp::casemapped_less(str1, str2);
	}
};