├── .gitattributes
├── .gitignore
├── FastHashSet
├── FastHashSet.cs
├── FastHashSet.csproj
└── Properties
│ └── AssemblyInfo.cs
├── FastHashSetTestsExtra
├── ExtraTests.cs
├── FastHashSetTestsExtra.csproj
├── FastHashSetTestsExtra.sln
└── Properties
│ └── AssemblyInfo.cs
├── HashSetBench.sln
├── HashSetBench
├── App.config
├── Bench.cs
├── BenchUtil.cs
├── ClassAndStruct.cs
├── HashSetBench.csproj
├── HashSetBench8.xlsx
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
├── app.manifest
└── packages.config
├── HashSetPerf
├── HashSetClassFast
│ ├── App.config
│ ├── HashSetClassFast.csproj
│ ├── Program.cs
│ └── Properties
│ │ └── AssemblyInfo.cs
├── HashSetContains
│ ├── App.config
│ ├── HashSetContains.csproj
│ ├── Program.cs
│ └── Properties
│ │ └── AssemblyInfo.cs
├── HashSetContainsC5
│ ├── App.config
│ ├── HashSetContainsC5.csproj
│ ├── Program.cs
│ └── Properties
│ │ └── AssemblyInfo.cs
├── HashSetContainsFast
│ ├── App.config
│ ├── HashSetContainsFast.csproj
│ ├── Program.cs
│ └── Properties
│ │ └── AssemblyInfo.cs
├── HashSetPerf.sln
├── HashSetPerf
│ ├── App.config
│ ├── BenchUtil.cs
│ ├── HashSetPerf.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── packages.config
└── HashSetStructFast
│ ├── App.config
│ ├── HashSetStructFast.csproj
│ ├── Program.cs
│ └── Properties
│ └── AssemblyInfo.cs
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | [Aa][Rr][Mm]/
24 | [Aa][Rr][Mm]64/
25 | bld/
26 | [Bb]in/
27 | [Oo]bj/
28 | [Ll]og/
29 |
30 | # Visual Studio 2015/2017 cache/options directory
31 | .vs/
32 | # Uncomment if you have tasks that create the project's static files in wwwroot
33 | #wwwroot/
34 |
35 | # Visual Studio 2017 auto generated files
36 | Generated\ Files/
37 |
38 | # MSTest test Results
39 | [Tt]est[Rr]esult*/
40 | [Bb]uild[Ll]og.*
41 |
42 | # NUNIT
43 | *.VisualState.xml
44 | TestResult.xml
45 |
46 | # Build Results of an ATL Project
47 | [Dd]ebugPS/
48 | [Rr]eleasePS/
49 | dlldata.c
50 |
51 | # Benchmark Results
52 | BenchmarkDotNet.Artifacts/
53 |
54 | # .NET Core
55 | project.lock.json
56 | project.fragment.lock.json
57 | artifacts/
58 |
59 | # StyleCop
60 | StyleCopReport.xml
61 |
62 | # Files built by Visual Studio
63 | *_i.c
64 | *_p.c
65 | *_h.h
66 | *.ilk
67 | *.meta
68 | *.obj
69 | *.iobj
70 | *.pch
71 | *.pdb
72 | *.ipdb
73 | *.pgc
74 | *.pgd
75 | *.rsp
76 | *.sbr
77 | *.tlb
78 | *.tli
79 | *.tlh
80 | *.tmp
81 | *.tmp_proj
82 | *_wpftmp.csproj
83 | *.log
84 | *.vspscc
85 | *.vssscc
86 | .builds
87 | *.pidb
88 | *.svclog
89 | *.scc
90 |
91 | # Chutzpah Test files
92 | _Chutzpah*
93 |
94 | # Visual C++ cache files
95 | ipch/
96 | *.aps
97 | *.ncb
98 | *.opendb
99 | *.opensdf
100 | *.sdf
101 | *.cachefile
102 | *.VC.db
103 | *.VC.VC.opendb
104 |
105 | # Visual Studio profiler
106 | *.psess
107 | *.vsp
108 | *.vspx
109 | *.sap
110 |
111 | # Visual Studio Trace Files
112 | *.e2e
113 |
114 | # TFS 2012 Local Workspace
115 | $tf/
116 |
117 | # Guidance Automation Toolkit
118 | *.gpState
119 |
120 | # ReSharper is a .NET coding add-in
121 | _ReSharper*/
122 | *.[Rr]e[Ss]harper
123 | *.DotSettings.user
124 |
125 | # JustCode is a .NET coding add-in
126 | .JustCode
127 |
128 | # TeamCity is a build add-in
129 | _TeamCity*
130 |
131 | # DotCover is a Code Coverage Tool
132 | *.dotCover
133 |
134 | # AxoCover is a Code Coverage Tool
135 | .axoCover/*
136 | !.axoCover/settings.json
137 |
138 | # Visual Studio code coverage results
139 | *.coverage
140 | *.coveragexml
141 |
142 | # NCrunch
143 | _NCrunch_*
144 | .*crunch*.local.xml
145 | nCrunchTemp_*
146 |
147 | # MightyMoose
148 | *.mm.*
149 | AutoTest.Net/
150 |
151 | # Web workbench (sass)
152 | .sass-cache/
153 |
154 | # Installshield output folder
155 | [Ee]xpress/
156 |
157 | # DocProject is a documentation generator add-in
158 | DocProject/buildhelp/
159 | DocProject/Help/*.HxT
160 | DocProject/Help/*.HxC
161 | DocProject/Help/*.hhc
162 | DocProject/Help/*.hhk
163 | DocProject/Help/*.hhp
164 | DocProject/Help/Html2
165 | DocProject/Help/html
166 |
167 | # Click-Once directory
168 | publish/
169 |
170 | # Publish Web Output
171 | *.[Pp]ublish.xml
172 | *.azurePubxml
173 | # Note: Comment the next line if you want to checkin your web deploy settings,
174 | # but database connection strings (with potential passwords) will be unencrypted
175 | *.pubxml
176 | *.publishproj
177 |
178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
179 | # checkin your Azure Web App publish settings, but sensitive information contained
180 | # in these scripts will be unencrypted
181 | PublishScripts/
182 |
183 | # NuGet Packages
184 | *.nupkg
185 | # The packages folder can be ignored because of Package Restore
186 | **/[Pp]ackages/*
187 | # except build/, which is used as an MSBuild target.
188 | !**/[Pp]ackages/build/
189 | # Uncomment if necessary however generally it will be regenerated when needed
190 | #!**/[Pp]ackages/repositories.config
191 | # NuGet v3's project.json files produces more ignorable files
192 | *.nuget.props
193 | *.nuget.targets
194 |
195 | # Microsoft Azure Build Output
196 | csx/
197 | *.build.csdef
198 |
199 | # Microsoft Azure Emulator
200 | ecf/
201 | rcf/
202 |
203 | # Windows Store app package directories and files
204 | AppPackages/
205 | BundleArtifacts/
206 | Package.StoreAssociation.xml
207 | _pkginfo.txt
208 | *.appx
209 |
210 | # Visual Studio cache files
211 | # files ending in .cache can be ignored
212 | *.[Cc]ache
213 | # but keep track of directories ending in .cache
214 | !?*.[Cc]ache/
215 |
216 | # Others
217 | ClientBin/
218 | ~$*
219 | *~
220 | *.dbmdl
221 | *.dbproj.schemaview
222 | *.jfm
223 | *.pfx
224 | *.publishsettings
225 | orleans.codegen.cs
226 |
227 | # Including strong name files can present a security risk
228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
229 | #*.snk
230 |
231 | # Since there are multiple workflows, uncomment next line to ignore bower_components
232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
233 | #bower_components/
234 | # ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
235 | **/wwwroot/lib/
236 |
237 | # RIA/Silverlight projects
238 | Generated_Code/
239 |
240 | # Backup & report files from converting an old project file
241 | # to a newer Visual Studio version. Backup files are not needed,
242 | # because we have git ;-)
243 | _UpgradeReport_Files/
244 | Backup*/
245 | UpgradeLog*.XML
246 | UpgradeLog*.htm
247 | ServiceFabricBackup/
248 | *.rptproj.bak
249 |
250 | # SQL Server files
251 | *.mdf
252 | *.ldf
253 | *.ndf
254 |
255 | # Business Intelligence projects
256 | *.rdl.data
257 | *.bim.layout
258 | *.bim_*.settings
259 | *.rptproj.rsuser
260 | *- Backup*.rdl
261 |
262 | # Microsoft Fakes
263 | FakesAssemblies/
264 |
265 | # GhostDoc plugin setting file
266 | *.GhostDoc.xml
267 |
268 | # Node.js Tools for Visual Studio
269 | .ntvs_analysis.dat
270 | node_modules/
271 |
272 | # Visual Studio 6 build log
273 | *.plg
274 |
275 | # Visual Studio 6 workspace options file
276 | *.opt
277 |
278 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
279 | *.vbw
280 |
281 | # Visual Studio LightSwitch build output
282 | **/*.HTMLClient/GeneratedArtifacts
283 | **/*.DesktopClient/GeneratedArtifacts
284 | **/*.DesktopClient/ModelManifest.xml
285 | **/*.Server/GeneratedArtifacts
286 | **/*.Server/ModelManifest.xml
287 | _Pvt_Extensions
288 |
289 | # Paket dependency manager
290 | .paket/paket.exe
291 | paket-files/
292 |
293 | # FAKE - F# Make
294 | .fake/
295 |
296 | # JetBrains Rider
297 | .idea/
298 | *.sln.iml
299 |
300 | # CodeRush personal settings
301 | .cr/personal
302 |
303 | # Python Tools for Visual Studio (PTVS)
304 | __pycache__/
305 | *.pyc
306 |
307 | # Cake - Uncomment if you are using it
308 | # tools/**
309 | # !tools/packages.config
310 |
311 | # Tabs Studio
312 | *.tss
313 |
314 | # Telerik's JustMock configuration file
315 | *.jmconfig
316 |
317 | # BizTalk build output
318 | *.btp.cs
319 | *.btm.cs
320 | *.odx.cs
321 | *.xsd.cs
322 |
323 | # OpenCover UI analysis results
324 | OpenCover/
325 |
326 | # Azure Stream Analytics local run output
327 | ASALocalRun/
328 |
329 | # MSBuild Binary and Structured Log
330 | *.binlog
331 |
332 | # NVidia Nsight GPU debugger configuration file
333 | *.nvuser
334 |
335 | # MFractors (Xamarin productivity tool) working folder
336 | .mfractor/
337 |
338 | # Local History for Visual Studio
339 | .localhistory/
340 |
341 | # BeatPulse healthcheck temp database
342 | healthchecksdb
--------------------------------------------------------------------------------
/FastHashSet/FastHashSet.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}
8 | Library
9 | Properties
10 | FastHashSet
11 | FastHashSet
12 | v4.7.2
13 | 512
14 | true
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | TRACE;DEBUG
22 | prompt
23 | 4
24 | 7.3
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 | 7.3
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/FastHashSet/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FastHashSet")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("FastHashSet")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("a99bfa31-0806-4e83-82cc-c50a0a5d1b55")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 | [assembly: InternalsVisibleTo("FastHashSet.Tests")]
38 | [assembly: InternalsVisibleTo("FastHashSet.Explorables")]
39 |
40 |
--------------------------------------------------------------------------------
/FastHashSetTestsExtra/ExtraTests.cs:
--------------------------------------------------------------------------------
1 | //#define RunLongTests
2 | //#define RunVeryLongTests
3 |
4 | using Xunit;
5 | using Motvin.Collections;
6 | using System.Text;
7 | using System.Collections.Generic;
8 | using System;
9 |
10 | namespace FastHashSetTestsExtra
11 | {
12 | public class ExtraTests
13 | {
14 |
15 | public static bool IsPrime(int number)
16 | {
17 | if (number <= 2) return false;
18 | if (number % 2 == 0) return (number == 2);
19 | int root = (int)System.Math.Sqrt((double)number);
20 | for (int i = 3; i <= root; i += 2)
21 | {
22 | if (number % i == 0) return false;
23 | }
24 | return true;
25 | }
26 |
27 | [Fact]
28 | public void Prime()
29 | {
30 | int p = FastHashSet.FastHashSetUtil.GetEqualOrClosestHigherPrime(2);
31 |
32 | Assert.True(p == 3);
33 | }
34 |
35 | [Fact]
36 | public void Prime2()
37 | {
38 | for (int i = 2; i < 100_000; i++)
39 | {
40 | int p = FastHashSet.FastHashSetUtil.GetEqualOrClosestHigherPrime(i);
41 |
42 | for (int j = i; j < p; j++)
43 | {
44 | //if (IsPrime(j))
45 | //{
46 | // int adf = 1;
47 | //}
48 | Assert.False(IsPrime(j));
49 |
50 | }
51 | Assert.True(IsPrime(p));
52 | }
53 | }
54 |
55 | #if RunLongTests
56 | [Fact]
57 | public void Prime3()
58 | {
59 | for (int i = 100_000; i < 10_000_000; i++)
60 | {
61 | int p = FastHashSet.FastHashSetUtil.GetEqualOrClosestHigherPrime(i);
62 |
63 | for (int j = i; j < p; j++)
64 | {
65 | //if (IsPrime(j))
66 | //{
67 | // int adf = 1;
68 | //}
69 | Assert.False(IsPrime(j));
70 |
71 | }
72 | Assert.True(IsPrime(p));
73 | }
74 | }
75 | #endif
76 |
77 | #if RunVeryLongTests
78 | [Fact]
79 | public void Prime4()
80 | {
81 | for (int i = 10_000_000; i < 100_000_000; i++)
82 | {
83 | int p = FastHashSet.FastHashSetUtil.GetEqualOrClosestHigherPrime(i);
84 |
85 | for (int j = i; j < p; j++)
86 | {
87 | //if (IsPrime(j))
88 | //{
89 | // int adf = 1;
90 | //}
91 | Assert.False(IsPrime(j));
92 |
93 | }
94 | Assert.True(IsPrime(p));
95 | }
96 | }
97 | #endif
98 |
99 | [Fact]
100 | public void AddIn()
101 | {
102 | FastHashSet set = new FastHashSet();
103 | int x = 1;
104 | int x2 = 2;
105 | int x3 = 3;
106 | int x4 = 4;
107 | int x5 = 5;
108 | int x6 = 6;
109 | int x7 = 7;
110 | int x8 = 8;
111 | int x9 = 9;
112 | int x10 = 10;
113 | int x11 = 11;
114 | int x12 = 12;
115 | set.Add(in x);
116 | set.Add(in x2);
117 | set.Add(in x3);
118 | set.Add(in x4);
119 | set.Add(in x5);
120 | set.Add(in x6);
121 | set.Add(in x7);
122 | set.Add(in x8);
123 | set.Add(in x9);
124 | set.Add(in x10);
125 | set.Add(in x11);
126 | set.Add(in x12);
127 |
128 | Assert.Contains(1, set);
129 | Assert.True(set.Count == 12);
130 | }
131 |
132 | [Fact]
133 | public void AddIn2()
134 | {
135 | FastHashSet set = new FastHashSet();
136 | int x = 1;
137 | set.Add(in x);
138 |
139 | Assert.Contains(1, set);
140 | }
141 |
142 | [Fact]
143 | public void ContainsIn()
144 | {
145 | FastHashSet set = new FastHashSet();
146 | int x = 1;
147 | int x2 = 2;
148 | int x3 = 3;
149 | int x4 = 4;
150 | int x5 = 5;
151 | int x6 = 6;
152 | int x7 = 7;
153 | int x8 = 8;
154 | int x9 = 9;
155 | int x10 = 10;
156 | int x11 = 11;
157 | int x12 = 12;
158 | set.Add(in x);
159 | set.Add(in x2);
160 | set.Add(in x3);
161 | set.Add(in x4);
162 | set.Add(in x5);
163 | set.Add(in x6);
164 | set.Add(in x7);
165 | set.Add(in x8);
166 | set.Add(in x9);
167 | set.Add(in x10);
168 | set.Add(in x11);
169 | set.Add(in x12);
170 | set.Remove(x12);
171 |
172 | Assert.True(set.Contains(in x));
173 | Assert.True(set.Contains(in x2));
174 | Assert.True(set.Contains(in x3));
175 | Assert.True(set.Contains(in x4));
176 | Assert.True(set.Contains(in x5));
177 | Assert.True(set.Contains(in x6));
178 | Assert.True(set.Contains(in x7));
179 | Assert.True(set.Contains(in x8));
180 | Assert.True(set.Contains(in x9));
181 | Assert.True(set.Contains(in x10));
182 | Assert.True(set.Contains(in x11));
183 | Assert.False(set.Contains(in x12));
184 | }
185 |
186 | [Fact]
187 | public void ContainsIn2()
188 | {
189 | FastHashSet set = new FastHashSet();
190 | int x = 1;
191 | set.Add(in x);
192 | Assert.True(set.Contains(in x));
193 | }
194 |
195 | [Fact]
196 | public void RemoveIf()
197 | {
198 | FastHashSet set = new FastHashSet();
199 | int x = 1;
200 | int x2 = 2;
201 | int x3 = 3;
202 | int x4 = 4;
203 | int x5 = 5;
204 | int x6 = 6;
205 | int x7 = 7;
206 | int x8 = 8;
207 | int x9 = 9;
208 | int x10 = 10;
209 | int x11 = 11;
210 | int x12 = 12;
211 | set.Add(in x);
212 | set.Add(in x2);
213 | set.Add(in x3);
214 | set.Add(in x4);
215 | set.Add(in x5);
216 | set.Add(in x6);
217 | set.Add(in x7);
218 | set.Add(in x8);
219 | set.Add(in x9);
220 | set.Add(in x10);
221 | set.Add(in x11);
222 | set.Add(in x12);
223 |
224 | bool isRemoved = set.RemoveIf(in x, n => n < 2);
225 |
226 | Assert.True(isRemoved);
227 | Assert.DoesNotContain(1, set);
228 |
229 | isRemoved = set.RemoveIf(x2, n => n < 2);
230 |
231 | Assert.False(isRemoved);
232 | Assert.Contains(x2, set);
233 |
234 | set.Add(in x);
235 | bool isRemoved2 = set.RemoveIf(in x, n => n > 2);
236 |
237 | Assert.False(isRemoved2);
238 | Assert.Contains(1, set);
239 | }
240 |
241 | [Fact]
242 | public void RemoveIf2()
243 | {
244 | FastHashSet set = new FastHashSet();
245 | int x = 1;
246 | set.Add(in x);
247 |
248 | bool isRemoved = set.RemoveIf(in x, n => n < 2);
249 |
250 | Assert.True(isRemoved);
251 | Assert.DoesNotContain(1, set);
252 |
253 | set.Add(in x);
254 | bool isRemoved2 = set.RemoveIf(in x, n => n > 2);
255 |
256 | Assert.False(isRemoved2);
257 | Assert.Contains(1, set);
258 | }
259 |
260 | public struct IDCount
261 | {
262 | public int id;
263 | public int count;
264 |
265 | public IDCount(int id, int count)
266 | {
267 | this.id = id;
268 | this.count = count;
269 | }
270 |
271 | public override int GetHashCode()
272 | {
273 | return id;
274 | }
275 |
276 | public override bool Equals(object obj)
277 | {
278 | return this.id == ((IDCount)obj).id;
279 | }
280 | }
281 |
282 | [Fact]
283 | public void FindOrAdd()
284 | {
285 | FastHashSet set = new FastHashSet();
286 | IDCount x = new IDCount(1, 1);
287 | bool isFound;
288 | ref IDCount xRef = ref set.FindOrAdd(in x, out isFound);
289 | if (isFound)
290 | {
291 | xRef.count++;
292 | }
293 |
294 | bool added = set.Add(new IDCount(1, 1)); // alrady added
295 | Assert.False(added);
296 |
297 | set.Add(new IDCount(2, 1));
298 | set.Add(new IDCount(3, 1));
299 | set.Add(new IDCount(4, 1));
300 | set.Add(new IDCount(6, 1));
301 | set.Add(new IDCount(7, 1));
302 | set.Add(new IDCount(8, 1));
303 | set.Add(new IDCount(9, 1));
304 | set.Add(new IDCount(10, 1));
305 | set.Add(new IDCount(11, 1));
306 |
307 | Assert.False(isFound);
308 |
309 | xRef = ref set.FindOrAdd(in x, out isFound);
310 | if (isFound)
311 | {
312 | xRef.count++;
313 | }
314 | Assert.True(isFound);
315 | Assert.True(xRef.count == 2);
316 |
317 | Assert.Contains(x, set);
318 | }
319 |
320 | [Fact]
321 | public void FindOrAdd2()
322 | {
323 | FastHashSet set = new FastHashSet();
324 | IDCount x = new IDCount(1, 1);
325 | bool isFound;
326 | ref IDCount xRef = ref set.FindOrAdd(in x, out isFound);
327 | if (isFound)
328 | {
329 | xRef.count++;
330 | }
331 |
332 | Assert.False(isFound);
333 |
334 | xRef = ref set.FindOrAdd(in x, out isFound);
335 | if (isFound)
336 | {
337 | xRef.count++;
338 | }
339 | Assert.True(isFound);
340 | Assert.True(xRef.count == 2);
341 |
342 | Assert.Contains(x, set);
343 | }
344 |
345 | [Fact]
346 | public void Find()
347 | {
348 | FastHashSet set = new FastHashSet();
349 | IDCount x = new IDCount(1, 123);
350 | set.Add(in x);
351 | set.Add(new IDCount(1, 1)); // already added with 123 as count
352 | set.Add(new IDCount(2, 1));
353 | set.Add(new IDCount(3, 1));
354 | set.Add(new IDCount(4, 1));
355 | set.Add(new IDCount(6, 1));
356 | set.Add(new IDCount(7, 1));
357 | set.Add(new IDCount(8, 1));
358 | set.Add(new IDCount(9, 1));
359 | set.Add(new IDCount(10, 1));
360 | set.Add(new IDCount(11, 1));
361 | bool isFound;
362 | ref IDCount xRef = ref set.Find(in x, out isFound);
363 | if (isFound)
364 | {
365 | xRef.count++;
366 | }
367 |
368 | Assert.True(isFound);
369 |
370 | xRef = ref set.Find(in x, out isFound);
371 |
372 | Assert.True(isFound);
373 | Assert.True(xRef.count == 124);
374 |
375 | Assert.Contains(x, set);
376 | }
377 |
378 | [Fact]
379 | public void ReorderChainedNodesToBeAdjacent()
380 | {
381 | FastHashSet set = new FastHashSet();
382 | int x = 1;
383 | set.Add(in x);
384 |
385 | Random rand = new Random(17);
386 | int itemCnt = 10_000;
387 | int maxVal = itemCnt * 4;
388 | for (int i = 0; i < itemCnt; i++)
389 | {
390 | set.Add(rand.Next(0, maxVal));
391 | }
392 |
393 | int cnt = set.Count;
394 | List lst = set.GetChainLevelsCounts(out double avgNodeVisitsPerChain);
395 | set.ReorderChainedNodesToBeAdjacent();
396 | List lst2 = set.GetChainLevelsCounts(out double avgNodeVisitsPerChain2);
397 |
398 | Assert.Contains(x, set);
399 | Assert.True(set.Count == cnt);
400 | }
401 |
402 | [Fact]
403 | public void Find2()
404 | {
405 | FastHashSet set = new FastHashSet();
406 | IDCount x = new IDCount(1, 123);
407 | set.Add(in x);
408 | bool isFound;
409 | ref IDCount xRef = ref set.Find(in x, out isFound);
410 | if (isFound)
411 | {
412 | xRef.count++;
413 | }
414 |
415 | Assert.True(isFound);
416 |
417 | xRef = ref set.Find(in x, out isFound);
418 |
419 | Assert.True(isFound);
420 | Assert.True(xRef.count == 124);
421 |
422 | Assert.Contains(x, set);
423 | }
424 |
425 | [Fact]
426 | public void FindAndRemoveIf()
427 | {
428 | FastHashSet set = new FastHashSet();
429 | IDCount x = new IDCount(5, 1);
430 |
431 | set.Add(new IDCount(1, 1));
432 | set.Add(new IDCount(2, 1));
433 | set.Add(new IDCount(3, 1));
434 | set.Add(new IDCount(4, 1));
435 | set.Add(new IDCount(6, 1));
436 | set.Add(new IDCount(7, 1));
437 | set.Add(new IDCount(8, 1));
438 | set.Add(new IDCount(9, 1));
439 | set.Add(new IDCount(10, 1));
440 | set.Add(new IDCount(11, 1));
441 |
442 | bool isFound;
443 | bool isRemoved;
444 |
445 | // below is how you can increment a ref counted item and add if the current count = 1
446 | ref IDCount xRef = ref set.FindOrAdd(in x, out isFound);
447 | if (isFound)
448 | {
449 | xRef.count++;
450 | }
451 | Assert.False(isFound);
452 |
453 | xRef = ref set.FindOrAdd(in x, out isFound);
454 | if (isFound)
455 | {
456 | xRef.count++;
457 | }
458 | Assert.True(isFound);
459 |
460 | // below is how you can decrement a ref counted item and remove if the current count = 1
461 | xRef = ref set.FindAndRemoveIf(in x, n => n.count == 1, out isFound, out isRemoved);
462 | if (!isRemoved && isFound)
463 | {
464 | xRef.count--;
465 | }
466 |
467 | Assert.True(isFound);
468 | Assert.False(isRemoved);
469 |
470 | xRef = ref set.FindAndRemoveIf(in x, n => n.count == 1, out isFound, out isRemoved);
471 | if (!isRemoved && isFound)
472 | {
473 | xRef.count--;
474 | }
475 |
476 | Assert.True(isFound);
477 | Assert.True(isRemoved);
478 |
479 | Assert.DoesNotContain(x, set);
480 | }
481 |
482 | [Fact]
483 | public void FindAndRemoveIf2()
484 | {
485 | FastHashSet set = new FastHashSet();
486 | IDCount x = new IDCount(5, 1);
487 |
488 | set.Add(new IDCount(1, 1));
489 | set.Add(new IDCount(2, 1));
490 | set.Add(new IDCount(3, 1));
491 |
492 | bool isFound;
493 | bool isRemoved;
494 |
495 | // below is how you can increment a ref counted item and add if the current count = 1
496 | ref IDCount xRef = ref set.FindOrAdd(in x, out isFound);
497 | if (isFound)
498 | {
499 | xRef.count++;
500 | }
501 | Assert.False(isFound);
502 |
503 | xRef = ref set.FindOrAdd(in x, out isFound);
504 | if (isFound)
505 | {
506 | xRef.count++;
507 | }
508 | Assert.True(isFound);
509 |
510 | // below is how you can decrement a ref counted item and remove if the current count = 1
511 | xRef = ref set.FindAndRemoveIf(in x, n => n.count == 1, out isFound, out isRemoved);
512 | if (!isRemoved && isFound)
513 | {
514 | xRef.count--;
515 | }
516 |
517 | Assert.True(isFound);
518 | Assert.False(isRemoved);
519 |
520 | xRef = ref set.FindAndRemoveIf(in x, n => n.count == 1, out isFound, out isRemoved);
521 | if (!isRemoved && isFound)
522 | {
523 | xRef.count--;
524 | }
525 |
526 | Assert.True(isFound);
527 | Assert.True(isRemoved);
528 |
529 | Assert.DoesNotContain(x, set);
530 | }
531 | }
532 | }
533 |
--------------------------------------------------------------------------------
/FastHashSetTestsExtra/FastHashSetTestsExtra.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {BE23D537-9CFB-4711-B7D5-CF22395062DC}
8 | Library
9 | Properties
10 | FastHashSetTestsExtra
11 | FastHashSetTestsExtra
12 | v4.7.2
13 | 512
14 | true
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | {a99bfa31-0806-4e83-82cc-c50a0a5d1b55}
50 | FastHashSet
51 |
52 |
53 |
54 |
55 | 2.3.1
56 | runtime; build; native; contentfiles; analyzers; buildtransitive
57 | all
58 |
59 |
60 | 2.4.1
61 |
62 |
63 | 0.10.0
64 |
65 |
66 | 2.4.1
67 | runtime; build; native; contentfiles; analyzers; buildtransitive
68 | all
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/FastHashSetTestsExtra/FastHashSetTestsExtra.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.28729.10
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastHashSetTestsExtra", "FastHashSetTestsExtra.csproj", "{BE23D537-9CFB-4711-B7D5-CF22395062DC}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastHashSet", "..\FastHashSet\FastHashSet.csproj", "{A99BFA31-0806-4E83-82CC-C50A0A5D1B55}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {BE23D537-9CFB-4711-B7D5-CF22395062DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {BE23D537-9CFB-4711-B7D5-CF22395062DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {BE23D537-9CFB-4711-B7D5-CF22395062DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {BE23D537-9CFB-4711-B7D5-CF22395062DC}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {5BECDDB1-8E31-4A57-8462-39F4A114FAC1}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/FastHashSetTestsExtra/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FastHashSetTestsExtra")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("FastHashSetTestsExtra")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("be23d537-9cfb-4711-b7d5-cf22395062dc")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HashSetBench.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.28711.60
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HashSetBench", "HashSetBench\HashSetBench.csproj", "{5BAD01F3-672C-4B32-B04E-7110705892BA}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastHashSet", "FastHashSet\FastHashSet.csproj", "{A99BFA31-0806-4E83-82CC-C50A0A5D1B55}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {5BAD01F3-672C-4B32-B04E-7110705892BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {5BAD01F3-672C-4B32-B04E-7110705892BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {5BAD01F3-672C-4B32-B04E-7110705892BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {5BAD01F3-672C-4B32-B04E-7110705892BA}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {B7C52EE0-C4DC-4AB3-AED9-9C9AED6CA4DA}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/HashSetBench/App.config:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/HashSetBench/BenchUtil.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using SCG = System.Collections.Generic;
7 | using Motvin.Collections;
8 |
9 | namespace HashSetBench
10 | {
11 | public static class BenchUtil
12 | {
13 | public const int MaxCacheSizeInInts = 5_000_000;
14 |
15 | public static int[] clearCacheArray;
16 | public static int[] indicesIntoCacheArray;
17 |
18 | public static int sum;
19 |
20 | public static void ClearCpuCaches()
21 | {
22 | if (clearCacheArray == null)
23 | {
24 | clearCacheArray = new int[MaxCacheSizeInInts * 2];
25 |
26 | // populate the array
27 | for (int i = 0; i < clearCacheArray.Length; i++)
28 | {
29 | clearCacheArray[i] = 1;
30 | }
31 |
32 | // populate an array of indices into this array and mix up their order
33 | int indicesIntoCacheArraySize = clearCacheArray.Length / 16; // assume that a cache line is at least 16 bytes long
34 | indicesIntoCacheArray = new int[indicesIntoCacheArraySize];
35 | Random rand = new Random(89);
36 | int maxIdx = indicesIntoCacheArray.Length - 1;
37 | for (int i = 0; i < indicesIntoCacheArraySize; i++)
38 | {
39 | int idx = rand.Next(1, maxIdx); // don't allow 0 index because this will be the not-an-index value
40 |
41 | int j = idx;
42 | for ( ; j < indicesIntoCacheArraySize; j++)
43 | {
44 | if (indicesIntoCacheArray[i] == 0)
45 | {
46 | indicesIntoCacheArray[i] = idx;
47 | break;
48 | }
49 | }
50 |
51 | if (j == indicesIntoCacheArraySize)
52 | {
53 | // try to find a free spot going backwards
54 | j = idx -1;
55 | for ( ; j >= 0; j--)
56 | {
57 | if (indicesIntoCacheArray[i] == 0)
58 | {
59 | indicesIntoCacheArray[i] = idx;
60 | break;
61 | }
62 | }
63 | }
64 | }
65 | }
66 |
67 | for (int i = 0; i < indicesIntoCacheArray.Length; i++)
68 | {
69 | sum += clearCacheArray[indicesIntoCacheArray[i]];
70 | }
71 | }
72 |
73 | // make sure the minInt/maxInt range is large enough for the length of the array so that the random #'s aren't mostly already taken
74 | public static void PopulateIntArray(int[] dest, Random rand, int minInt, int maxInt, double uniqueValuePercent = 0)
75 | {
76 | if (uniqueValuePercent > 0)
77 | {
78 | int uniqueValuesCount = (int)(uniqueValuePercent * dest.Length);
79 | if (uniqueValuesCount <= 0)
80 | {
81 | uniqueValuesCount = 1; // there must be at least one of these unique values
82 | }
83 |
84 | // first get all unique values in the uniqueValuesArray
85 | HashSet h = new HashSet();
86 |
87 | int cnt = 0;
88 | if (dest.Length == uniqueValuesCount)
89 | {
90 | while (cnt < uniqueValuesCount)
91 | {
92 | int val = rand.Next(minInt, maxInt);
93 | if (h.Add(val))
94 | {
95 | dest[cnt] = val;
96 | cnt++;
97 | }
98 | }
99 | }
100 | else
101 | {
102 | int[] uniqueValuesArray = new int[uniqueValuesCount];
103 | while (cnt < uniqueValuesCount)
104 | {
105 | int val = rand.Next(minInt, maxInt);
106 | if (h.Add(val))
107 | {
108 | uniqueValuesArray[cnt] = val;
109 | cnt++;
110 | }
111 | }
112 |
113 | PopulateIntArrayFromUniqueArray(dest, rand, uniqueValuesArray, uniqueValuesCount);
114 | }
115 | }
116 | else
117 | {
118 | for (int i = 0; i < dest.Length; i++)
119 | {
120 | dest[i] = rand.Next(minInt, maxInt);
121 | }
122 | }
123 | }
124 |
125 | // put numberOfRandomValues in dest at random places (indices)
126 | // the random values are from minInt to maxInt
127 | public static void PopulateIntArrayAtRandomIndices(int[] dest, Random rand, int minInt, int maxInt, int numberOfRandomValues)
128 | {
129 | for (int i = 0; i < numberOfRandomValues; i++)
130 | {
131 | int val = rand.Next(minInt, maxInt);
132 | int idx = rand.Next(0, dest.Length - 1);
133 | dest[idx] = val;
134 | }
135 | }
136 |
137 | public static void PopulateIntArrayFromUniqueArray(int[] dest, Random rand, int[] uniqueValuesArray, int uniqueValuesCount)
138 | {
139 | // randomly pick an index for each value and indicate that this index is used
140 | bool[] isUsed = new bool[dest.Length];
141 |
142 | int maxIdx = dest.Length - 1;
143 | int cnt = 0;
144 | while (cnt < uniqueValuesCount)
145 | {
146 | int idx = rand.Next(0, maxIdx); // get a random dest index and place each unique value in these dest index slots
147 | if (!isUsed[idx])
148 | {
149 | dest[idx] = uniqueValuesArray[cnt];
150 | isUsed[idx] = true;
151 | cnt++;
152 | }
153 | }
154 |
155 | // now loop through dest and randomly pick a value from uniqueValuesArray - these will be duplicates
156 | maxIdx = uniqueValuesCount - 1;
157 | for (int i = 0; i < dest.Length; i++)
158 | {
159 | if (isUsed[i] == false)
160 | {
161 | int idx = rand.Next(0, maxIdx);
162 | dest[i] = uniqueValuesArray[idx];
163 | }
164 | }
165 | }
166 |
167 | public static void PopulateCollections25_25_50PctUnique(int maxN, out int[] uniqueArray, out int[] mixedArray,
168 | SCG.HashSet h, FastHashSet f = null, C5.HashSet c5 = null, SCG.SortedSet sortedSet = null, SCG.List lst = null)
169 | {
170 | uniqueArray = new int[maxN];
171 | mixedArray = new int[maxN];
172 |
173 | Random rand = new Random(89);
174 | BenchUtil.PopulateIntArray(uniqueArray, rand, int.MinValue, int.MaxValue, 1.0); // a array should have 100% unique values
175 |
176 | int uniqueValuesCount = maxN / 2; // this should produce a c array that has 50% unique values (the other 50% are duplicates), but all are actually in the uniqueArray, so 1, 1, 2, 2 would be an example of this
177 | if (uniqueValuesCount == 0)
178 | {
179 | uniqueValuesCount = 1;
180 | }
181 | BenchUtil.PopulateIntArrayFromUniqueArray(mixedArray, rand, uniqueArray, uniqueValuesCount);
182 | BenchUtil.PopulateIntArrayAtRandomIndices(mixedArray, rand, int.MinValue, int.MaxValue, maxN - uniqueValuesCount);
183 |
184 | if (h != null)
185 | {
186 | for (int i = 0; i < maxN; i++)
187 | {
188 | h.Add(uniqueArray[i]);
189 | }
190 | }
191 |
192 | if (f != null)
193 | {
194 | for (int i = 0; i < maxN; i++)
195 | {
196 | f.Add(uniqueArray[i]);
197 | }
198 | }
199 |
200 | if (c5 != null)
201 | {
202 | for (int i = 0; i < maxN; i++)
203 | {
204 | c5.Add(uniqueArray[i]);
205 | }
206 | }
207 |
208 | if (sortedSet != null)
209 | {
210 | for (int i = 0; i < maxN; i++)
211 | {
212 | sortedSet.Add(uniqueArray[i]);
213 | }
214 | }
215 |
216 | if (lst != null)
217 | {
218 | for (int i = 0; i < maxN; i++)
219 | {
220 | lst.Add(uniqueArray[i]);
221 | }
222 | lst.Sort();
223 | }
224 | }
225 | }
226 |
227 | public static class StringRandUtil
228 | {
229 | public const string uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
230 | public const string space = " ";
231 | public const string digits = "1234567890";
232 | public const string lowercaseChars = "abcdefghijklmnopqrstuvwxyz";
233 | public const string symbols = "!@#$%^&*()_+-=[]{};':\",./<>?\\";
234 |
235 | public static string CreateRandomString(Random rand, int minLen, int maxLen, string[] freqArray)
236 | {
237 | int len = rand.Next(minLen, maxLen);
238 |
239 | StringBuilder sb = new StringBuilder(new string(' ', len));
240 |
241 | int maxFreq = freqArray.Length - 1;
242 | string s;
243 | for (int i = 0; i < len; i++)
244 | {
245 | if (maxFreq == 0)
246 | {
247 | s = freqArray[0];
248 | }
249 | else
250 | {
251 | int freq = rand.Next(0, maxFreq);
252 | s = freqArray[freq];
253 | }
254 | int n = rand.Next(0, s.Length - 1);
255 |
256 | sb[i] = s[n];
257 | }
258 |
259 | return sb.ToString();
260 | }
261 | }
262 | }
263 |
--------------------------------------------------------------------------------
/HashSetBench/ClassAndStruct.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace HashSetBench
8 | {
9 | // this should be 8 bytes in size
10 | public struct SmallStruct : IEquatable
11 | {
12 | public int myInt;
13 | public int myInt2;
14 |
15 | public SmallStruct(int i, int i2)
16 | {
17 | myInt = i;
18 | myInt2 = i2;
19 | }
20 |
21 | public static SmallStruct CreateRand(Random rand)
22 | {
23 | int i = rand.Next(); // make this non-negative
24 | int i2 = rand.Next(); // make this non-negative
25 |
26 | return new SmallStruct(i, i2);
27 | }
28 |
29 | public override int GetHashCode()
30 | {
31 | int hash = 13;
32 |
33 | unchecked // the code below may overflow the hash int and that will cause an exception if compiler is checking for arithmetic overflow - unchecked prevents this
34 | {
35 | hash = (hash * 7) + myInt;
36 | hash = (hash * 7) + myInt2;
37 | }
38 |
39 | return hash;
40 | }
41 |
42 | public override bool Equals(object obj)
43 | {
44 | if (obj.GetType() != typeof(SmallStruct))
45 | {
46 | return false;
47 | }
48 |
49 | return Equals((SmallStruct)obj);
50 | }
51 |
52 | public bool Equals(SmallStruct other)
53 | {
54 | return (myInt == other.myInt && myInt2 == other.myInt2);
55 | }
56 |
57 | public static bool operator ==(SmallStruct c1, SmallStruct c2)
58 | {
59 | return c1.Equals(c2);
60 | }
61 |
62 | public static bool operator !=(SmallStruct c1, SmallStruct c2)
63 | {
64 | return !c1.Equals(c2);
65 | }
66 | }
67 |
68 | public sealed class SmallClass : IEquatable
69 | {
70 | public int myInt;
71 | public int myInt2;
72 |
73 | public SmallClass(int i, int i2)
74 | {
75 | myInt = i;
76 | myInt2 = i2;
77 | }
78 |
79 | public static SmallClass CreateRand(Random rand)
80 | {
81 | int i = rand.Next(); // make this non-negative
82 | int i2 = rand.Next(); // make this non-negative
83 |
84 | return new SmallClass(i, i2);
85 | }
86 |
87 | public override int GetHashCode()
88 | {
89 | int hash = 13;
90 |
91 | unchecked // the code below may overflow the hash int and that will cause an exception if compiler is checking for arithmetic overflow - unchecked prevents this
92 | {
93 | hash = (hash * 7) + myInt;
94 | hash = (hash * 7) + myInt2;
95 | }
96 |
97 | return hash;
98 | }
99 |
100 | public override bool Equals(object obj)
101 | {
102 | if (obj == null)
103 | {
104 | return false;
105 | }
106 |
107 | return Equals(obj as SmallClass);
108 | }
109 |
110 | public bool Equals(SmallClass other)
111 | {
112 | if (other == null)
113 | {
114 | return false;
115 | }
116 |
117 | return (myInt == other.myInt && myInt2 == other.myInt2);
118 | }
119 | }
120 |
121 | public struct SmallStructIntVal : IEquatable
122 | {
123 | public int myInt;
124 | public int refCountOrSum;
125 |
126 | public SmallStructIntVal(int i, int refCountOrSum)
127 | {
128 | myInt = i;
129 | this.refCountOrSum = refCountOrSum;
130 | }
131 |
132 | public override int GetHashCode()
133 | {
134 | return myInt;
135 | }
136 |
137 | public override bool Equals(object obj)
138 | {
139 | if (obj.GetType() != typeof(SmallStructIntVal))
140 | {
141 | return false;
142 | }
143 |
144 | return Equals((SmallStruct)obj);
145 | }
146 |
147 | public bool Equals(SmallStructIntVal other)
148 | {
149 | return (myInt == other.myInt);
150 | }
151 |
152 | public static bool operator ==(SmallStructIntVal c1, SmallStructIntVal c2)
153 | {
154 | return c1.Equals(c2);
155 | }
156 |
157 | public static bool operator !=(SmallStructIntVal c1, SmallStructIntVal c2)
158 | {
159 | return !c1.Equals(c2);
160 | }
161 | }
162 |
163 | public sealed class SmallClassIntVal : IEquatable
164 | {
165 | public int myInt;
166 | public int refCountOrSum;
167 |
168 | public SmallClassIntVal(int i, int refCountOrSum)
169 | {
170 | myInt = i;
171 | this.refCountOrSum = refCountOrSum;
172 | }
173 |
174 | public override int GetHashCode()
175 | {
176 | return myInt;
177 | }
178 |
179 | public override bool Equals(object obj)
180 | {
181 | return Equals(obj as SmallClassIntVal);
182 | }
183 |
184 | public bool Equals(SmallClassIntVal other)
185 | {
186 | if (other == null)
187 | {
188 | return false;
189 | }
190 |
191 | return (myInt == other.myInt);
192 | }
193 | }
194 |
195 | // this should be 8 bytes in size
196 | public struct SmallStructBasic
197 | {
198 | public int myInt;
199 | public int myInt2;
200 |
201 | public SmallStructBasic(int i, int i2)
202 | {
203 | myInt = i;
204 | myInt2 = i2;
205 | }
206 | }
207 |
208 | public class SmallClassBasic
209 | {
210 | public int myInt;
211 | public int myInt2;
212 |
213 | public SmallClassBasic(int i, int i2)
214 | {
215 | myInt = i;
216 | myInt2 = i2;
217 | }
218 | }
219 |
220 | // this should be about 20 bytes in size (assuming DateTime is 8 bytes)
221 | public struct MediumStruct : IEquatable
222 | {
223 | public DateTime myDate;
224 | public double myDouble;
225 | public int myInt;
226 |
227 | public MediumStruct(DateTime dt, double d, int i)
228 | {
229 | myDate = dt;
230 | myDouble = d;
231 | myInt = i;
232 | }
233 |
234 | public static MediumStruct CreateRand(Random rand)
235 | {
236 | double d = rand.NextDouble();
237 | int i = rand.Next(); // make this non-negative
238 | int year = rand.Next(1990, 2019);
239 | int month = rand.Next(1, 12);
240 | int day = rand.Next(1, 28);
241 |
242 | return new MediumStruct(new DateTime(year, month, day), d, i);
243 | }
244 |
245 | public override int GetHashCode()
246 | {
247 | int hash = 13;
248 |
249 | unchecked // the code below may overflow the hash int and that will cause an exception if compiler is checking for arithmetic overflow - unchecked prevents this
250 | {
251 | hash = (hash * 7) + myInt;
252 | hash = (hash * 7) + myDouble.GetHashCode();
253 | hash = (hash * 7) + myDate.GetHashCode();
254 | }
255 |
256 | return hash;
257 | }
258 |
259 | public override bool Equals(object obj)
260 | {
261 | if (obj.GetType() != typeof(MediumStruct))
262 | {
263 | return false;
264 | }
265 |
266 | return Equals((MediumStruct)obj);
267 | }
268 |
269 | public bool Equals(MediumStruct other)
270 | {
271 | return (myInt == other.myInt && myDouble == other.myDouble && myDate == other.myDate);
272 |
273 | }
274 |
275 | public static bool operator ==(MediumStruct c1, MediumStruct c2)
276 | {
277 | return c1.Equals(c2);
278 | }
279 |
280 | public static bool operator !=(MediumStruct c1, MediumStruct c2)
281 | {
282 | return !c1.Equals(c2);
283 | }
284 | }
285 |
286 | public sealed class MediumClass : IEquatable
287 | {
288 | public DateTime myDate;
289 | public double myDouble;
290 | public int myInt;
291 |
292 | public MediumClass(DateTime dt, double d, int i)
293 | {
294 | myDate = dt;
295 | myDouble = d;
296 | myInt = i;
297 | }
298 |
299 | public static MediumClass CreateRand(Random rand)
300 | {
301 | double d = rand.NextDouble();
302 | int i = rand.Next(); // make this non-negative
303 | int year = rand.Next(1990, 2019);
304 | int month = rand.Next(1, 12);
305 | int day = rand.Next(1, 28);
306 |
307 | return new MediumClass(new DateTime(year, month, day), d, i);
308 | }
309 |
310 | public override int GetHashCode()
311 | {
312 | int hash = 13;
313 |
314 | unchecked // the code below may overflow the hash int and that will cause an exception if compiler is checking for arithmetic overflow - unchecked prevents this
315 | {
316 | hash = (hash * 7) + myInt;
317 | hash = (hash * 7) + myDouble.GetHashCode();
318 | hash = (hash * 7) + myDate.GetHashCode();
319 | }
320 |
321 | return hash;
322 | }
323 |
324 | public override bool Equals(object obj)
325 | {
326 | if (obj == null)
327 | {
328 | return false;
329 | }
330 |
331 | return Equals(obj as MediumClass);
332 | }
333 |
334 | public bool Equals(MediumClass other)
335 | {
336 | if (other == null)
337 | {
338 | return false;
339 | }
340 |
341 | return (myInt == other.myInt && myDouble == other.myDouble && myDate == other.myDate);
342 | }
343 | }
344 |
345 | // this should be about 40 bytes, not including the space for the actual string bytes
346 | public struct LargeStruct : IEquatable
347 | {
348 | public DateTime myDate;
349 | public double myDouble;
350 | public double myDouble2;
351 | public int myInt;
352 | public int myInt2;
353 | public int myInt3;
354 | public string myString;
355 |
356 | public LargeStruct(DateTime dt, double d, double d2, int i, int i2, int i3, string s)
357 | {
358 | myDate = dt;
359 | myDouble = d;
360 | myDouble2 = d2;
361 | myInt = i;
362 | myInt2 = i2;
363 | myInt3 = i3;
364 | myString = s;
365 | }
366 |
367 | public static LargeStruct CreateRand(Random rand)
368 | {
369 | double d = rand.NextDouble();
370 | double d2 = rand.NextDouble();
371 | int i = rand.Next(); // make this non-negative
372 | int i2 = rand.Next(); // make this non-negative
373 | int i3 = rand.Next(); // make this non-negative
374 | int year = rand.Next(1990, 2019);
375 | int month = rand.Next(1, 12);
376 | int day = rand.Next(1, 28);
377 |
378 | string[] strFreq = new string[] {
379 | StringRandUtil.uppercaseChars,
380 | StringRandUtil.uppercaseChars,
381 | StringRandUtil.lowercaseChars,
382 | StringRandUtil.lowercaseChars,
383 | StringRandUtil.digits,
384 | StringRandUtil.space,
385 | StringRandUtil.symbols,
386 | };
387 | string s = StringRandUtil.CreateRandomString(rand, 10, 12, strFreq);
388 |
389 | return new LargeStruct(new DateTime(year, month, day), d, d2, i, i2, i3, s);
390 | }
391 |
392 | public override int GetHashCode()
393 | {
394 | int hash = 13;
395 |
396 | unchecked // the code below may overflow the hash int and that will cause an exception if compiler is checking for arithmetic overflow - unchecked prevents this
397 | {
398 | hash = (hash * 7) + myInt;
399 | hash = (hash * 7) + myInt2;
400 | hash = (hash * 7) + myInt3;
401 | hash = (hash * 7) + myDouble.GetHashCode();
402 | hash = (hash * 7) + myDouble2.GetHashCode();
403 | hash = (hash * 7) + myDate.GetHashCode();
404 | hash = (hash * 7) + myString.GetHashCode();
405 | }
406 |
407 | return hash;
408 | }
409 |
410 | public override bool Equals(object obj)
411 | {
412 | if (obj.GetType() != typeof(LargeStruct))
413 | {
414 | return false;
415 | }
416 |
417 | return Equals((LargeStruct)obj);
418 | }
419 |
420 | public bool Equals(LargeStruct other)
421 | {
422 | return (myInt == other.myInt && myInt2 == other.myInt2 && myInt3 == other.myInt3 && myDouble == other.myDouble && myDouble2 == other.myDouble2 && myDate == other.myDate && myString == other.myString);
423 | }
424 |
425 | public static bool operator ==(LargeStruct c1, LargeStruct c2)
426 | {
427 | return c1.Equals(c2);
428 | }
429 |
430 | public static bool operator !=(LargeStruct c1, LargeStruct c2)
431 | {
432 | return !c1.Equals(c2);
433 | }
434 | }
435 |
436 | // this should be about 40 bytes, not including the space for the actual string bytes
437 | public sealed class LargeClass : IEquatable
438 | {
439 | public DateTime myDate;
440 | public double myDouble;
441 | public double myDouble2;
442 | public int myInt;
443 | public int myInt2;
444 | public int myInt3;
445 | public string myString;
446 |
447 | public LargeClass(DateTime dt, double d, double d2, int i, int i2, int i3, string s)
448 | {
449 | myDate = dt;
450 | myDouble = d;
451 | myDouble2 = d2;
452 | myInt = i;
453 | myInt2 = i2;
454 | myInt3 = i3;
455 | myString = s;
456 | }
457 |
458 | public static LargeClass CreateRand(Random rand)
459 | {
460 | double d = rand.NextDouble();
461 | double d2 = rand.NextDouble();
462 | int i = rand.Next(); // make this non-negative
463 | int i2 = rand.Next(); // make this non-negative
464 | int i3 = rand.Next(); // make this non-negative
465 | int year = rand.Next(1990, 2019);
466 | int month = rand.Next(1, 12);
467 | int day = rand.Next(1, 28);
468 |
469 | string[] strFreq = new string[] {
470 | StringRandUtil.uppercaseChars,
471 | StringRandUtil.uppercaseChars,
472 | StringRandUtil.lowercaseChars,
473 | StringRandUtil.lowercaseChars,
474 | StringRandUtil.digits,
475 | StringRandUtil.space,
476 | StringRandUtil.symbols,
477 | };
478 | string s = StringRandUtil.CreateRandomString(rand, 10, 12, strFreq);
479 |
480 | return new LargeClass(new DateTime(year, month, day), d, d2, i, i2, i3, s);
481 | }
482 |
483 | public override int GetHashCode()
484 | {
485 | int hash = 13;
486 |
487 | unchecked // the code below may overflow the hash int and that will cause an exception if compiler is checking for arithmetic overflow - unchecked prevents this
488 | {
489 | hash = (hash * 7) + myInt;
490 | hash = (hash * 7) + myInt2;
491 | hash = (hash * 7) + myInt3;
492 | hash = (hash * 7) + myDouble.GetHashCode();
493 | hash = (hash * 7) + myDouble2.GetHashCode();
494 | hash = (hash * 7) + myDate.GetHashCode();
495 | hash = (hash * 7) + myString.GetHashCode();
496 | }
497 |
498 | return hash;
499 | }
500 |
501 | public override bool Equals(object obj)
502 | {
503 | if (obj == null)
504 | {
505 | return false;
506 | }
507 |
508 | return Equals(obj as LargeClass);
509 | }
510 |
511 | public bool Equals(LargeClass other)
512 | {
513 | if (other == null)
514 | {
515 | return false;
516 | }
517 |
518 | return (myInt == other.myInt && myInt2 == other.myInt2 && myInt3 == other.myInt3 && myDouble == other.myDouble && myDouble2 == other.myDouble2 && myDate == other.myDate && myString == other.myString);
519 | }
520 | }
521 |
522 | // this should be about 64 bytes, not including the space for the actual string bytes
523 | public struct VeryLargeStruct : IEquatable
524 | {
525 | public DateTime myDate;
526 | public double myDouble;
527 | public double myDouble2;
528 | public int myInt;
529 | public int myInt2;
530 | public int myInt3;
531 | public string myString;
532 |
533 | public VeryLargeStruct(DateTime dt, double d, double d2, int i, int i2, int i3, string s)
534 | {
535 | myDate = dt;
536 | myDouble = d;
537 | myDouble2 = d2;
538 | myInt = i;
539 | myInt2 = i2;
540 | myInt3 = i3;
541 | myString = s;
542 | }
543 |
544 | public static VeryLargeStruct CreateRand(Random rand)
545 | {
546 | double d = rand.NextDouble();
547 | double d2 = rand.NextDouble();
548 | int i = rand.Next(); // make this non-negative
549 | int i2 = rand.Next(); // make this non-negative
550 | int i3 = rand.Next(); // make this non-negative
551 | int year = rand.Next(1990, 2019);
552 | int month = rand.Next(1, 12);
553 | int day = rand.Next(1, 28);
554 |
555 | string[] strFreq = new string[] {
556 | StringRandUtil.uppercaseChars,
557 | StringRandUtil.uppercaseChars,
558 | StringRandUtil.lowercaseChars,
559 | StringRandUtil.lowercaseChars,
560 | StringRandUtil.digits,
561 | StringRandUtil.space,
562 | StringRandUtil.symbols,
563 | };
564 | string s = StringRandUtil.CreateRandomString(rand, 10, 12, strFreq);
565 |
566 | return new VeryLargeStruct(new DateTime(year, month, day), d, d2, i, i2, i3, s);
567 | }
568 |
569 | public override int GetHashCode()
570 | {
571 | int hash = 13;
572 |
573 | unchecked // the code below may overflow the hash int and that will cause an exception if compiler is checking for arithmetic overflow - unchecked prevents this
574 | {
575 | hash = (hash * 7) + myInt;
576 | hash = (hash * 7) + myInt2;
577 | hash = (hash * 7) + myInt3;
578 | hash = (hash * 7) + myDouble.GetHashCode();
579 | hash = (hash * 7) + myDouble2.GetHashCode();
580 | hash = (hash * 7) + myDate.GetHashCode();
581 | hash = (hash * 7) + myString.GetHashCode();
582 | }
583 |
584 | return hash;
585 | }
586 |
587 | public override bool Equals(object obj)
588 | {
589 | if (obj.GetType() != typeof(VeryLargeStruct))
590 | {
591 | return false;
592 | }
593 |
594 | return Equals((VeryLargeStruct)obj);
595 | }
596 |
597 | public bool Equals(VeryLargeStruct other)
598 | {
599 | return (myInt == other.myInt && myInt2 == other.myInt2 && myInt3 == other.myInt3 && myDouble == other.myDouble && myDouble2 == other.myDouble2 && myDate == other.myDate && myString == other.myString);
600 | }
601 |
602 | public static bool operator ==(VeryLargeStruct c1, VeryLargeStruct c2)
603 | {
604 | return c1.Equals(c2);
605 | }
606 |
607 | public static bool operator !=(VeryLargeStruct c1, VeryLargeStruct c2)
608 | {
609 | return !c1.Equals(c2);
610 | }
611 | }
612 |
613 | // this should be about 64 bytes, not including the space for the actual string bytes
614 | public sealed class VeryLargeClass : IEquatable
615 | {
616 | public DateTime myDate;
617 | public double myDouble;
618 | public double myDouble2;
619 | public int myInt;
620 | public int myInt2;
621 | public int myInt3;
622 | public string myString;
623 |
624 | public VeryLargeClass(DateTime dt, double d, double d2, int i, int i2, int i3, string s)
625 | {
626 | myDate = dt;
627 | myDouble = d;
628 | myDouble2 = d2;
629 | myInt = i;
630 | myInt2 = i2;
631 | myInt3 = i3;
632 | myString = s;
633 | }
634 |
635 | public static VeryLargeClass CreateRand(Random rand)
636 | {
637 | double d = rand.NextDouble();
638 | double d2 = rand.NextDouble();
639 | int i = rand.Next(); // make this non-negative
640 | int i2 = rand.Next(); // make this non-negative
641 | int i3 = rand.Next(); // make this non-negative
642 | int year = rand.Next(1990, 2019);
643 | int month = rand.Next(1, 12);
644 | int day = rand.Next(1, 28);
645 |
646 | string[] strFreq = new string[] {
647 | StringRandUtil.uppercaseChars,
648 | StringRandUtil.uppercaseChars,
649 | StringRandUtil.lowercaseChars,
650 | StringRandUtil.lowercaseChars,
651 | StringRandUtil.digits,
652 | StringRandUtil.space,
653 | StringRandUtil.symbols,
654 | };
655 | string s = StringRandUtil.CreateRandomString(rand, 10, 12, strFreq);
656 |
657 | return new VeryLargeClass(new DateTime(year, month, day), d, d2, i, i2, i3, s);
658 | }
659 |
660 | public override int GetHashCode()
661 | {
662 | int hash = 13;
663 |
664 | unchecked // the code below may overflow the hash int and that will cause an exception if compiler is checking for arithmetic overflow - unchecked prevents this
665 | {
666 | hash = (hash * 7) + myInt;
667 | hash = (hash * 7) + myInt2;
668 | hash = (hash * 7) + myInt3;
669 | hash = (hash * 7) + myDouble.GetHashCode();
670 | hash = (hash * 7) + myDouble2.GetHashCode();
671 | hash = (hash * 7) + myDate.GetHashCode();
672 | hash = (hash * 7) + myString.GetHashCode();
673 | }
674 |
675 | return hash;
676 | }
677 |
678 | public override bool Equals(object obj)
679 | {
680 | if (obj == null)
681 | {
682 | return false;
683 | }
684 |
685 | return Equals(obj as VeryLargeClass);
686 | }
687 |
688 | public bool Equals(VeryLargeClass other)
689 | {
690 | if (other == null)
691 | {
692 | return false;
693 | }
694 |
695 | return (myInt == other.myInt && myInt2 == other.myInt2 && myInt3 == other.myInt3 && myDouble == other.myDouble && myDouble2 == other.myDouble2 && myDate == other.myDate && myString == other.myString);
696 | }
697 | }
698 | }
699 |
--------------------------------------------------------------------------------
/HashSetBench/HashSetBench.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Debug
7 | AnyCPU
8 | {5BAD01F3-672C-4B32-B04E-7110705892BA}
9 | Exe
10 | HashSetBench
11 | HashSetBench
12 | v4.7.2
13 | 512
14 | true
15 | true
16 |
17 |
18 |
19 |
20 | AnyCPU
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 | 7.3
29 | false
30 | true
31 |
32 |
33 | AnyCPU
34 | pdbonly
35 | true
36 | bin\Release\
37 | TRACE
38 | prompt
39 | 4
40 | 7.3
41 | false
42 | true
43 |
44 |
45 | app.manifest
46 |
47 |
48 |
49 | False
50 | packages\BenchmarkDotNet.0.11.4\lib\netstandard2.0\BenchmarkDotNet.dll
51 |
52 |
53 | packages\BenchmarkDotNet.Diagnostics.Windows.0.11.4\lib\netstandard2.0\BenchmarkDotNet.Diagnostics.Windows.dll
54 |
55 |
56 | packages\C5.2.5.3\lib\net45\C5.dll
57 |
58 |
59 | packages\CommandLineParser.2.4.3\lib\netstandard2.0\CommandLine.dll
60 |
61 |
62 | packages\Microsoft.Diagnostics.Tracing.TraceEvent.2.0.34\lib\net45\Dia2Lib.dll
63 | True
64 |
65 |
66 | packages\Microsoft.CodeAnalysis.Common.2.10.0\lib\netstandard1.3\Microsoft.CodeAnalysis.dll
67 |
68 |
69 | packages\Microsoft.CodeAnalysis.CSharp.2.10.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll
70 |
71 |
72 | packages\Microsoft.Diagnostics.Tracing.TraceEvent.2.0.34\lib\net45\Microsoft.Diagnostics.FastSerialization.dll
73 |
74 |
75 | packages\Microsoft.Diagnostics.Tracing.TraceEvent.2.0.34\lib\net45\Microsoft.Diagnostics.Tracing.TraceEvent.dll
76 |
77 |
78 | packages\Microsoft.DotNet.PlatformAbstractions.2.1.0\lib\net45\Microsoft.DotNet.PlatformAbstractions.dll
79 |
80 |
81 | packages\Microsoft.Win32.Registry.4.5.0\lib\net461\Microsoft.Win32.Registry.dll
82 |
83 |
84 | packages\Microsoft.Diagnostics.Tracing.TraceEvent.2.0.34\lib\net45\OSExtensions.dll
85 |
86 |
87 |
88 | packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll
89 | True
90 | True
91 |
92 |
93 | packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll
94 |
95 |
96 |
97 | packages\System.Console.4.3.0\lib\net46\System.Console.dll
98 | True
99 | True
100 |
101 |
102 |
103 | packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll
104 | True
105 | True
106 |
107 |
108 | packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll
109 | True
110 | True
111 |
112 |
113 | packages\System.IO.4.3.0\lib\net462\System.IO.dll
114 | True
115 | True
116 |
117 |
118 | packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll
119 | True
120 | True
121 |
122 |
123 | packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll
124 | True
125 | True
126 |
127 |
128 | packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll
129 | True
130 | True
131 |
132 |
133 | packages\System.Linq.4.3.0\lib\net463\System.Linq.dll
134 | True
135 | True
136 |
137 |
138 | packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll
139 | True
140 | True
141 |
142 |
143 |
144 |
145 | packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll
146 | True
147 | True
148 |
149 |
150 | packages\System.Reflection.Metadata.1.6.0\lib\netstandard2.0\System.Reflection.Metadata.dll
151 |
152 |
153 | packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll
154 | True
155 | True
156 |
157 |
158 | packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
159 |
160 |
161 | packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll
162 | True
163 | True
164 |
165 |
166 | packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll
167 | True
168 | True
169 |
170 |
171 | packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
172 | True
173 | True
174 |
175 |
176 | packages\System.Security.AccessControl.4.5.0\lib\net461\System.Security.AccessControl.dll
177 |
178 |
179 | packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll
180 | True
181 | True
182 |
183 |
184 | packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll
185 | True
186 | True
187 |
188 |
189 | packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll
190 | True
191 | True
192 |
193 |
194 | packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll
195 | True
196 | True
197 |
198 |
199 | packages\System.Security.Principal.Windows.4.5.0\lib\net461\System.Security.Principal.Windows.dll
200 |
201 |
202 | packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll
203 |
204 |
205 | packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
206 |
207 |
208 | packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll
209 | True
210 | True
211 |
212 |
213 | packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 | packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll
223 | True
224 | True
225 |
226 |
227 | packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll
228 | True
229 | True
230 |
231 |
232 | packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll
233 | True
234 | True
235 |
236 |
237 | packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll
238 | True
239 | True
240 |
241 |
242 | packages\System.Xml.XPath.XmlDocument.4.3.0\lib\net46\System.Xml.XPath.XmlDocument.dll
243 |
244 |
245 | packages\Microsoft.Diagnostics.Tracing.TraceEvent.2.0.34\lib\net45\TraceReloggerLib.dll
246 | True
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 | {a99bfa31-0806-4e83-82cc-c50a0a5d1b55}
268 | FastHashSet
269 |
270 |
271 |
272 |
273 |
274 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
275 |
276 |
277 |
278 |
--------------------------------------------------------------------------------
/HashSetBench/HashSetBench8.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Motvin/FastHashSet/c9d43f6342055e32038be3b441d6758f40d9104f/HashSetBench/HashSetBench8.xlsx
--------------------------------------------------------------------------------
/HashSetBench/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using BenchmarkDotNet.Running;
4 | using System.Collections.Generic;
5 |
6 | namespace HashSetBench
7 | {
8 | class Program
9 | {
10 | static void Main(string[] args)
11 | {
12 | var summary = BenchmarkRunner.Run();
13 | //var summary = BenchmarkRunner.Run();
14 | //var summary2 = BenchmarkRunner.Run();
15 | //var summary = BenchmarkRunner.Run();
16 | //var summary = BenchmarkRunner.Run();
17 | //var summary2 = BenchmarkRunner.Run();
18 | //var summary = BenchmarkRunner.Run();
19 | //var summary2 = BenchmarkRunner.Run();
20 | //var summary3 = BenchmarkRunner.Run();
21 | //var summar4 = BenchmarkRunner.Run();
22 | //var summar5 = BenchmarkRunner.Run();
23 |
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/HashSetBench/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HashSetBench")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HashSetBench")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("5bad01f3-672c-4b32-b04e-7110705892ba")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HashSetBench/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
52 |
59 |
60 |
61 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/HashSetBench/packages.config:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetClassFast/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetClassFast/HashSetClassFast.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {62F10831-1467-4F15-B0A4-CC3D8A23DFEE}
8 | Exe
9 | HashSetClassFast
10 | HashSetClassFast
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | {be6aecf7-2469-4af6-9cdd-11f4e52387c7}
55 | Perf
56 |
57 |
58 | {a99bfa31-0806-4e83-82cc-c50a0a5d1b55}
59 | FastHashSet
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetClassFast/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Diagnostics;
7 | using Perf;
8 | using Motvin.Collections;
9 |
10 |
11 | namespace HashSetClassFast
12 | {
13 | class Program
14 | {
15 | static void Main(string[] args)
16 | {
17 | // cmd line params variables
18 | string dbConnStr = null;
19 | int runID = 0;
20 | int benchmarkMethodID = 0;
21 | int n;
22 | int maxN;
23 |
24 | try
25 | {
26 | DateTime startTime = DateTime.Now;
27 | //Console.WriteLine($"Args Count:" + args.Length.ToString());
28 | //foreach (string s in args)
29 | //{
30 | // Console.WriteLine(s);
31 | //}
32 | //Console.ReadKey();
33 |
34 | string errMsg = PerfUtil.GetCmdLineParams_DbNAndMaxN(args, out dbConnStr, out runID, out benchmarkMethodID, out n, out maxN);
35 | //if (errMsg != null)
36 | //{
37 | // Console.WriteLine(errMsg);
38 | //}
39 | //Console.WriteLine($"Args: {dbConnStr}; {runID.ToString()}; {benchmarkMethodID.ToString()}; {n.ToString()}; {maxN.ToString()}");
40 | //Console.ReadKey();
41 |
42 | int[] a = new int[n];
43 | int[] a2 = new int[n];
44 |
45 | Random rand = new Random(89);
46 | for (int i = 0; i < a.Length; i++)
47 | {
48 | a[i] = rand.Next();
49 | a2[i] = rand.Next();
50 | }
51 |
52 | FastHashSet setWarmup = new FastHashSet();
53 | setWarmup.Add(new SmallClass(1, 2));
54 |
55 | FastHashSet set = new FastHashSet();
56 |
57 | double overheadNanoSecs = PerfUtil.GetTimestampOverheadInNanoSeconds();
58 |
59 | PerfUtil.DoGCCollect();
60 |
61 | int iterations = 1;
62 | long startTicks;
63 | long endTicks;
64 | double ticks;
65 |
66 | // this is enough to jit things and not put everything in the cache
67 | //bool isContained = set.Contains(0);
68 |
69 | iterations = 1;
70 |
71 | //SmallClass sc = new SmallClass(a[0], a2[0]);
72 | startTicks = Stopwatch.GetTimestamp();
73 | for (int i = 0; i < a.Length; i++)
74 | {
75 | set.Add(new SmallClass(a[i], a2[i]));
76 | }
77 | // set.Add(sc);
78 |
79 | endTicks = Stopwatch.GetTimestamp();
80 |
81 | ticks = (double)(endTicks - startTicks);
82 |
83 | double nanoSecs = PerfUtil.GetNanoSecondsFromTicks(ticks, Stopwatch.Frequency) - overheadNanoSecs;
84 |
85 | PerfDb.InsertMeasurement(dbConnStr, runID, benchmarkMethodID, n, iterations, nanoSecs, startTime, DateTime.Now);
86 |
87 | }
88 | catch (Exception ex)
89 | {
90 | Console.Write(ex.ToString());
91 | if (!string.IsNullOrEmpty(dbConnStr))
92 | {
93 | // write error to db
94 | PerfDb.InsertRunError(dbConnStr, runID, benchmarkMethodID, ex);
95 | }
96 | else
97 | {
98 | // log error to file
99 | }
100 | }
101 | }
102 | }
103 | public sealed class SmallClass : IEquatable
104 | {
105 | public int myInt;
106 | public int myInt2;
107 |
108 | public SmallClass(int i, int i2)
109 | {
110 | myInt = i;
111 | myInt2 = i2;
112 | }
113 |
114 | public static SmallClass CreateRand(Random rand)
115 | {
116 | int i = rand.Next(); // make this non-negative
117 | int i2 = rand.Next(); // make this non-negative
118 |
119 | return new SmallClass(i, i2);
120 | }
121 |
122 | public override int GetHashCode()
123 | {
124 | int hash = 13;
125 |
126 | unchecked // the code below may overflow the hash int and that will cause an exception if compiler is checking for arithmetic overflow - unchecked prevents this
127 | {
128 | hash = (hash * 7) + myInt;
129 | hash = (hash * 7) + myInt2;
130 | }
131 |
132 | return hash;
133 | }
134 |
135 | public override bool Equals(object obj)
136 | {
137 | if (obj == null)
138 | {
139 | return false;
140 | }
141 |
142 | return Equals(obj as SmallClass);
143 | }
144 |
145 | public bool Equals(SmallClass other)
146 | {
147 | if (other == null)
148 | {
149 | return false;
150 | }
151 |
152 | return (myInt == other.myInt && myInt2 == other.myInt2);
153 | }
154 | }
155 |
156 |
157 | }
158 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetClassFast/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HashSetClassFast")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HashSetClassFast")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("62f10831-1467-4f15-b0a4-cc3d8a23dfee")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetContains/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetContains/HashSetContains.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {7D8A36A4-D784-4210-B669-DC058EDB138B}
8 | Exe
9 | HashSetContains
10 | HashSetContains
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | false
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 | false
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | {be6aecf7-2469-4af6-9cdd-11f4e52387c7}
57 | Perf
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetContains/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Diagnostics;
7 |
8 | using SCG = System.Collections.Generic;
9 | using Perf;
10 |
11 | namespace HashSetContains
12 | {
13 | class Program
14 | {
15 | static void Main(string[] args)
16 | {
17 | // cmd line params variables
18 | string dbConnStr = null;
19 | int runID = 0;
20 | int benchmarkMethodID = 0;
21 | int n;
22 | int maxN;
23 |
24 | try
25 | {
26 | DateTime startTime = DateTime.Now;
27 | //Console.WriteLine($"Args Count:" + args.Length.ToString());
28 | //foreach (string s in args)
29 | //{
30 | // Console.WriteLine(s);
31 | //}
32 | //Console.ReadKey();
33 |
34 | string errMsg = PerfUtil.GetCmdLineParams_DbNAndMaxN(args, out dbConnStr, out runID, out benchmarkMethodID, out n, out maxN);
35 | //if (errMsg != null)
36 | //{
37 | // Console.WriteLine(errMsg);
38 | //}
39 | //Console.WriteLine($"Args: {dbConnStr}; {runID.ToString()}; {benchmarkMethodID.ToString()}; {n.ToString()}; {maxN.ToString()}");
40 | //Console.ReadKey();
41 |
42 | int[] a;
43 | int[] c;
44 |
45 | HashSet set = new HashSet();
46 |
47 | BenchUtil.PopulateArrays25_25_50PctUnique(maxN, out a, out c);
48 |
49 | // in a real world scenario, we will have probably have recently added the items into the set, so no need to try to clear the cache or anything
50 | for (int i = 0; i < maxN; i++)
51 | {
52 | set.Add(a[i]);
53 | }
54 |
55 | double overheadNanoSecs = PerfUtil.GetTimestampOverheadInNanoSeconds();
56 |
57 | PerfUtil.DoGCCollect();
58 |
59 | int iterations = 1;
60 | long startTicks;
61 | long endTicks;
62 | double ticks;
63 |
64 | // this is enough to jit things and not put everything in the cache
65 | bool isContained = set.Contains(0);
66 |
67 | if (maxN <= 1000)
68 | {
69 | iterations = 1;
70 |
71 | // there amount of time taken for these is too small to measure just one iteration - so we measure multiple iterations in a loop and get the time for these
72 | // the mean time is this total time / iterations
73 |
74 | // for really small operations, like a single contains on a hashet that has 8 items you would probably want to call at least a feww hundred Contains
75 | // and then average that - the maxN wouldn't work too well if that was just 8
76 |
77 | startTicks = Stopwatch.GetTimestamp();
78 |
79 | for (int i = 0; i < maxN; i++)
80 | {
81 | set.Contains(c[i]);
82 | }
83 |
84 | endTicks = Stopwatch.GetTimestamp();
85 |
86 | ticks = ((endTicks - startTicks) * n) / (double)maxN;
87 | }
88 | else
89 | {
90 | iterations = 1;
91 |
92 | startTicks = Stopwatch.GetTimestamp();
93 | for (int i = 0; i < n; i++) // loop overhead is ok because we assume there will be some loop in real-world scenario
94 | {
95 | set.Contains(c[i]);
96 | }
97 | endTicks = Stopwatch.GetTimestamp();
98 |
99 | ticks = (double)(endTicks - startTicks);
100 | }
101 |
102 | double nanoSecs = PerfUtil.GetNanoSecondsFromTicks(ticks, Stopwatch.Frequency) - overheadNanoSecs;
103 |
104 | PerfDb.InsertMeasurement(dbConnStr, runID, benchmarkMethodID, n, iterations, nanoSecs, startTime, DateTime.Now);
105 | }
106 | catch (Exception ex)
107 | {
108 | Console.Write(ex.ToString());
109 | if (!string.IsNullOrEmpty(dbConnStr))
110 | {
111 | // write error to db
112 | PerfDb.InsertRunError(dbConnStr, runID, benchmarkMethodID, ex);
113 | }
114 | else
115 | {
116 | // log error to file
117 | }
118 | }
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetContains/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HashSetContains")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HashSetContains")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("7d8a36a4-d784-4210-b669-dc058edb138b")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetContainsC5/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetContainsC5/HashSetContainsC5.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {74C21F9D-D981-474B-893F-64DE177CF895}
8 | Exe
9 | HashSetContainsC5
10 | HashSetContainsC5
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | false
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 | false
36 |
37 |
38 |
39 | ..\packages\C5.2.5.3\lib\net45\C5.dll
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | {be6aecf7-2469-4af6-9cdd-11f4e52387c7}
60 | Perf
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetContainsC5/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | //using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Diagnostics;
5 | using Perf;
6 |
7 | namespace HashSetContainsC5
8 | {
9 | class Program
10 | {
11 | static void Main(string[] args)
12 | {
13 | // cmd line params variables
14 | string dbConnStr = null;
15 | int runID = 0;
16 | int benchmarkMethodID = 0;
17 | int n;
18 | int maxN;
19 |
20 | try
21 | {
22 | DateTime startTime = DateTime.Now;
23 | //Console.WriteLine($"Args Count:" + args.Length.ToString());
24 | //foreach (string s in args)
25 | //{
26 | // Console.WriteLine(s);
27 | //}
28 | //Console.ReadKey();
29 |
30 | string errMsg = PerfUtil.GetCmdLineParams_DbNAndMaxN(args, out dbConnStr, out runID, out benchmarkMethodID, out n, out maxN);
31 | //if (errMsg != null)
32 | //{
33 | // Console.WriteLine(errMsg);
34 | //}
35 | //Console.WriteLine($"Args: {dbConnStr}; {runID.ToString()}; {benchmarkMethodID.ToString()}; {n.ToString()}; {maxN.ToString()}");
36 | //Console.ReadKey();
37 |
38 | int[] a;
39 | int[] c;
40 |
41 | C5.HashSet set = new C5.HashSet();
42 |
43 | BenchUtil.PopulateArrays25_25_50PctUnique(maxN, out a, out c);
44 |
45 | // in a real world scenario, we will have probably have recently added the items into the set, so no need to try to clear the cache or anything
46 | for (int i = 0; i < maxN; i++)
47 | {
48 | set.Add(a[i]);
49 | }
50 |
51 | double overheadNanoSecs = PerfUtil.GetTimestampOverheadInNanoSeconds();
52 |
53 | PerfUtil.DoGCCollect();
54 |
55 | int iterations = 1;
56 | long startTicks;
57 | long endTicks;
58 | double ticks;
59 |
60 | // this is enough to jit things and not put everything in the cache
61 | bool isContained = set.Contains(0);
62 |
63 | if (maxN <= 1000)
64 | {
65 | iterations = 1;
66 |
67 | // there amount of time taken for these is too small to measure just one iteration - so we measure multiple iterations in a loop and get the time for these
68 | // the mean time is this total time / iterations
69 |
70 | startTicks = Stopwatch.GetTimestamp();
71 |
72 | for (int i = 0; i < maxN; i++)
73 | {
74 | set.Contains(c[i]);
75 | }
76 |
77 | endTicks = Stopwatch.GetTimestamp();
78 |
79 | ticks = ((endTicks - startTicks) * n) / (double)maxN;
80 | }
81 | else
82 | {
83 | iterations = 1;
84 |
85 | startTicks = Stopwatch.GetTimestamp();
86 | for (int i = 0; i < n; i++) // loop overhead is ok because we assume there will be some loop in real-world scenario
87 | {
88 | set.Contains(c[i]);
89 | }
90 | endTicks = Stopwatch.GetTimestamp();
91 |
92 | ticks = (double)(endTicks - startTicks);
93 | }
94 |
95 | double nanoSecs = PerfUtil.GetNanoSecondsFromTicks(ticks, Stopwatch.Frequency) - overheadNanoSecs;
96 |
97 | PerfDb.InsertMeasurement(dbConnStr, runID, benchmarkMethodID, n, iterations, nanoSecs, startTime, DateTime.Now);
98 | }
99 | catch (Exception ex)
100 | {
101 | Console.Write(ex.ToString());
102 | if (!string.IsNullOrEmpty(dbConnStr))
103 | {
104 | // write error to db
105 | PerfDb.InsertRunError(dbConnStr, runID, benchmarkMethodID, ex);
106 | }
107 | else
108 | {
109 | // log error to file
110 | }
111 | }
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetContainsC5/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HashSetContainsC5")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HashSetContainsC5")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("74c21f9d-d981-474b-893f-64de177cf895")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetContainsFast/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetContainsFast/HashSetContainsFast.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {39E71982-201B-43A3-98EF-C9E78F252498}
8 | Exe
9 | HashSetContainsFast
10 | HashSetContainsFast
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | false
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 | false
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | {be6aecf7-2469-4af6-9cdd-11f4e52387c7}
57 | Perf
58 |
59 |
60 | {a99bfa31-0806-4e83-82cc-c50a0a5d1b55}
61 | FastHashSet
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetContainsFast/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using Perf;
5 | using Motvin.Collections;
6 |
7 | namespace HashSetContainsFast
8 | {
9 | class Program
10 | {
11 | static void Main(string[] args)
12 | {
13 | // cmd line params variables
14 | string dbConnStr = null;
15 | int runID = 0;
16 | int benchmarkMethodID = 0;
17 | int n;
18 | int maxN;
19 |
20 | try
21 | {
22 | DateTime startTime = DateTime.Now;
23 | //Console.WriteLine($"Args Count:" + args.Length.ToString());
24 | //foreach (string s in args)
25 | //{
26 | // Console.WriteLine(s);
27 | //}
28 | //Console.ReadKey();
29 |
30 | string errMsg = PerfUtil.GetCmdLineParams_DbNAndMaxN(args, out dbConnStr, out runID, out benchmarkMethodID, out n, out maxN);
31 | //if (errMsg != null)
32 | //{
33 | // Console.WriteLine(errMsg);
34 | //}
35 | //Console.WriteLine($"Args: {dbConnStr}; {runID.ToString()}; {benchmarkMethodID.ToString()}; {n.ToString()}; {maxN.ToString()}");
36 | //Console.ReadKey();
37 |
38 | int[] a;
39 | int[] c;
40 |
41 | FastHashSet set = new FastHashSet();
42 |
43 | BenchUtil.PopulateArrays25_25_50PctUnique(maxN, out a, out c);
44 |
45 | // in a real world scenario, we will have probably have recently added the items into the set, so no need to try to clear the cache or anything
46 | for (int i = 0; i < maxN; i++)
47 | {
48 | set.Add(a[i]);
49 | }
50 |
51 | double overheadNanoSecs = PerfUtil.GetTimestampOverheadInNanoSeconds();
52 |
53 | PerfUtil.DoGCCollect();
54 |
55 | int iterations = 1;
56 | long startTicks;
57 | long endTicks;
58 | double ticks;
59 |
60 | // this is enough to jit things and not put everything in the cache
61 | bool isContained = set.Contains(0);
62 |
63 | if (maxN <= 1000)
64 | {
65 | iterations = 1;
66 |
67 | // there amount of time taken for these is too small to measure just one iteration - so we measure multiple iterations in a loop and get the time for these
68 | // the mean time is this total time / iterations
69 |
70 | startTicks = Stopwatch.GetTimestamp();
71 |
72 | for (int i = 0; i < maxN; i++)
73 | {
74 | set.Contains(c[i]);
75 | }
76 |
77 | endTicks = Stopwatch.GetTimestamp();
78 |
79 | ticks = ((endTicks - startTicks) * n) / (double)maxN;
80 | }
81 | else
82 | {
83 | iterations = 1;
84 |
85 | startTicks = Stopwatch.GetTimestamp();
86 | for (int i = 0; i < n; i++) // loop overhead is ok because we assume there will be some loop in real-world scenario
87 | {
88 | set.Contains(c[i]);
89 | }
90 | endTicks = Stopwatch.GetTimestamp();
91 |
92 | ticks = (double)(endTicks - startTicks);
93 | }
94 |
95 | double nanoSecs = PerfUtil.GetNanoSecondsFromTicks(ticks, Stopwatch.Frequency) - overheadNanoSecs;
96 |
97 | PerfDb.InsertMeasurement(dbConnStr, runID, benchmarkMethodID, n, iterations, nanoSecs, startTime, DateTime.Now);
98 |
99 | }
100 | catch (Exception ex)
101 | {
102 | Console.Write(ex.ToString());
103 | if (!string.IsNullOrEmpty(dbConnStr))
104 | {
105 | // write error to db
106 | PerfDb.InsertRunError(dbConnStr, runID, benchmarkMethodID, ex);
107 | }
108 | else
109 | {
110 | // log error to file
111 | }
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetContainsFast/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HashSetContainsFast")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HashSetContainsFast")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("39e71982-201b-43a3-98ef-c9e78f252498")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetPerf.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.28714.193
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HashSetPerf", "HashSetPerf\HashSetPerf.csproj", "{F46BDD49-599A-4158-9578-228B7868F1EB}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastHashSet", "..\FastHashSet\FastHashSet.csproj", "{A99BFA31-0806-4E83-82CC-C50A0A5D1B55}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HashSetContainsC5", "HashSetContainsC5\HashSetContainsC5.csproj", "{74C21F9D-D981-474B-893F-64DE177CF895}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HashSetContains", "HashSetContains\HashSetContains.csproj", "{7D8A36A4-D784-4210-B669-DC058EDB138B}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HashSetContainsFast", "HashSetContainsFast\HashSetContainsFast.csproj", "{39E71982-201B-43A3-98EF-C9E78F252498}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perf", "..\..\Perf\Perf.csproj", "{BE6AECF7-2469-4AF6-9CDD-11F4E52387C7}"
17 | EndProject
18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HashSetClassFast", "HashSetClassFast\HashSetClassFast.csproj", "{62F10831-1467-4F15-B0A4-CC3D8A23DFEE}"
19 | EndProject
20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HashSetStructFast", "HashSetStructFast\HashSetStructFast.csproj", "{BBB3A2E6-0774-429D-AE19-016A63B265B0}"
21 | EndProject
22 | Global
23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
24 | Debug|Any CPU = Debug|Any CPU
25 | Release|Any CPU = Release|Any CPU
26 | EndGlobalSection
27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
28 | {F46BDD49-599A-4158-9578-228B7868F1EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {F46BDD49-599A-4158-9578-228B7868F1EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {F46BDD49-599A-4158-9578-228B7868F1EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {F46BDD49-599A-4158-9578-228B7868F1EB}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {A99BFA31-0806-4E83-82CC-C50A0A5D1B55}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {74C21F9D-D981-474B-893F-64DE177CF895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {74C21F9D-D981-474B-893F-64DE177CF895}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {74C21F9D-D981-474B-893F-64DE177CF895}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {74C21F9D-D981-474B-893F-64DE177CF895}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {7D8A36A4-D784-4210-B669-DC058EDB138B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {7D8A36A4-D784-4210-B669-DC058EDB138B}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {7D8A36A4-D784-4210-B669-DC058EDB138B}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {7D8A36A4-D784-4210-B669-DC058EDB138B}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {39E71982-201B-43A3-98EF-C9E78F252498}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {39E71982-201B-43A3-98EF-C9E78F252498}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {39E71982-201B-43A3-98EF-C9E78F252498}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {39E71982-201B-43A3-98EF-C9E78F252498}.Release|Any CPU.Build.0 = Release|Any CPU
48 | {BE6AECF7-2469-4AF6-9CDD-11F4E52387C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49 | {BE6AECF7-2469-4AF6-9CDD-11F4E52387C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
50 | {BE6AECF7-2469-4AF6-9CDD-11F4E52387C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 | {BE6AECF7-2469-4AF6-9CDD-11F4E52387C7}.Release|Any CPU.Build.0 = Release|Any CPU
52 | {62F10831-1467-4F15-B0A4-CC3D8A23DFEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
53 | {62F10831-1467-4F15-B0A4-CC3D8A23DFEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
54 | {62F10831-1467-4F15-B0A4-CC3D8A23DFEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
55 | {62F10831-1467-4F15-B0A4-CC3D8A23DFEE}.Release|Any CPU.Build.0 = Release|Any CPU
56 | {BBB3A2E6-0774-429D-AE19-016A63B265B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
57 | {BBB3A2E6-0774-429D-AE19-016A63B265B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
58 | {BBB3A2E6-0774-429D-AE19-016A63B265B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
59 | {BBB3A2E6-0774-429D-AE19-016A63B265B0}.Release|Any CPU.Build.0 = Release|Any CPU
60 | EndGlobalSection
61 | GlobalSection(SolutionProperties) = preSolution
62 | HideSolutionNode = FALSE
63 | EndGlobalSection
64 | GlobalSection(ExtensibilityGlobals) = postSolution
65 | SolutionGuid = {BA876230-63F0-4219-B505-5778CF7AB54E}
66 | EndGlobalSection
67 | EndGlobal
68 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetPerf/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetPerf/BenchUtil.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 | using System.Threading.Tasks;
5 | using System.Collections.Generic;
6 | using Motvin.Collections;
7 |
8 | namespace HashSetBench
9 | {
10 | public static class BenchUtil
11 | {
12 | public const int MaxCacheSizeInInts = 5_000_000;
13 |
14 | public static int[] clearCacheArray;
15 | public static int[] indicesIntoCacheArray;
16 |
17 | public static int sum;
18 |
19 | public static void ClearCpuCaches()
20 | {
21 | if (clearCacheArray == null)
22 | {
23 | clearCacheArray = new int[MaxCacheSizeInInts * 2];
24 |
25 | // populate the array
26 | for (int i = 0; i < clearCacheArray.Length; i++)
27 | {
28 | clearCacheArray[i] = 1;
29 | }
30 |
31 | // populate an array of indices into this array and mix up their order
32 | int indicesIntoCacheArraySize = clearCacheArray.Length / 16; // assume that a cache line is at least 16 bytes long
33 | indicesIntoCacheArray = new int[indicesIntoCacheArraySize];
34 | Random rand = new Random(89);
35 | int maxIdx = indicesIntoCacheArray.Length - 1;
36 | for (int i = 0; i < indicesIntoCacheArraySize; i++)
37 | {
38 | int idx = rand.Next(1, maxIdx); // don't allow 0 index because this will be the not-an-index value
39 |
40 | int j = idx;
41 | for ( ; j < indicesIntoCacheArraySize; j++)
42 | {
43 | if (indicesIntoCacheArray[i] == 0)
44 | {
45 | indicesIntoCacheArray[i] = idx;
46 | break;
47 | }
48 | }
49 |
50 | if (j == indicesIntoCacheArraySize)
51 | {
52 | // try to find a free spot going backwards
53 | j = idx -1;
54 | for ( ; j >= 0; j--)
55 | {
56 | if (indicesIntoCacheArray[i] == 0)
57 | {
58 | indicesIntoCacheArray[i] = idx;
59 | break;
60 | }
61 | }
62 | }
63 | }
64 | }
65 |
66 | for (int i = 0; i < indicesIntoCacheArray.Length; i++)
67 | {
68 | sum += clearCacheArray[indicesIntoCacheArray[i]];
69 | }
70 | }
71 |
72 | // make sure the minInt/maxInt range is large enough for the length of the array so that the random #'s aren't mostly already taken
73 | public static void PopulateIntArray(int[] dest, Random rand, int minInt, int maxInt, double uniqueValuePercent = 0)
74 | {
75 | if (uniqueValuePercent > 0)
76 | {
77 | int uniqueValuesCount = (int)(uniqueValuePercent * dest.Length);
78 | if (uniqueValuesCount <= 0)
79 | {
80 | uniqueValuesCount = 1; // there must be at least one of these unique values
81 | }
82 |
83 | // first get all unique values in the uniqueValuesArray
84 | HashSet h = new HashSet();
85 |
86 | int cnt = 0;
87 | if (dest.Length == uniqueValuesCount)
88 | {
89 | while (cnt < uniqueValuesCount)
90 | {
91 | int val = rand.Next(minInt, maxInt);
92 | if (h.Add(val))
93 | {
94 | dest[cnt] = val;
95 | cnt++;
96 | }
97 | }
98 | }
99 | else
100 | {
101 | int[] uniqueValuesArray = new int[uniqueValuesCount];
102 | while (cnt < uniqueValuesCount)
103 | {
104 | int val = rand.Next(minInt, maxInt);
105 | if (h.Add(val))
106 | {
107 | uniqueValuesArray[cnt] = val;
108 | cnt++;
109 | }
110 | }
111 |
112 | PopulateIntArrayFromUniqueArray(dest, rand, uniqueValuesArray, uniqueValuesCount);
113 | }
114 | }
115 | else
116 | {
117 | for (int i = 0; i < dest.Length; i++)
118 | {
119 | dest[i] = rand.Next(minInt, maxInt);
120 | }
121 | }
122 | }
123 |
124 | // put numberOfRandomValues in dest at random places (indices)
125 | // the random values are from minInt to maxInt
126 | public static void PopulateIntArrayAtRandomIndices(int[] dest, Random rand, int minInt, int maxInt, int numberOfRandomValues)
127 | {
128 | for (int i = 0; i < numberOfRandomValues; i++)
129 | {
130 | int val = rand.Next(minInt, maxInt);
131 | int idx = rand.Next(0, dest.Length - 1);
132 | dest[idx] = val;
133 | }
134 | }
135 |
136 | public static void PopulateIntArrayFromUniqueArray(int[] dest, Random rand, int[] uniqueValuesArray, int uniqueValuesCount)
137 | {
138 | // randomly pick an index for each value and indicate that this index is used
139 | bool[] isUsed = new bool[dest.Length];
140 |
141 | int maxIdx = dest.Length - 1;
142 | int cnt = 0;
143 | while (cnt < uniqueValuesCount)
144 | {
145 | int idx = rand.Next(0, maxIdx); // get a random dest index and place each unique value in these dest index slots
146 | if (!isUsed[idx])
147 | {
148 | dest[idx] = uniqueValuesArray[cnt];
149 | isUsed[idx] = true;
150 | cnt++;
151 | }
152 | }
153 |
154 | // now loop through dest and randomly pick a value from uniqueValuesArray - these will be duplicates
155 | maxIdx = uniqueValuesCount - 1;
156 | for (int i = 0; i < dest.Length; i++)
157 | {
158 | if (isUsed[i] == false)
159 | {
160 | int idx = rand.Next(0, maxIdx);
161 | dest[i] = uniqueValuesArray[idx];
162 | }
163 | }
164 | }
165 |
166 | public static void PopulateCollections25_25_50PctUnique(int maxN, out int[] uniqueArray, out int[] mixedArray,
167 | HashSet h, FastHashSet f = null, C5.HashSet c5 = null, SortedSet sortedSet = null, List lst = null)
168 | {
169 | uniqueArray = new int[maxN];
170 | mixedArray = new int[maxN];
171 |
172 | Random rand = new Random(89);
173 | BenchUtil.PopulateIntArray(uniqueArray, rand, int.MinValue, int.MaxValue, 1.0); // a array should have 100% unique values
174 |
175 | int uniqueValuesCount = maxN / 2; // this should produce a c array that has 50% unique values (the other 50% are duplicates), but all are actually in the uniqueArray, so 1, 1, 2, 2 would be an example of this
176 | if (uniqueValuesCount == 0)
177 | {
178 | uniqueValuesCount = 1;
179 | }
180 | BenchUtil.PopulateIntArrayFromUniqueArray(mixedArray, rand, uniqueArray, uniqueValuesCount);
181 | BenchUtil.PopulateIntArrayAtRandomIndices(mixedArray, rand, int.MinValue, int.MaxValue, maxN - uniqueValuesCount);
182 |
183 | if (h != null)
184 | {
185 | for (int i = 0; i < maxN; i++)
186 | {
187 | h.Add(uniqueArray[i]);
188 | }
189 | }
190 |
191 | if (f != null)
192 | {
193 | for (int i = 0; i < maxN; i++)
194 | {
195 | f.Add(uniqueArray[i]);
196 | }
197 | }
198 |
199 | if (c5 != null)
200 | {
201 | for (int i = 0; i < maxN; i++)
202 | {
203 | c5.Add(uniqueArray[i]);
204 | }
205 | }
206 |
207 | if (sortedSet != null)
208 | {
209 | for (int i = 0; i < maxN; i++)
210 | {
211 | sortedSet.Add(uniqueArray[i]);
212 | }
213 | }
214 |
215 | if (lst != null)
216 | {
217 | for (int i = 0; i < maxN; i++)
218 | {
219 | lst.Add(uniqueArray[i]);
220 | }
221 | lst.Sort();
222 | }
223 | }
224 | }
225 |
226 | public static class StringRandUtil
227 | {
228 | public const string uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
229 | public const string space = " ";
230 | public const string digits = "1234567890";
231 | public const string lowercaseChars = "abcdefghijklmnopqrstuvwxyz";
232 | public const string symbols = "!@#$%^&*()_+-=[]{};':\",./<>?\\";
233 |
234 | public static string CreateRandomString(Random rand, int minLen, int maxLen, string[] freqArray)
235 | {
236 | int len = rand.Next(minLen, maxLen);
237 |
238 | StringBuilder sb = new StringBuilder(new string(' ', len));
239 |
240 | int maxFreq = freqArray.Length - 1;
241 | string s;
242 | for (int i = 0; i < len; i++)
243 | {
244 | if (maxFreq == 0)
245 | {
246 | s = freqArray[0];
247 | }
248 | else
249 | {
250 | int freq = rand.Next(0, maxFreq);
251 | s = freqArray[freq];
252 | }
253 | int n = rand.Next(0, s.Length - 1);
254 |
255 | sb[i] = s[n];
256 | }
257 |
258 | return sb.ToString();
259 | }
260 | }
261 | }
262 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetPerf/HashSetPerf.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {F46BDD49-599A-4158-9578-228B7868F1EB}
8 | Exe
9 | HashSetPerf
10 | HashSetPerf
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | false
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 | false
36 |
37 |
38 |
39 | ..\packages\C5.2.5.3\lib\net45\C5.dll
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | {be6aecf7-2469-4af6-9cdd-11f4e52387c7}
62 | Perf
63 |
64 |
65 | {a99bfa31-0806-4e83-82cc-c50a0a5d1b55}
66 | FastHashSet
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetPerf/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Text;
6 | using System.Runtime.CompilerServices;
7 |
8 | using SCG = System.Collections.Generic;
9 | using Motvin.Collections;
10 | using Perf;
11 |
12 | namespace HashSetPerf
13 | {
14 | class Program
15 | {
16 | static void Main(string[] args)
17 | {
18 | //string outputFileName = @"e:\\proj\\summary.tsv";
19 | //int minN = 100_000;
20 | //int maxN = 1_000_000;
21 |
22 | //int incrementNBy = 10_000;
23 | string errMsg = PerfUtil.GetCmdLineParams_OutputFileAndMinMaxIncN(args, out int minN, out int maxN, out int incrementNBy, out string outputFileName);
24 |
25 | int nCount = ((maxN - minN) / incrementNBy) + 1;
26 | int[] nArray = new int[nCount];
27 |
28 | int idx = 0;
29 | for (int n = minN; n <= maxN; n += incrementNBy, idx++)
30 | {
31 | nArray[idx] = n;
32 | }
33 |
34 | const int LoopUnrollCount = 1;
35 | const int IterartionCount = 512;
36 | const int IterartionWarmupCount = 16;
37 |
38 | long [] ticksH = new long[nArray.Length * IterartionCount * LoopUnrollCount];
39 | int ticksIdxForH = 0;
40 |
41 | long [] ticksF = new long[nArray.Length * IterartionCount * LoopUnrollCount];
42 | int ticksIdxForF = 0;
43 |
44 | long [] ticksC = new long[nArray.Length * IterartionCount * LoopUnrollCount];
45 | int ticksIdxForC = 0;
46 |
47 | long startTicks;
48 |
49 | double overheadTicks = PerfUtil.GetTimestampOverheadInNanoSeconds();
50 |
51 | int[] a;
52 | int[] c;
53 |
54 | SCG.HashSet h = new HashSet();
55 | FastHashSet f = new FastHashSet();
56 | C5.HashSet c5 = new C5.HashSet();
57 |
58 | HashSetBench.BenchUtil.PopulateCollections25_25_50PctUnique(maxN, out a, out c, h, f, c5);
59 |
60 | // not sure if we should run bechmark 1 and then benchmark 2 separately so that the presence of the one doesn't effect the other???
61 | // in practice they will probably not be run together one after the other
62 |
63 | PerfUtil.DoGCCollect();
64 |
65 | int N;
66 | for (int j = 0; j < nArray.Length; j++)
67 | {
68 | N = nArray[j];
69 |
70 | // not really sure what running the warmup really does - it can put things in the cache that maybe shouldn't be there because they won't be in a real application???
71 | // still, if we execute the same code with the same data in a loop alot of times, this will populate the cache unrealistically
72 | // also if we do a warmup, the jit times will be removed, but does this represent reality - jit times do happen in real running code???
73 |
74 | for (int iterationIdx = 0; iterationIdx < IterartionWarmupCount; iterationIdx++)
75 | {
76 | // SCG_Contains
77 | for (int i = 0; i < N; i++)
78 | {
79 | h.Contains(c[i]);
80 | }
81 |
82 | // Fast_Contains
83 | for (int i = 0; i < N; i++)
84 | {
85 | f.Contains(c[i]);
86 | }
87 |
88 | for (int i = 0; i < N; i++)
89 | {
90 | c5.Contains(c[i]);
91 | }
92 | }
93 |
94 | for (int iterationIdx = 0; iterationIdx < IterartionCount; iterationIdx++)
95 | {
96 | // to minimize the effects of the loop code on the count, unroll each bechmark 2 times
97 | // also alternate randomly between the order of these to minimize any effects of order
98 | // not sure what effects loop unrolling has since that part isn't contained in the stopwatch time
99 | // still there might be some residual effects on CPU registers? - not really sure
100 |
101 | // 1
102 |
103 | // there is some overhead that should be removed - it is returning from GetTimestamp and setting startTicks and afterwards calling GetTimestamp until the point where the return value is obtained
104 | // we should determine this overhead by calling
105 | startTicks = Stopwatch.GetTimestamp();
106 | for (int i = 0; i < N; i++)
107 | {
108 | h.Contains(c[i]);
109 | }
110 | ticksH[ticksIdxForH++] = Stopwatch.GetTimestamp() - startTicks;
111 |
112 | startTicks = Stopwatch.GetTimestamp();
113 | for (int i = 0; i < N; i++)
114 | {
115 | f.Contains(c[i]);
116 | }
117 | ticksF[ticksIdxForF++] = Stopwatch.GetTimestamp() - startTicks;
118 |
119 | startTicks = Stopwatch.GetTimestamp();
120 | for (int i = 0; i < N; i++)
121 | {
122 | c5.Contains(c[i]);
123 | }
124 | ticksC[ticksIdxForC++] = Stopwatch.GetTimestamp() - startTicks;
125 | }
126 | }
127 |
128 | // summarize and output the data
129 |
130 | BenchmarkSummaries summaries = new BenchmarkSummaries();
131 |
132 | summaries.AddNSummaryList(NSummary.CreateNSummaryListForBenchmark(overheadTicks, nArray, IterartionCount * LoopUnrollCount, ticksH), "SCG_Contains");
133 |
134 | summaries.AddNSummaryList(NSummary.CreateNSummaryListForBenchmark(overheadTicks, nArray, IterartionCount * LoopUnrollCount, ticksF), "Fast_Contains");
135 |
136 | summaries.AddNSummaryList(NSummary.CreateNSummaryListForBenchmark(overheadTicks, nArray, IterartionCount * LoopUnrollCount, ticksC), "C5_Contains");
137 |
138 | summaries.OutputSummariesToFile(outputFileName, "SCG_Contains");
139 | }
140 | }
141 |
142 | public static class Perf
143 | {
144 | }
145 |
146 |
147 | // public class Timings
148 | // {
149 | //private long[] timingsArray;
150 | //private int timingsIdx;
151 |
152 | //[MethodImpl(MethodImplOptions.AggressiveInlining)] //??? not sure this should be used
153 | //public Timings(int timingsCount)
154 | //{
155 | // timingsArray = new long[timingsCount];
156 | //}
157 |
158 | //[MethodImpl(MethodImplOptions.AggressiveInlining)]
159 | //public void Start(Stopwatch sw)
160 | //{
161 | // sw.Restart();
162 | //}
163 |
164 | //[MethodImpl(MethodImplOptions.AggressiveInlining)]
165 | //public void Stop(Stopwatch sw, bool getElapsedTime = true)
166 | //{
167 | // sw.Stop();
168 | // if (getElapsedTime)
169 | // {
170 | // timingsArray[timingsIdx++] = sw.ElapsedTicks;
171 | // }
172 | //}
173 |
174 | //[MethodImpl(MethodImplOptions.AggressiveInlining)]
175 | //public void StopAndRestart(Stopwatch sw, bool getElapsedTime = true)
176 | //{
177 | // if (getElapsedTime)
178 | // {
179 | // sw.Stop();
180 | // timingsArray[timingsIdx++] = sw.ElapsedTicks;
181 | // }
182 | // sw.Restart();
183 | //}
184 |
185 | //public void Clear()
186 | //{
187 | // Array
188 | //}
189 |
190 | //public static void WriteSummaryToFile(string fileName, Timings[] timimngsPerBechmarkArray, string[] benchmarkNameArray)
191 | //{
192 | // foreach ()
193 | // perfArray
194 | // long ticksPerSec = Stopwatch.Frequency;
195 | // long nanoSecPerTick = (1000L * 1000L * 1000L) / ticksPerSec;
196 |
197 | //}
198 | // }
199 |
200 | }
201 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetPerf/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HashSetPerf")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HashSetPerf")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("f46bdd49-599a-4158-9578-228b7868f1eb")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetPerf/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetStructFast/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetStructFast/HashSetStructFast.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {BBB3A2E6-0774-429D-AE19-016A63B265B0}
8 | Exe
9 | HashSetStructFast
10 | HashSetStructFast
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | {be6aecf7-2469-4af6-9cdd-11f4e52387c7}
55 | Perf
56 |
57 |
58 | {a99bfa31-0806-4e83-82cc-c50a0a5d1b55}
59 | FastHashSet
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetStructFast/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Diagnostics;
5 | using Perf;
6 | using Motvin.Collections;
7 |
8 | namespace HashSetStructFast
9 | {
10 | class Program
11 | {
12 | static void Main(string[] args)
13 | {
14 | // cmd line params variables
15 | string dbConnStr = null;
16 | int runID = 0;
17 | int benchmarkMethodID = 0;
18 | int n;
19 | int maxN;
20 |
21 | try
22 | {
23 | DateTime startTime = DateTime.Now;
24 | //Console.WriteLine($"Args Count:" + args.Length.ToString());
25 | //foreach (string s in args)
26 | //{
27 | // Console.WriteLine(s);
28 | //}
29 | //Console.ReadKey();
30 |
31 | string errMsg = PerfUtil.GetCmdLineParams_DbNAndMaxN(args, out dbConnStr, out runID, out benchmarkMethodID, out n, out maxN);
32 | //if (errMsg != null)
33 | //{
34 | // Console.WriteLine(errMsg);
35 | //}
36 | //Console.WriteLine($"Args: {dbConnStr}; {runID.ToString()}; {benchmarkMethodID.ToString()}; {n.ToString()}; {maxN.ToString()}");
37 | //Console.ReadKey();
38 |
39 | int[] a = new int[n];
40 | int[] a2 = new int[n];
41 |
42 | Random rand = new Random(89);
43 | for (int i = 0; i < a.Length; i++)
44 | {
45 | a[i] = rand.Next();
46 | a2[i] = rand.Next();
47 | }
48 |
49 | FastHashSet setWarmup = new FastHashSet();
50 | setWarmup.Add(new SmallStruct(1, 2));
51 |
52 | FastHashSet set = new FastHashSet();
53 |
54 | double overheadNanoSecs = PerfUtil.GetTimestampOverheadInNanoSeconds();
55 |
56 | PerfUtil.DoGCCollect();
57 |
58 | int iterations = 1;
59 | long startTicks;
60 | long endTicks;
61 | double ticks;
62 |
63 | // this is enough to jit things and not put everything in the cache
64 | //bool isContained = set.Contains(0);
65 |
66 | iterations = 1;
67 |
68 | startTicks = Stopwatch.GetTimestamp();
69 | for (int i = 0; i < a.Length; i++)
70 | {
71 | set.Add(new SmallStruct(a[i], a2[i]));
72 | }
73 |
74 | endTicks = Stopwatch.GetTimestamp();
75 |
76 | ticks = (double)(endTicks - startTicks);
77 |
78 | double nanoSecs = PerfUtil.GetNanoSecondsFromTicks(ticks, Stopwatch.Frequency) - overheadNanoSecs;
79 |
80 | PerfDb.InsertMeasurement(dbConnStr, runID, benchmarkMethodID, n, iterations, nanoSecs, startTime, DateTime.Now);
81 |
82 | }
83 | catch (Exception ex)
84 | {
85 | Console.Write(ex.ToString());
86 | if (!string.IsNullOrEmpty(dbConnStr))
87 | {
88 | // write error to db
89 | PerfDb.InsertRunError(dbConnStr, runID, benchmarkMethodID, ex);
90 | }
91 | else
92 | {
93 | // log error to file
94 | }
95 | }
96 | }
97 | }
98 | // this should be 8 bytes in size
99 | public struct SmallStruct : IEquatable
100 | {
101 | public int myInt;
102 | public int myInt2;
103 |
104 | public SmallStruct(int i, int i2)
105 | {
106 | myInt = i;
107 | myInt2 = i2;
108 | }
109 |
110 | public static SmallStruct CreateRand(Random rand)
111 | {
112 | int i = rand.Next(); // make this non-negative
113 | int i2 = rand.Next(); // make this non-negative
114 |
115 | return new SmallStruct(i, i2);
116 | }
117 |
118 | public override int GetHashCode()
119 | {
120 | int hash = 13;
121 |
122 | unchecked // the code below may overflow the hash int and that will cause an exception if compiler is checking for arithmetic overflow - unchecked prevents this
123 | {
124 | hash = (hash * 7) + myInt;
125 | hash = (hash * 7) + myInt2;
126 | }
127 |
128 | return hash;
129 | }
130 |
131 | public override bool Equals(object obj)
132 | {
133 | if (obj.GetType() != typeof(SmallStruct))
134 | {
135 | return false;
136 | }
137 |
138 | return Equals((SmallStruct)obj);
139 | }
140 |
141 | public bool Equals(SmallStruct other)
142 | {
143 | return (myInt == other.myInt && myInt2 == other.myInt2);
144 | }
145 |
146 | public static bool operator ==(SmallStruct c1, SmallStruct c2)
147 | {
148 | return c1.Equals(c2);
149 | }
150 |
151 | public static bool operator !=(SmallStruct c1, SmallStruct c2)
152 | {
153 | return !c1.Equals(c2);
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/HashSetPerf/HashSetStructFast/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HashSetStructFast")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HashSetStructFast")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("bbb3a2e6-0774-429d-ae19-016a63b265b0")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FastHashSet
2 | FastHashSet is a replacement for the generic HashSet<T>. It is usually faster, has more predictable memory allocations, and uses C# 7.x ref returns and readonly ref params (in).
3 |
--------------------------------------------------------------------------------