1 /**
2  * This file is part of DCD, a development tool for the D programming language.
3  * Copyright (C) 2014 Brian Schott
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 module dsymbol.string_interning;
20 
21 import std.traits : Unqual;
22 import dparse.lexer;
23 
24 /// Obsolete, use `istring` constructor instead
25 istring internString(string s) nothrow @nogc @safe
26 {
27 	return istring(s);
28 }
29 
30 static this()
31 {
32 	stringCache = StringCache(StringCache.defaultBucketCount);
33 }
34 
35 static ~this()
36 {
37 	destroy(stringCache);
38 }
39 
40 private StringCache stringCache = void;
41 
42 struct istring
43 {
44 nothrow @nogc @safe:
45 	/// Interns the given string and returns the interned version. Handles empty strings too.
46 	this(string s)
47 	{
48 		if (s.length > 0)
49 			_data = stringCache.intern(s);
50 	}
51 
52 pure:
53 	void opAssign(T)(T other) if (is(Unqual!T == istring))
54 	{
55 		_data = other._data;
56 	}
57 
58 	bool opCast(To : bool)() const
59 	{
60 		return _data.length > 0;
61 	}
62 
63 	ptrdiff_t opCmpFast(const istring another) const @trusted
64 	{
65 		// Interned strings can be compared by the pointers.
66 		// Identical strings MUST have the same address
67 		return (cast(ptrdiff_t) _data.ptr) - (cast(ptrdiff_t) another._data.ptr);
68 	}
69 	ptrdiff_t opCmp(const string another) const
70 	{
71 		import std.algorithm.comparison : cmp;
72 		// Compare as usual, because another string may come from somewhere else
73 		return cmp(_data, another);
74 	}
75 
76 	bool opEquals(const istring another) const @trusted
77 	{
78 		return _data.ptr is another._data.ptr;
79 	}
80 	bool opEquals(const string another) const
81 	{
82 		return _data == another;
83 	}
84 
85 	size_t toHash() const @trusted
86 	{
87 		return (cast(size_t) _data.ptr) * 27_644_437;
88 	}
89 
90 	string data() const
91 	{
92 		return _data;
93 	}
94 
95 	alias data this;
96 	private string _data;
97 }