├── .gitignore ├── LICENSE ├── NMS.DynamicDictionary.2.5.1.snupkg ├── Project.sln ├── README.md ├── samples └── Project │ ├── Program.cs │ └── Project.csproj ├── src ├── DynamicDictionary │ ├── Api │ │ ├── FastStringDictionary.cs │ │ ├── FuzzyDictionary.cs │ │ ├── PrecisionDictionary.cs │ │ └── Utils │ │ │ └── CurrentLock.cs │ ├── Base │ │ └── DynamicDictionaryBase.cs │ ├── Builder │ │ ├── DynamicDictionaryBuilder.cs │ │ └── DynamicSwitchBuilder.cs │ ├── DynamicDictionary.csproj │ ├── Extension │ │ └── ExtensionApi.cs │ └── Implementation │ │ ├── CustomerCache.cs │ │ ├── FuzzyCache.cs │ │ ├── HashCache.cs │ │ └── PrecisionCache.cs └── readme.txt └── test ├── BenchmarkProject ├── BenchmarkProject.csproj ├── BenchmarkTest.cs ├── Program.cs └── TestModel.cs └── UTProject ├── FuzzyTest.cs ├── HashTest.cs ├── Model ├── BuilderModel.cs ├── OperatorModel.cs ├── TestModel.cs └── TestStaticModel.cs ├── NatashaIni.cs ├── PrecisionTest.cs ├── TextFile1.txt └── UTProject.csproj /.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 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Night Moon Studio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NMS.DynamicDictionary.2.5.1.snupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/night-moon-studio/DynamicDictionary/5e07bc10139a85633c5cc0b81b7fc1c8cd718a26/NMS.DynamicDictionary.2.5.1.snupkg -------------------------------------------------------------------------------- /Project.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31912.275 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Project", "samples\Project\Project.csproj", "{570DAB44-5303-459F-A8B0-11C406E6FB4F}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UTProject", "test\UTProject\UTProject.csproj", "{DC5084F8-097B-482F-B20B-1471F61326A1}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{84977F43-7A74-4310-B07F-D4FBF5D0333F}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C4396801-F1E3-4033-B973-B7A12807EFFF}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9A154FFA-A8AE-473E-8940-7020D44B9141}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BenchmarkProject", "test\BenchmarkProject\BenchmarkProject.csproj", "{BADB6031-8605-40B4-94BF-96256438A77C}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DynamicDictionary", "src\DynamicDictionary\DynamicDictionary.csproj", "{B1C95DDB-48C0-4286-A00B-E90CC6389E98}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Release|Any CPU = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {570DAB44-5303-459F-A8B0-11C406E6FB4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {570DAB44-5303-459F-A8B0-11C406E6FB4F}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {570DAB44-5303-459F-A8B0-11C406E6FB4F}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {570DAB44-5303-459F-A8B0-11C406E6FB4F}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {DC5084F8-097B-482F-B20B-1471F61326A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {DC5084F8-097B-482F-B20B-1471F61326A1}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {DC5084F8-097B-482F-B20B-1471F61326A1}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {DC5084F8-097B-482F-B20B-1471F61326A1}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {BADB6031-8605-40B4-94BF-96256438A77C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {BADB6031-8605-40B4-94BF-96256438A77C}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {BADB6031-8605-40B4-94BF-96256438A77C}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {BADB6031-8605-40B4-94BF-96256438A77C}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {B1C95DDB-48C0-4286-A00B-E90CC6389E98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {B1C95DDB-48C0-4286-A00B-E90CC6389E98}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {B1C95DDB-48C0-4286-A00B-E90CC6389E98}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {B1C95DDB-48C0-4286-A00B-E90CC6389E98}.Release|Any CPU.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | GlobalSection(NestedProjects) = preSolution 47 | {570DAB44-5303-459F-A8B0-11C406E6FB4F} = {84977F43-7A74-4310-B07F-D4FBF5D0333F} 48 | {DC5084F8-097B-482F-B20B-1471F61326A1} = {C4396801-F1E3-4033-B973-B7A12807EFFF} 49 | {BADB6031-8605-40B4-94BF-96256438A77C} = {C4396801-F1E3-4033-B973-B7A12807EFFF} 50 | {B1C95DDB-48C0-4286-A00B-E90CC6389E98} = {9A154FFA-A8AE-473E-8940-7020D44B9141} 51 | EndGlobalSection 52 | GlobalSection(ExtensibilityGlobals) = postSolution 53 | SolutionGuid = {E330F2E1-7532-4657-A941-C1782EAE9D1C} 54 | EndGlobalSection 55 | EndGlobal 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # DynamicDictionary 3 | 基于BTFindTree项目的动态缓存构造库 4 | 5 | 6 | #### 使用方法(User Api): 7 | 8 |
9 | 10 | - 引入 动态构件库: NMS.DynamicDictionary 11 | 12 | - 初始化 Natasha : NatashaInitializer.InitializeAndPreheating(); 13 | 14 | ```C# 15 | 16 | var fastDict = dict.HashTree / PrecitionTree / FuzzyTree(); 17 | var result = fastDict["a"]; 18 | fastDict["a"] = "b"; 19 | fastDict["other"] = "b"; //ERROR dict 在生成时未带有 other 键 20 | 21 | ``` 22 | 23 | #### 性能测试 24 | 25 | ![benchmark](https://images.gitee.com/uploads/images/2020/1201/172724_a9004a04_1478282.png) 26 | 27 |
28 | 29 | #### 捐赠 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /samples/Project/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.CompilerServices; 4 | using System.Threading.Tasks; 5 | 6 | namespace Project 7 | { 8 | class Program 9 | { 10 | public static event Func a; 11 | static void Main(string[] args) 12 | { 13 | a += Program_a; 14 | NatashaInitializer.Preheating(); 15 | var domainName = Test(); 16 | for (int i = 0; i < 6; i++) 17 | { 18 | GC.Collect(); 19 | GC.WaitForPendingFinalizers(); 20 | } 21 | Console.WriteLine(domainName); 22 | Console.WriteLine(DomainManagement.IsDeleted(domainName)); 23 | Console.ReadKey(); 24 | } 25 | public static async Task b() 26 | { 27 | await a(1); 28 | } 29 | private static async Task Program_a(int arg) 30 | { 31 | await Task.Delay(100); 32 | } 33 | 34 | [MethodImpl(MethodImplOptions.NoInlining)] 35 | public unsafe static string Test() 36 | { 37 | var dict2 = new Dictionary(); 38 | var dict = new Dictionary(); 39 | for (int i = 0; i < 10; i++) 40 | { 41 | 42 | dict[i.ToString()] = i; 43 | dict2[i] = i.ToString(); 44 | 45 | } 46 | var test = dict2.CustomerTree(item => item.ToString()); 47 | 48 | 49 | var temp = dict.HashTree(); 50 | var name = temp.GetType().Name; 51 | var result = temp["1"]; 52 | //var a = temp.GetKeys(1); 53 | //var domainName = temp.ProxyType.GetDomain().Name; 54 | Console.WriteLine(DomainManagement.IsDeleted(name)); 55 | // temp.Dispose(); 56 | for (int i = 0; i < 6; i++) 57 | { 58 | GC.Collect(); 59 | } 60 | return name; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /samples/Project/Project.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | true 10 | 11 | 12 | 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/DynamicDictionary/Api/FastStringDictionary.cs: -------------------------------------------------------------------------------- 1 | using DynamicDictionary.Api.Utils; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.Runtime.CompilerServices; 7 | using System.Text; 8 | 9 | namespace DynamicDictionary.Api 10 | { 11 | public class FastStringDictionary : IDictionary 12 | { 13 | private readonly CurrentLock _currentLock; 14 | protected internal readonly ConcurrentDictionary _dict_cache; 15 | protected internal DynamicDictionaryBase _fast_cache; 16 | protected Action SaveFastCache; 17 | protected internal bool use_default; 18 | public FastStringDictionary(bool useDefault) 19 | { 20 | use_default = useDefault; 21 | _currentLock = new CurrentLock(); 22 | _dict_cache = new ConcurrentDictionary(); 23 | _fast_cache = _dict_cache.PrecisioTree(use_default); 24 | 25 | } 26 | public TValue this[string key] 27 | { 28 | 29 | get 30 | { 31 | if (_currentLock.CanGetLock()) 32 | { 33 | return _fast_cache[key]; 34 | } 35 | return _dict_cache[key]; 36 | } 37 | set 38 | { 39 | 40 | _dict_cache[key] = value; 41 | Add(key, value); 42 | 43 | } 44 | } 45 | 46 | public ICollection Keys => _dict_cache.Keys; 47 | 48 | public ICollection Values => _dict_cache.Values; 49 | 50 | public int Count => _dict_cache.Count; 51 | 52 | public bool IsReadOnly => true; 53 | 54 | 55 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 56 | public void Add(string key, TValue value) 57 | { 58 | _dict_cache[key] = value; 59 | Refresh(); 60 | } 61 | 62 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 63 | public void Add(KeyValuePair item) 64 | { 65 | Add(item.Key, item.Value); 66 | } 67 | 68 | public void Clear() 69 | { 70 | _dict_cache.Clear(); 71 | Refresh(); 72 | } 73 | 74 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 75 | public void Refresh() 76 | { 77 | _currentLock.GetAndWaitLock(); 78 | SaveFastCache(); 79 | _currentLock.ReleaseLock(); 80 | } 81 | 82 | public bool Contains(KeyValuePair item) 83 | { 84 | 85 | if (TryGetValue(item.Key, out var result)) 86 | { 87 | 88 | return result.Equals(item.Value); 89 | 90 | } 91 | return false; 92 | 93 | } 94 | 95 | public bool ContainsKey(string key) 96 | { 97 | if (_currentLock.CanGetLock()) 98 | { 99 | return _fast_cache.TryGetValue(key, out var _); 100 | } 101 | return _dict_cache.ContainsKey(key); 102 | } 103 | 104 | public void CopyTo(KeyValuePair[] array, int arrayIndex) 105 | { 106 | for (int i = arrayIndex; i < array.Length; i+=1) 107 | { 108 | _dict_cache[array[i].Key] = array[i].Value; 109 | } 110 | Refresh(); 111 | } 112 | 113 | public IEnumerator> GetEnumerator() 114 | { 115 | return _dict_cache.GetEnumerator(); 116 | } 117 | 118 | public bool Remove(string key) 119 | { 120 | if (_dict_cache.TryRemove(key,out TValue _)) 121 | { 122 | Refresh(); 123 | return true; 124 | } 125 | return false; 126 | } 127 | 128 | public bool Remove(KeyValuePair item) 129 | { 130 | if (_dict_cache.TryRemove(item.Key, out TValue value)) 131 | { 132 | if (item.Value.Equals(value)) 133 | { 134 | Refresh(); 135 | return true; 136 | } 137 | } 138 | return false; 139 | } 140 | 141 | public bool TryGetValue(string key, out TValue value) 142 | { 143 | if (_currentLock.CanGetLock()) 144 | { 145 | return _fast_cache.TryGetValue(key, out value); 146 | } 147 | return _dict_cache.TryGetValue(key, out value); 148 | } 149 | 150 | IEnumerator IEnumerable.GetEnumerator() 151 | { 152 | return _dict_cache.GetEnumerator(); 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/DynamicDictionary/Api/FuzzyDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DynamicDictionary.Api 6 | { 7 | public class FuzzyDictionary : FastStringDictionary 8 | { 9 | public FuzzyDictionary(bool useDefault) : base(useDefault) 10 | { 11 | this.SaveFastCache = () => { this._fast_cache = this._dict_cache.FuzzyTree(use_default); }; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/DynamicDictionary/Api/PrecisionDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DynamicDictionary.Api 6 | { 7 | public class PrecisionDictionary : FastStringDictionary 8 | { 9 | public PrecisionDictionary(bool useDefault) : base(useDefault) 10 | { 11 | this.SaveFastCache = () => { this._fast_cache = this._dict_cache.PrecisioTree(use_default); }; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/DynamicDictionary/Api/Utils/CurrentLock.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using System.Threading; 3 | 4 | namespace DynamicDictionary.Api.Utils 5 | { 6 | public class CurrentLock 7 | { 8 | 9 | private int _lockCount = 0; 10 | 11 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 12 | public bool GetLock() 13 | { 14 | return Interlocked.CompareExchange(ref _lockCount, 1, 0) == 0; 15 | 16 | } 17 | 18 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 19 | public bool CanGetLock() 20 | { 21 | bool result = Interlocked.CompareExchange(ref _lockCount, 1, 0) == 0; 22 | if (result) 23 | { 24 | _lockCount = 0; 25 | } 26 | return result; 27 | } 28 | 29 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 30 | public void GetAndWaitLock() 31 | { 32 | while (Interlocked.CompareExchange(ref _lockCount, 1, 0) != 0) 33 | { 34 | Thread.Sleep(20); 35 | } 36 | } 37 | 38 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 39 | public void ReleaseLock() 40 | { 41 | _lockCount = 0; 42 | } 43 | 44 | } 45 | } 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/DynamicDictionary/Base/DynamicDictionaryBase.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | 4 | 5 | #if NET5_0 6 | [SkipLocalsInit] 7 | #endif 8 | public abstract class DynamicDictionaryBase 9 | { 10 | 11 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 12 | public abstract TValue GetValue(TKey key); 13 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 14 | public abstract bool TryGetValue(TKey key, out TValue value); 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public abstract void Change(TKey key, TValue value); 17 | 18 | 19 | public TValue this[TKey key] 20 | { 21 | 22 | get 23 | { 24 | 25 | return GetValue(key); 26 | 27 | } 28 | set 29 | { 30 | Change(key, value); 31 | } 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/DynamicDictionary/Builder/DynamicDictionaryBuilder.cs: -------------------------------------------------------------------------------- 1 | using Natasha.CSharp; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace DynamicDictionary 6 | { 7 | 8 | public abstract class DynamicDictionaryBuilder 9 | { 10 | 11 | private static readonly string _prefix = "_anonymous_"; 12 | public abstract string ScriptKeyAction(IDictionary dict, string paramName); 13 | 14 | public readonly DynamicDictionaryBase Instance; 15 | 16 | public DynamicDictionaryBuilder(IDictionary pairs, bool useDefault) 17 | { 18 | 19 | int count = 0; 20 | NClass nClass; 21 | #if NETCOREAPP3_1_OR_GREATER 22 | if (useDefault) 23 | { 24 | nClass = NClass.DefaultDomain(); 25 | } 26 | else 27 | { 28 | nClass = NClass.RandomDomain(); 29 | } 30 | nClass 31 | #else 32 | nClass = NClass.DefaultDomain() 33 | #endif 34 | 35 | .Access("public sealed") 36 | .InheritanceAppend>() 37 | .Unsafe(); 38 | 39 | #if NET5_0_OR_GREATER 40 | nClass.SkipInit(); 41 | #endif 42 | 43 | 44 | 45 | 46 | //构建快查字典 给BTF使用 47 | var getValueMethodScript = new Dictionary(); 48 | var tryGetValueMethodScript = new Dictionary(); 49 | var setValueMethodSciprt = new Dictionary(); 50 | foreach (var item in pairs) 51 | { 52 | count += 1; 53 | string field = _prefix + count; 54 | nClass.PrivateReadonlyField(field); 55 | 56 | getValueMethodScript[item.Key] = $"return {field};"; 57 | tryGetValueMethodScript[item.Key] = $"value = {field};return true;"; 58 | setValueMethodSciprt[item.Key] = $"{field.ToReadonlyScript()} = value;return;"; 59 | } 60 | 61 | //根据快查字典生成快查代码 62 | //value GetValue(key) 63 | nClass.Method(method => 64 | { 65 | method 66 | .Param("key") 67 | .Override() 68 | .Return() 69 | .Name("GetValue") 70 | .Public() 71 | .BodyAppend(ScriptKeyAction(getValueMethodScript, "key")) 72 | .BodyAppend("return default;"); 73 | }); 74 | 75 | //bool TryGetValue(key,out value) 76 | nClass.Method(method => 77 | { 78 | method 79 | .Param("key") 80 | .Param("value", "out ") 81 | .Override() 82 | .Return() 83 | .Name("TryGetValue") 84 | .Public() 85 | .BodyAppend(ScriptKeyAction(tryGetValueMethodScript, "key")) 86 | .BodyAppend("value=default; return false;"); 87 | }); 88 | 89 | //Change(key,value) 90 | nClass.Method(method => 91 | { 92 | method 93 | .Param("key") 94 | .Param("value") 95 | .Override() 96 | .Name("Change") 97 | .Public() 98 | .BodyAppend(ScriptKeyAction(setValueMethodSciprt, "key")) 99 | .BodyAppend("throw new Exception(\"Can't find key!\");"); 100 | }); 101 | 102 | 103 | var ProxyType = nClass.GetType(); 104 | 105 | Instance = nClass 106 | .DelegateHandler 107 | .Func>($"return new {ProxyType.GetDevelopName()}();")(); 108 | 109 | 110 | foreach (var item in pairs) 111 | { 112 | Instance.Change(item.Key, item.Value); 113 | } 114 | 115 | } 116 | 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/DynamicDictionary/Builder/DynamicSwitchBuilder.cs: -------------------------------------------------------------------------------- 1 | using Natasha.CSharp; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace DynamicDictionary 6 | { 7 | 8 | public abstract class DynamicSwitchBuilder 9 | { 10 | 11 | private static readonly string _prefix = "_anonymous_"; 12 | public abstract string ScriptKeyAction(IDictionary dict, string paramName, Func func = null); 13 | 14 | public readonly DynamicDictionaryBase Instance; 15 | 16 | public DynamicSwitchBuilder(IDictionary pairs,Func keyToCase = null, bool useDefault = false) 17 | { 18 | 19 | int count = 0; 20 | NClass nClass; 21 | #if NETCOREAPP3_1_OR_GREATER 22 | if (useDefault) 23 | { 24 | nClass = NClass.DefaultDomain(); 25 | } 26 | else 27 | { 28 | nClass = NClass.RandomDomain(); 29 | } 30 | nClass 31 | #else 32 | nClass = NClass.DefaultDomain() 33 | #endif 34 | 35 | .Access("public sealed") 36 | .InheritanceAppend>() 37 | .Unsafe(); 38 | 39 | #if NET5_0 40 | nClass.SkipInit(); 41 | #endif 42 | 43 | 44 | 45 | 46 | //构建快查字典 给BTF使用 47 | var getValueMethodScript = new Dictionary(); 48 | var tryGetValueMethodScript = new Dictionary(); 49 | var setValueMethodSciprt = new Dictionary(); 50 | foreach (var item in pairs) 51 | { 52 | count += 1; 53 | string field = _prefix + count; 54 | nClass.PrivateReadonlyField(field); 55 | 56 | getValueMethodScript[item.Key] = $"return {field};"; 57 | tryGetValueMethodScript[item.Key] = $"value = {field};return true;"; 58 | setValueMethodSciprt[item.Key] = $"{field.ToReadonlyScript()} = value;return;"; 59 | } 60 | 61 | //根据快查字典生成快查代码 62 | //value GetValue(key) 63 | nClass.Method(method => 64 | { 65 | method 66 | .Param("key") 67 | .Override() 68 | .Return() 69 | .Name("GetValue") 70 | .Public() 71 | .BodyAppend(ScriptKeyAction(getValueMethodScript, "key", keyToCase)) 72 | .BodyAppend("return default;"); 73 | }); 74 | 75 | //bool TryGetValue(key,out value) 76 | nClass.Method(method => 77 | { 78 | method 79 | .Param("key") 80 | .Param("value", "out ") 81 | .Override() 82 | .Return() 83 | .Name("TryGetValue") 84 | .Public() 85 | .BodyAppend(ScriptKeyAction(tryGetValueMethodScript, "key",keyToCase)) 86 | .BodyAppend("value=default; return false;"); 87 | }); 88 | 89 | //Change(key,value) 90 | nClass.Method(method => 91 | { 92 | method 93 | .Param("key") 94 | .Param("value") 95 | .Override() 96 | .Name("Change") 97 | .Public() 98 | .BodyAppend(ScriptKeyAction(setValueMethodSciprt, "key", keyToCase)) 99 | .BodyAppend("throw new Exception(\"Can't find key!\");"); 100 | }); 101 | 102 | 103 | var ProxyType = nClass.GetType(); 104 | 105 | Instance = nClass 106 | .DelegateHandler 107 | .Func>($"return new {ProxyType.GetDevelopName()}();")(); 108 | 109 | 110 | foreach (var item in pairs) 111 | { 112 | Instance.Change(item.Key, item.Value); 113 | } 114 | 115 | } 116 | 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/DynamicDictionary/DynamicDictionary.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;netcoreapp3.1;net5.0;net6.0; 5 | DynamicDictionary 6 | 将字典转换成动态查找树,以便快速查找。 7 | Night Moon Studio 8 | NMS.DynamicDictionary 9 | False 10 | 将字典转换成动态查找树,以便快速查找。 11 | 2.5.1 12 | true 13 | true 14 | https://github.com/night-moon-studio/DynamicDictionary/blob/master/LICENSE 15 | https://github.com/night-moon-studio/DynamicDictionary 16 | Roslyn;IL;Script;Dynamic;Dictionary;Fast;Cache; 17 | True 18 | NMSAzulX 19 | https://avatars2.githubusercontent.com/u/51699821 20 | NMSAzulX 21 | preview 22 | true 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/DynamicDictionary/Extension/ExtensionApi.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Collections.Generic; 3 | 4 | namespace System 5 | { 6 | 7 | public static class ExtensionApi 8 | { 9 | 10 | public static DynamicDictionaryBase HashTree(this IDictionary dict, bool useDefault = false) 11 | { 12 | return new HashCache(dict, useDefault).Instance; 13 | } 14 | public static DynamicDictionaryBase CustomerTree(this IDictionary dict, Func keyFunc,bool useDefault=false) 15 | { 16 | return new CustomerCache(dict, keyFunc,useDefault).Instance; 17 | } 18 | 19 | 20 | 21 | 22 | public static DynamicDictionaryBase FuzzyTree(this IDictionary dict, bool useDefault = false) 23 | { 24 | return new FuzzyCache(dict, useDefault).Instance; 25 | } 26 | 27 | 28 | 29 | 30 | public static DynamicDictionaryBase PrecisioTree(this IDictionary dict, bool useDefault = false) 31 | { 32 | return new PrecisionCache(dict, useDefault).Instance; 33 | } 34 | 35 | 36 | 37 | 38 | public static DynamicDictionaryBase HashTree(this Dictionary dict, bool useDefault = false) 39 | { 40 | return new HashCache(dict).Instance; 41 | } 42 | 43 | 44 | 45 | 46 | public static DynamicDictionaryBase FuzzyTree(this Dictionary dict, bool useDefault = false) 47 | { 48 | return new FuzzyCache(dict, useDefault).Instance; 49 | } 50 | 51 | 52 | 53 | 54 | public static DynamicDictionaryBase PrecisioTree(this Dictionary dict, bool useDefault = false) 55 | { 56 | return new PrecisionCache(dict, useDefault).Instance; 57 | } 58 | 59 | 60 | 61 | 62 | public static DynamicDictionaryBase HashTree(this ConcurrentDictionary dict, bool useDefault = false) 63 | { 64 | return new HashCache(dict, useDefault).Instance; 65 | } 66 | 67 | 68 | 69 | 70 | public static DynamicDictionaryBase FuzzyTree(this ConcurrentDictionary dict, bool useDefault = false) 71 | { 72 | return new FuzzyCache(dict, useDefault).Instance; 73 | } 74 | 75 | 76 | 77 | 78 | public static DynamicDictionaryBase PrecisioTree(this ConcurrentDictionary dict, bool useDefault = false) 79 | { 80 | return new PrecisionCache(dict, useDefault).Instance; 81 | } 82 | 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/DynamicDictionary/Implementation/CustomerCache.cs: -------------------------------------------------------------------------------- 1 | using BTFindTree; 2 | using DynamicDictionary; 3 | using System.Collections.Generic; 4 | 5 | namespace System 6 | { 7 | 8 | public class CustomerCache : DynamicSwitchBuilder 9 | { 10 | 11 | public CustomerCache(IDictionary pairs, Func keyToCase, bool useDefault = false) : base(pairs, keyToCase, useDefault) 12 | { 13 | 14 | 15 | } 16 | 17 | public override string ScriptKeyAction(IDictionary dict, string paramName, Func func = null) 18 | { 19 | return BTFTemplate.GetCustomerBTFScript(dict, paramName, func); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/DynamicDictionary/Implementation/FuzzyCache.cs: -------------------------------------------------------------------------------- 1 | using BTFindTree; 2 | using DynamicDictionary; 3 | using System.Collections.Generic; 4 | 5 | namespace System 6 | { 7 | 8 | public class FuzzyCache : DynamicDictionaryBuilder 9 | { 10 | 11 | public FuzzyCache(IDictionary pairs, bool useDefault = false) : base(pairs, useDefault) 12 | { 13 | 14 | 15 | } 16 | 17 | public override string ScriptKeyAction(IDictionary dict, string paramName) 18 | { 19 | return BTFTemplate.GetGroupFuzzyPointBTFScript(dict, paramName); 20 | } 21 | 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/DynamicDictionary/Implementation/HashCache.cs: -------------------------------------------------------------------------------- 1 | using BTFindTree; 2 | using DynamicDictionary; 3 | using System.Collections.Generic; 4 | 5 | namespace System 6 | { 7 | 8 | public class HashCache : DynamicDictionaryBuilder 9 | { 10 | 11 | public HashCache(IDictionary pairs,bool useDefault = false) : base(pairs,useDefault) 12 | { 13 | 14 | 15 | } 16 | 17 | public override string ScriptKeyAction(IDictionary dict, string paramName) 18 | { 19 | return BTFTemplate.GetHashBTFScript(dict, paramName); 20 | } 21 | 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/DynamicDictionary/Implementation/PrecisionCache.cs: -------------------------------------------------------------------------------- 1 | using BTFindTree; 2 | using DynamicDictionary; 3 | using System.Collections.Generic; 4 | 5 | namespace System 6 | { 7 | 8 | public class PrecisionCache : DynamicDictionaryBuilder 9 | { 10 | 11 | public PrecisionCache(IDictionary pairs, bool useDefault = false) : base(pairs, useDefault) 12 | { 13 | 14 | } 15 | 16 | public override string ScriptKeyAction(IDictionary dict, string paramName) 17 | { 18 | return BTFTemplate.GetGroupPrecisionPointBTFScript(dict, paramName); 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/readme.txt: -------------------------------------------------------------------------------- 1 | 在此文件夹下建立类库源码 -------------------------------------------------------------------------------- /test/BenchmarkProject/BenchmarkProject.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net5.0 6 | true 7 | 8 | 9 | 10 | x64 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /test/BenchmarkProject/BenchmarkTest.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using BenchmarkDotNet.Configs; 3 | using BenchmarkDotNet.Mathematics; 4 | using BenchmarkDotNet.Order; 5 | using ImTools; 6 | using System; 7 | using System.Collections.Concurrent; 8 | using System.Collections.Generic; 9 | using System.Collections.Immutable; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | 13 | namespace BenchmarkProject 14 | { 15 | 16 | [MemoryDiagnoser, MarkdownExporter, RPlotExporter] 17 | [MinColumn, MaxColumn, MeanColumn, MedianColumn] 18 | [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] 19 | [Orderer(SummaryOrderPolicy.FastestToSlowest)] 20 | [RankColumn(NumeralSystem.Arabic)] 21 | [CategoriesColumn] 22 | public class BenchmarkTest 23 | { 24 | public readonly TestModel model; 25 | public readonly DynamicDictionaryBase FuzzyHandler; 26 | public readonly DynamicDictionaryBase HashHandler; 27 | public readonly DynamicDictionaryBase PrecisionHandler; 28 | public readonly DynamicDictionaryBase HashCodePrecisionHandler; 29 | public readonly Dictionary DictHandler; 30 | public readonly ConcurrentDictionary ConDictHandler; 31 | public readonly ImmutableDictionary ReadonlyDictHandler; 32 | public readonly ImMap _imMap; 33 | public readonly ImHashMap _imHashMap; 34 | public BenchmarkTest() 35 | { 36 | NatashaInitializer.Preheating(); 37 | model = new TestModel(); 38 | _imMap = ImMap.Empty; 39 | _imHashMap = ImHashMap.Empty; 40 | FuzzyHandler = model.Model1.FuzzyTree(); 41 | HashHandler = model.Model1.HashTree(); 42 | PrecisionHandler = model.Model1.PrecisioTree(); 43 | DictHandler = model.Model1; 44 | Dictionary hashDict = new(); 45 | foreach (var item in model.Model1) 46 | { 47 | _imHashMap = _imHashMap.AddOrUpdate(item.Key, item.Value); 48 | _imMap = _imMap.AddOrUpdate(Int32.Parse(item.Key), item.Value); 49 | hashDict[Int32.Parse(item.Key)] = item.Value; 50 | } 51 | HashCodePrecisionHandler = hashDict.CustomerTree(item=>item.ToString()); 52 | ConDictHandler = new ConcurrentDictionary(model.Model1); 53 | ReadonlyDictHandler = ImmutableDictionary.CreateRange(DictHandler); 54 | } 55 | 56 | //[Benchmark(Description = "哈希查找树")] 57 | //public void TestHash() 58 | //{ 59 | // var result = HashHandler["11"]; 60 | // result = HashHandler["2"]; 61 | //} 62 | 63 | //[Benchmark(Description = "模糊查找树")] 64 | //public void TestFuzzy() 65 | //{ 66 | // var result = FuzzyHandler["11"]; 67 | // result = FuzzyHandler["2"]; 68 | //} 69 | 70 | [Benchmark(Description = "精确查找树")] 71 | public void TestPrecision() 72 | { 73 | var result = PrecisionHandler["11"]; 74 | result = PrecisionHandler["2"]; 75 | } 76 | 77 | [Benchmark(Description = "普通字典")] 78 | public void TestDict() 79 | { 80 | var result = DictHandler["11"]; 81 | result = DictHandler["2"]; 82 | } 83 | 84 | [Benchmark(Description = "CustomerSwitch")] 85 | public void TestCustomer() 86 | { 87 | var result = HashCodePrecisionHandler[11]; 88 | result = HashCodePrecisionHandler[2]; 89 | } 90 | 91 | 92 | [Benchmark(Description = "imMap")] 93 | public void TestImp() 94 | { 95 | _imMap.TryFind(11, out var result); 96 | _imMap.TryFind(2, out result); 97 | } 98 | [Benchmark(Description = "imHashMap")] 99 | public void TestHashImp() 100 | { 101 | _imHashMap.TryFind("11", out var result); 102 | _imHashMap.TryFind("2", out result); 103 | } 104 | 105 | //[Benchmark(Description = "并发字典")] 106 | //public void TestConDict() 107 | //{ 108 | // var result = ConDictHandler["11"]; 109 | // result = ConDictHandler["2"]; 110 | //} 111 | 112 | //[Benchmark(Description = "只读字典")] 113 | //public void TestImmDict() 114 | //{ 115 | // var result = ReadonlyDictHandler["11"]; 116 | // result = ReadonlyDictHandler["2"]; 117 | //} 118 | 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /test/BenchmarkProject/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | using Natasha; 3 | using System; 4 | 5 | namespace BenchmarkProject 6 | { 7 | class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | NatashaInitializer.Preheating(); 12 | BenchmarkRunner.Run(); 13 | Console.ReadKey(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/BenchmarkProject/TestModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace BenchmarkProject 6 | { 7 | public class TestModel 8 | { 9 | public Dictionary Model1; 10 | 11 | 12 | public TestModel() 13 | { 14 | Model1 = new Dictionary(); 15 | for (int i = 0; i < 20; i++) 16 | { 17 | string value = i.ToString(); 18 | Model1[value] = value; 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/UTProject/FuzzyTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UTProject.Model; 4 | using Xunit; 5 | 6 | namespace UTProject 7 | { 8 | 9 | [Trait("快速查找", "Fuzzy")] 10 | public class FuzzyTest: NatashaIni 11 | { 12 | TestModel model; 13 | DynamicDictionaryBase Handler1; 14 | 15 | public FuzzyTest() 16 | { 17 | 18 | model = new TestModel(); 19 | Handler1 = model.Model1.FuzzyTree(); 20 | } 21 | 22 | [Fact(DisplayName = "模糊查找测试1")] 23 | public void TestModel1() 24 | { 25 | foreach (var item in model.Model1) 26 | { 27 | Assert.Equal(item.Value, Handler1[item.Key]); 28 | } 29 | } 30 | 31 | [Fact(DisplayName = "空集合测试1")] 32 | public unsafe void TestModel4() 33 | { 34 | var model2 = new TestModel(); 35 | model2.Model1.Clear(); 36 | var tempHandler = model2.Model1.FuzzyTree(); 37 | Assert.Equal(default, tempHandler["1"]); 38 | //Assert.Equal(default, tempHandler.GetKeys("1")); 39 | Assert.Equal(default, tempHandler.GetValue("1")); 40 | } 41 | 42 | 43 | 44 | [Fact(DisplayName = "模糊查找树反向查找测试")] 45 | public unsafe void TestModel5() 46 | { 47 | 48 | Dictionary dict = new Dictionary(); 49 | dict["a"] = "a"; 50 | dict["b"] = "a"; 51 | dict["c"] = "a"; 52 | dict["d"] = "e"; 53 | 54 | 55 | var handler = dict.FuzzyTree(); 56 | foreach (var item in dict) 57 | { 58 | Assert.Equal(item.Value, handler[item.Key]); 59 | } 60 | handler["a"] = "b"; 61 | Assert.Equal("b", handler["a"]); 62 | 63 | //var hashSet = new HashSet(handler.GetKeys("a")); 64 | //Assert.Equal(3, hashSet.Count); 65 | //Assert.Contains("a", hashSet); 66 | //Assert.Contains("b", hashSet); 67 | //Assert.Contains("c", hashSet); 68 | 69 | } 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /test/UTProject/HashTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using UTProject.Model; 5 | using Xunit; 6 | 7 | namespace UTProject 8 | { 9 | 10 | [Trait("快速查找", "Hash")] 11 | public class HashTest : NatashaIni 12 | { 13 | TestModel model; 14 | DynamicDictionaryBase HashHandler1; 15 | DynamicDictionaryBase HashHandler2; 16 | DynamicDictionaryBase HashHandler3; 17 | //HashCache 18 | 19 | public HashTest() 20 | { 21 | model = new TestModel(); 22 | HashHandler1 = model.Model1.HashTree(); 23 | HashHandler2 = model.Model2.HashTree(); 24 | HashHandler3 = model.Model3.HashTree(); 25 | } 26 | 27 | [Fact(DisplayName = "Hash查找测试1")] 28 | public void TestModel1() 29 | { 30 | foreach (var item in model.Model1) 31 | { 32 | Assert.Equal(item.Value, HashHandler1[item.Key]); 33 | } 34 | } 35 | [Fact(DisplayName = "Hash查找测试2")] 36 | public void TestModel2() 37 | { 38 | foreach (var item in model.Model2) 39 | { 40 | Assert.Equal(item.Value, HashHandler2[item.Key]); 41 | } 42 | } 43 | [Fact(DisplayName = "Hash查找测试3")] 44 | public void TestModel3() 45 | { 46 | foreach (var item in model.Model3) 47 | { 48 | Assert.Equal(item.Value, HashHandler3[item.Key]); 49 | } 50 | } 51 | [Fact(DisplayName = "Hash反向查找测试")] 52 | public unsafe void TestModel5() 53 | { 54 | 55 | Dictionary dict = new Dictionary(); 56 | dict["a"] = "a"; 57 | dict["b"] = "a"; 58 | dict["c"] = "a"; 59 | dict["d"] = "e"; 60 | var handler = dict.HashTree(); 61 | foreach (var item in dict) 62 | { 63 | Assert.Equal(item.Value, handler[item.Key]); 64 | } 65 | 66 | //var hashSet = new HashSet(handler.GetKeys("a")); 67 | //Assert.Equal(3, hashSet.Count); 68 | //Assert.Contains("a", hashSet); 69 | //Assert.Contains("b", hashSet); 70 | //Assert.Contains("c", hashSet); 71 | 72 | } 73 | 74 | [Fact(DisplayName = "空集合测试1")] 75 | public unsafe void TestModel4() 76 | { 77 | 78 | var model2 = new TestModel(); 79 | model2.Model1.Clear(); 80 | var tempHandler = model2.Model1.HashTree(); 81 | Assert.Equal(default, tempHandler["1"]); 82 | //Assert.Equal(default, tempHandler.GetKeys("1")); 83 | Assert.Equal(default, tempHandler.GetValue("1")); 84 | 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /test/UTProject/Model/BuilderModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace UTProject.Model 6 | { 7 | public static class BuilderModel 8 | { 9 | public static Func Creator(string arg) 10 | { 11 | return null; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/UTProject/Model/OperatorModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace UTProject.Model 6 | { 7 | public static class OperatorModel 8 | { 9 | public static Func Creator; 10 | public static int Flag; 11 | public static Func Error; 12 | 13 | static OperatorModel() 14 | { 15 | Creator = item => default; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/UTProject/Model/TestModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace UTProject.Model 6 | { 7 | public class TestModel 8 | { 9 | 10 | public Dictionary Model1; 11 | public Dictionary Model2; 12 | public Dictionary Model3; 13 | 14 | 15 | public TestModel() 16 | { 17 | Model1 = new Dictionary(); 18 | Model2 = new Dictionary(); 19 | Model3 = new Dictionary(); 20 | for (int i = 0; i < 100; i++) 21 | { 22 | string value = i.ToString(); 23 | Model1[value] = value; 24 | A model = new A(); 25 | Model2[model] = i; 26 | Model3[i] = model; 27 | } 28 | } 29 | } 30 | 31 | public class A { } 32 | } 33 | -------------------------------------------------------------------------------- /test/UTProject/Model/TestStaticModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace UTProject.Model 4 | { 5 | public class TestStaticModel 6 | { 7 | public Dictionary Model1; 8 | public Dictionary Model2; 9 | public TestStaticModel() 10 | { 11 | Model1 = new Dictionary(); 12 | Model2 = new Dictionary(); 13 | for (int i = 0; i < 10; i++) 14 | { 15 | string value = i.ToString(); 16 | Model1[value] = value; 17 | A model = new A(); 18 | Model2[model] = value; 19 | } 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /test/UTProject/NatashaIni.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace UTProject 6 | { 7 | public class NatashaIni 8 | { 9 | static NatashaIni() 10 | { 11 | NatashaInitializer.Preheating(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/UTProject/PrecisionTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UTProject.Model; 4 | using Xunit; 5 | 6 | namespace UTProject 7 | { 8 | 9 | [Trait("快速查找", "Precision")] 10 | public class PrecisionTest : NatashaIni 11 | { 12 | TestModel model; 13 | DynamicDictionaryBase Handler1; 14 | DynamicDictionaryBase Handler2; 15 | public PrecisionTest() 16 | { 17 | model = new TestModel(); 18 | Handler2 = new Dictionary() 19 | { 20 | { "111891234","1" }, 21 | { "212895678","2" }, 22 | { "313896789","3" } 23 | 24 | }.PrecisioTree(); 25 | Handler1 = model.Model1.PrecisioTree(); 26 | } 27 | 28 | [Fact(DisplayName = "精确查找测试4")] 29 | public void TestModel4() 30 | { 31 | Assert.Equal(default, Handler2["413891234"]); 32 | } 33 | 34 | [Fact(DisplayName = "精确查找测试1")] 35 | public void TestModel1() 36 | { 37 | foreach (var item in model.Model1) 38 | { 39 | Assert.Equal(item.Value, Handler1[item.Key]); 40 | } 41 | } 42 | 43 | [Fact(DisplayName = "空集合测试1")] 44 | public unsafe void TestModel2() 45 | { 46 | var model2= new TestModel(); 47 | model2.Model1.Clear(); 48 | var tempHandler = model2.Model1.PrecisioTree(); 49 | Assert.Equal(default, tempHandler["1"]); 50 | //Assert.Equal(default, tempHandler.GetKeys("1")); 51 | Assert.Equal(default, tempHandler.GetValue("1")); 52 | } 53 | 54 | [Fact(DisplayName = "精确查找树反向查找测试")] 55 | public unsafe void TestModel5() 56 | { 57 | 58 | Dictionary dict = new Dictionary(); 59 | dict["a"] = "a"; 60 | dict["b"] = "a"; 61 | dict["c"] = "a"; 62 | dict["d"] = "e"; 63 | 64 | 65 | var handler = dict.PrecisioTree(); 66 | foreach (var item in dict) 67 | { 68 | Assert.Equal(item.Value, handler[item.Key]); 69 | } 70 | 71 | 72 | //var hashSet = new HashSet(handler.GetKeys("a")); 73 | //Assert.Equal(3, hashSet.Count); 74 | //Assert.Contains("a", hashSet); 75 | //Assert.Contains("b", hashSet); 76 | //Assert.Contains("c", hashSet); 77 | 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /test/UTProject/TextFile1.txt: -------------------------------------------------------------------------------- 1 | (9389766,9395148,9390780,9394073,9394076,9395151,9394080,9394086,9394088,9394091) -------------------------------------------------------------------------------- /test/UTProject/UTProject.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1;net5.0; 5 | false 6 | true 7 | 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | 18 | all 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | --------------------------------------------------------------------------------