-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
BlackboardPropertyName.cs
177 lines (157 loc) · 4.64 KB
/
BlackboardPropertyName.cs
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Copyright (c) 2020-2023 Vladimir Popov zor1994@gmail.com https://github.com/ZorPastaman/Simple-Blackboard
using System;
using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace Zor.SimpleBlackboard.Core
{
/// <summary>
/// Wrapper over <see cref="string"/> transforming it into <see cref="int"/> for faster comparisons.
/// </summary>
/// <remarks>
/// It's used in <see cref="Zor.SimpleBlackboard.Core.Blackboard"/>.
/// </remarks>
public readonly struct BlackboardPropertyName : IEquatable<BlackboardPropertyName>
{
/// <summary>
/// 0 on little endian machines, 1 on big endian machines.
/// Used in <see cref="ComputeHash"/>.
/// </summary>
private static readonly int s_hashByteOffset;
#if SIMPLE_BLACKBOARD_SAVE_NAMES
/// <summary>
/// Pairs of ids and strings that were used in <see cref="BlackboardPropertyName(string)"/>.
/// </summary>
[NotNull] private static readonly System.Collections.Generic.Dictionary<int, string> s_names = new(1000);
#endif
/// <summary>
/// Unique per string id.
/// </summary>
public readonly int id;
/// <summary>
/// Initializes <see cref="s_hashByteOffset"/>.
/// </summary>
static unsafe BlackboardPropertyName()
{
bool isBigEndian = !BitConverter.IsLittleEndian;
s_hashByteOffset = *(byte*)&isBigEndian;
}
/// <summary>
/// Creates a <see cref="BlackboardPropertyName"/> with unique <see cref="id"/> per <paramref name="name"/>.
/// </summary>
/// <param name="name">
/// For this, unique <see cref="id"/> is set.
/// Every symbol must be from ascii table.
/// </param>
public BlackboardPropertyName([NotNull] string name)
{
id = ComputeHash(name);
#if SIMPLE_BLACKBOARD_SAVE_NAMES
#if SIMPLE_BLACKBOARD_MULTITHREADING
lock (s_names)
#endif
{
s_names[id] = name;
}
#endif
}
/// <summary>
/// Creates a <see cref="BlackboardPropertyName"/> with the specified <paramref name="id"/>.
/// </summary>
/// <param name="id">Id to set.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BlackboardPropertyName(int id)
{
this.id = id;
}
/// <summary>
/// Name of the property. This method requires SIMPLE_BLACKBOARD_SAVE_NAMES define enabled.
/// </summary>
/// <returns>
/// <para>
/// Original string name of the property if the <see cref="BlackboardPropertyName"/> was created
/// with <see cref="BlackboardPropertyName(string)"/>.
/// </para>
/// <para>
/// If the <see cref="BlackboardPropertyName"/> was created with <see cref="BlackboardPropertyName(int)"/>,
/// this may return <see cref="string.Empty"/> or a name if another <see cref="BlackboardPropertyName"/>
/// was created with <see cref="BlackboardPropertyName(string)"/> and got the same <see cref="id"/>.
/// </para>
/// <para>
/// Empty string if SIMPLE_BLACKBOARD_SAVE_NAMES define is not enabled.
/// </para>
/// </returns>
[NotNull]
public string name
{
[Pure]
get
{
#if SIMPLE_BLACKBOARD_SAVE_NAMES
string propertyName;
bool found;
#if SIMPLE_BLACKBOARD_MULTITHREADING
lock (s_names)
#endif
{
found = s_names.TryGetValue(id, out propertyName);
}
return found ? propertyName : string.Empty;
#else
return string.Empty;
#endif
}
}
[Pure]
public override bool Equals(object obj)
{
return obj is BlackboardPropertyName other && other.id == id;
}
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
public bool Equals(BlackboardPropertyName other)
{
return other.id == id;
}
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
public override int GetHashCode()
{
return id;
}
[Pure]
public override string ToString()
{
#if SIMPLE_BLACKBOARD_SAVE_NAMES
return $"{id.ToString()}({name})";
#else
return id.ToString();
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
public static bool operator ==(BlackboardPropertyName lhs, BlackboardPropertyName rhs)
{
return lhs.id == rhs.id;
}
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
public static bool operator !=(BlackboardPropertyName lhs, BlackboardPropertyName rhs)
{
return lhs.id != rhs.id;
}
/// <summary>
/// Computes hash for <see cref="str"/>. It uses FNV-1a hash algorithm.
/// </summary>
/// <param name="str">String to be hashed.</param>
/// <returns>Computed hash.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
private static unsafe int ComputeHash([NotNull] string str)
{
fixed (char* c = str)
{
uint hash = 2166136261;
for (byte* b = (byte*)c + s_hashByteOffset; *b != 0; b += 2)
{
hash = (hash ^ *b) * 16777619;
}
return unchecked((int)hash);
}
}
}
}