├── .gitattributes ├── .gitignore ├── FriendlyCSharp.Databases ├── BTreeN │ ├── FcsBTreeN.cs │ ├── FcsDuplValueFastBTreeN.cs │ ├── FcsFastBTreeN.cs │ ├── FcsFastLockBTreeN.cs │ ├── FcsKeyFastBTreeN.cs │ └── FcsLockBTreeN.cs ├── FriendlyCSharp.Databases.csproj ├── Properties │ └── PublishProfiles │ │ └── FolderProfile.pubxml └── Storage │ └── FcsInmemStream.cs ├── FriendlyCSharp.Git.sln ├── LICENSE ├── README.md └── Samples ├── BtnEnumerator.Multi.sample ├── BtnEnumerator.Multi.sample.csproj └── Program.cs ├── DuplicityKeys.Multi.sample ├── DuplicityKeys.Multi.sample.csproj └── Program.cs ├── FcsFastBTreeN.Multi.benchmark ├── FcsFastBTreeN.Multi.benchmark.csproj └── Program.cs ├── FcsInmemStream.Multi.sample ├── FcsInmemStream.Multi.sample.csproj └── Program.cs └── MultipleKeys.Multi.sample ├── MultipleKeys.Multi.sample.csproj └── Program.cs /.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 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /FriendlyCSharp.Databases/BTreeN/FcsFastBTreeN.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the KUBDAT® under one or more agreements. 2 | // The KUBDAT® licenses this file to you under the Apache-2.0 license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections; 7 | using System.Collections.Generic; 8 | 9 | namespace FriendlyCSharp.Databases 10 | { 11 | public partial class FcsFastBTreeN : FcsBTreeN, IEnumerable> 12 | where TKey : IComparable 13 | { 14 | ////////////////////////// 15 | public FcsFastBTreeN(uint allocIdxFast) : base(_btnDefaultBTreeN, allocIdxFast, null) 16 | { 17 | } 18 | ////////////////////////// 19 | protected FcsFastBTreeN(uint allocIdxFast, object objCmp) : base(_btnDefaultBTreeN, allocIdxFast, objCmp) 20 | { 21 | } 22 | ////////////////////////// 23 | public FcsFastBTreeN(int btnBTreeN, uint allocIdxFast) : base(btnBTreeN, allocIdxFast, null) 24 | { 25 | } 26 | ////////////////////////// 27 | protected FcsFastBTreeN(int btnBTreeN, uint allocIdxFast, object objCmp) : base(btnBTreeN, allocIdxFast, objCmp) 28 | { 29 | } 30 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 31 | ///////////////////////////////////////////// BtnFind ////////////////////////////////////////////////////// 32 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 33 | public virtual bool? BtnFastFind(TKey key, out TValue value, uint idxFast) 34 | { 35 | return _BtnFind(ref key, out value, _btnRoot, out _btnKVFast[idxFast]); 36 | } 37 | ////////////////////////// 38 | protected virtual bool? BtnFastFind(TKey key, out TValue value, out KeyValueFast btnFast) 39 | { 40 | return _BtnFind(ref key, out value, _btnRoot, out btnFast); 41 | } 42 | ////////////////////////// 43 | // Specify if necessary, the symbol of: Project -> Properties -> Build -> Conditional Compilation Symbols 44 | #if KEY_VALUE_PAIR 45 | public virtual KeyValuePair? BtnFastFind(TKey key, uint idxFast) 46 | { 47 | if (_BtnFind(ref key, out TValue valueOut, _btnRoot, out _btnKVFast[idxFast]) == true) 48 | return new KeyValuePair(key, valueOut); 49 | else 50 | return null; 51 | } 52 | #else 53 | public virtual (TKey key, TValue value)? BtnFastFind(TKey key, uint idxFast) 54 | { 55 | if (_BtnFind(ref key, out TValue valueOut, _btnRoot, out _btnKVFast[idxFast]) == true) 56 | return (key: key, value: valueOut); 57 | else 58 | return null; 59 | } 60 | #endif 61 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 62 | ///////////////////////////////////////////// BtnFirst ////////////////////////////////////////////////////// 63 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 64 | public virtual bool? BtnFastFirst(out TKey key, out TValue value, uint idxFast) 65 | { 66 | return _BtnFirst(out key, out value, out _btnKVFast[idxFast]); 67 | } 68 | ////////////////////////// 69 | protected virtual bool? BtnFastFirst(out TKey key, out TValue value, out KeyValueFast btnFast) 70 | { 71 | return _BtnFirst(out key, out value, out btnFast); 72 | } 73 | ////////////////////////// 74 | #if KEY_VALUE_PAIR 75 | public virtual KeyValuePair? BtnFastFirst(uint idxFast) 76 | { 77 | return _BtnFirst(out _btnKVFast[idxFast]); 78 | } 79 | #else 80 | public virtual (TKey key, TValue value)? BtnFastFirst(uint idxFast) 81 | { 82 | return _BtnFirst(out _btnKVFast[idxFast]); 83 | } 84 | #endif 85 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 86 | ///////////////////////////////////////////// BtnLast ////////////////////////////////////////////////////// 87 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 88 | public virtual bool? BtnFastLast(out TKey key, out TValue value, uint idxFast) 89 | { 90 | return _BtnLast(out key, out value, out _btnKVFast[idxFast]); 91 | } 92 | ////////////////////////// 93 | protected virtual bool? BtnFastLast(out TKey key, out TValue value, out KeyValueFast btnFast) 94 | { 95 | return _BtnLast(out key, out value, out btnFast); 96 | } 97 | ////////////////////////// 98 | #if KEY_VALUE_PAIR 99 | public virtual KeyValuePair? BtnFastLast(uint idxFast) 100 | { 101 | return _BtnLast(out _btnKVFast[idxFast]); 102 | } 103 | #else 104 | public virtual (TKey key, TValue value)? BtnFastLast(uint idxFast) 105 | { 106 | return _BtnLast(out _btnKVFast[idxFast]); 107 | } 108 | #endif 109 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 110 | ///////////////////////////////////////////// BtnNext ////////////////////////////////////////////////////// 111 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 112 | public virtual bool? BtnFastNext(ref TKey key, out TValue value, uint idxFast) 113 | { 114 | int middle = _btnKVFast[idxFast].fastMiddle; 115 | KeyValueFast btnFast = _btnKVFast[idxFast]; 116 | if ( (btnFast.version == BtnVersion) && (btnFast.fastPage != null) && (middle > 0) && 117 | (middle < btnFast.fastPage.iDataCount) && (BtnCompares(key, btnFast.fastPage.aData[middle].key, _objCompares) == 0)) 118 | { 119 | middle = ++_btnKVFast[idxFast].fastMiddle; 120 | key = btnFast.fastPage.aData[middle].key; 121 | value = btnFast.fastPage.aData[middle].value; 122 | return true; 123 | } 124 | else 125 | { 126 | bool bNext = false; 127 | return _BtnNext(ref key, out value, _btnRoot, ref bNext, out _btnKVFast[idxFast]); 128 | } 129 | } 130 | ////////////////////////// 131 | protected virtual bool? BtnFastNext(ref TKey key, out TValue value, ref KeyValueFast btnFast) 132 | { 133 | int middle = btnFast.fastMiddle; 134 | if ( (btnFast.version == BtnVersion) && (btnFast.fastPage != null) && (middle > 0) && 135 | (middle < btnFast.fastPage.iDataCount) && (BtnCompares(key, btnFast.fastPage.aData[middle].key, _objCompares) == 0)) 136 | { 137 | middle = ++btnFast.fastMiddle; 138 | key = btnFast.fastPage.aData[middle].key; 139 | value = btnFast.fastPage.aData[middle].value; 140 | return true; 141 | } 142 | else 143 | { 144 | bool bNext = false; 145 | return _BtnNext(ref key, out value, _btnRoot, ref bNext, out btnFast); 146 | } 147 | } 148 | ////////////////////////// 149 | #if KEY_VALUE_PAIR 150 | public virtual KeyValuePair? BtnFastNext(TKey key, uint idxFast) 151 | { 152 | int middle = _btnKVFast[idxFast].fastMiddle; 153 | KeyValueFast btnFast = _btnKVFast[idxFast]; 154 | if ( (btnFast.version == BtnVersion) && (btnFast.fastPage != null) && (middle > 0) && 155 | (middle < btnFast.fastPage.iDataCount) && (BtnCompares(key, btnFast.fastPage.aData[middle].key, _objCompares) == 0)) 156 | { 157 | middle = ++_btnKVFast[idxFast].fastMiddle; 158 | return new KeyValuePair(btnFast.fastPage.aData[middle].key, btnFast.fastPage.aData[middle].value); 159 | } 160 | else 161 | { 162 | bool bNext = false; 163 | if (_BtnNext(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[idxFast]) == true) 164 | return new KeyValuePair(key, valueOut); 165 | else 166 | return null; 167 | } 168 | } 169 | #else 170 | public virtual (TKey key, TValue value)? BtnFastNext(TKey key, uint idxFast) 171 | { 172 | int middle = _btnKVFast[idxFast].fastMiddle; 173 | BtnFastKeyValue btnFast = _btnKVFast[idxFast]; 174 | if ( (btnFast.version == BtnVersion) && (btnFast.fastPage != null) && (middle > 0) && 175 | (middle < btnFast.fastPage.iDataCount) && (BtnCompares(key, btnFast.fastPage.aData[middle].key, _objCompares) == 0)) 176 | { 177 | middle = ++_btnKVFast[idxFast].fastMiddle; 178 | return (key: btnFast.fastPage.aData[middle].key, value: btnFast.fastPage.aData[middle].value); 179 | } 180 | else 181 | { 182 | bool bNext = false; 183 | if (_BtnNext(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[idxFast]) == true) 184 | return (key: key, value: valueOut); 185 | else 186 | return null; 187 | } 188 | } 189 | #endif 190 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 191 | ///////////////////////////////////////////// BtnPrev ////////////////////////////////////////////////////// 192 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 193 | public virtual bool? BtnFastPrev(ref TKey key, out TValue value, uint idxFast) 194 | { 195 | int middle = _btnKVFast[idxFast].fastMiddle; 196 | KeyValueFast btnFast = _btnKVFast[idxFast]; 197 | if ( (btnFast.version == BtnVersion) && (btnFast.fastPage != null) && (middle > 1) && 198 | (middle <= btnFast.fastPage.iDataCount) && (BtnCompares(key, btnFast.fastPage.aData[middle].key, _objCompares) == 0) ) 199 | { 200 | middle = --_btnKVFast[idxFast].fastMiddle; 201 | key = btnFast.fastPage.aData[middle].key; 202 | value = btnFast.fastPage.aData[middle].value; 203 | return true; 204 | } 205 | else 206 | { 207 | bool bNext = false; 208 | return _BtnPrev(ref key, out value, _btnRoot, ref bNext, out _btnKVFast[idxFast]); 209 | } 210 | } 211 | ////////////////////////// 212 | protected virtual bool? BtnFastPrev(ref TKey key, out TValue value, ref KeyValueFast btnFast) 213 | { 214 | int middle = btnFast.fastMiddle; 215 | if ( (btnFast.version == BtnVersion) && (btnFast.fastPage != null) && (middle > 1) && 216 | (middle <= btnFast.fastPage.iDataCount) && (BtnCompares(key, btnFast.fastPage.aData[middle].key, _objCompares) == 0)) 217 | { 218 | middle = --btnFast.fastMiddle; 219 | key = btnFast.fastPage.aData[middle].key; 220 | value = btnFast.fastPage.aData[middle].value; 221 | return true; 222 | } 223 | else 224 | { 225 | bool bNext = false; 226 | return _BtnPrev(ref key, out value, _btnRoot, ref bNext, out btnFast); 227 | } 228 | } 229 | ////////////////////////// 230 | #if KEY_VALUE_PAIR 231 | public virtual KeyValuePair? BtnFastPrev(TKey key, uint idxFast) 232 | { 233 | int middle = _btnKVFast[idxFast].fastMiddle; 234 | KeyValueFast btnFast = _btnKVFast[idxFast]; 235 | if ( (btnFast.version == BtnVersion) && (btnFast.fastPage != null) && (middle > 1) && 236 | (middle <= btnFast.fastPage.iDataCount) && (BtnCompares(key, btnFast.fastPage.aData[middle].key, _objCompares) == 0)) 237 | { 238 | middle = --_btnKVFast[idxFast].fastMiddle; 239 | return new KeyValuePair(btnFast.fastPage.aData[middle].key, btnFast.fastPage.aData[middle].value); 240 | } 241 | else 242 | { 243 | bool bNext = false; 244 | if (_BtnPrev(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[idxFast]) == true) 245 | return new KeyValuePair(key, valueOut); 246 | else 247 | return null; 248 | } 249 | } 250 | #else 251 | public virtual (TKey key, TValue value)? BtnFastPrev(TKey key, uint idxFast) 252 | { 253 | int middle = _btnKVFast[idxFast].fastMiddle; 254 | BtnFastKeyValue btnFast = _btnKVFast[idxFast]; 255 | if ( (btnFast.version == BtnVersion) && (btnFast.fastPage != null) && (middle > 1) && 256 | (middle <= btnFast.fastPage.iDataCount) && (BtnCompares(key, btnFast.fastPage.aData[middle].key, _objCompares) == 0)) 257 | { 258 | middle = --_btnKVFast[idxFast].fastMiddle; 259 | return (key: btnFast.fastPage.aData[middle].key, value: btnFast.fastPage.aData[middle].value); 260 | } 261 | else 262 | { 263 | bool bNext = false; 264 | if (_BtnNext(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[idxFast]) == true) 265 | return (key: key, value: valueOut); 266 | else 267 | return null; 268 | } 269 | } 270 | #endif 271 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 272 | ///////////////////////////////////////////// BtnSearch ////////////////////////////////////////////////////// 273 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 274 | public virtual bool? BtnFastSearch(ref TKey key, out TValue value, uint idxFast) 275 | { 276 | bool bNext = false; 277 | return _BtnSearch(ref key, out value, _btnRoot, ref bNext, out _btnKVFast[idxFast]); 278 | } 279 | ////////////////////////// 280 | protected virtual bool? BtnFastSearch(ref TKey key, out TValue value, out KeyValueFast btnFast) 281 | { 282 | bool bNext = false; 283 | return _BtnSearch(ref key, out value, _btnRoot, ref bNext, out btnFast); 284 | } 285 | ////////////////////////// 286 | #if KEY_VALUE_PAIR 287 | public virtual KeyValuePair? BtnFastSearch(TKey key, uint idxFast) 288 | { 289 | bool bNext = false; 290 | if (_BtnSearch(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[idxFast]) == true) 291 | return new KeyValuePair(key, valueOut); 292 | else 293 | return null; 294 | } 295 | #else 296 | public virtual (TKey key, TValue value)? BtnFastSearch(TKey key, uint idxFast) 297 | { 298 | bool bNext = false; 299 | if (_BtnSearch(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[idxFast]) == true) 300 | return (key: key, value: valueOut); 301 | else 302 | return null; 303 | } 304 | #endif 305 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 306 | ///////////////////////////////////////////// BtnSearchPrev ////////////////////////////////////////////////////// 307 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 308 | public virtual bool? BtnFastSearchPrev(ref TKey key, out TValue value, uint idxFast) 309 | { 310 | bool bNext = false; 311 | return _BtnSearchPrev(ref key, out value, _btnRoot, ref bNext, out _btnKVFast[idxFast]); 312 | } 313 | ////////////////////////// 314 | protected virtual bool? BtnFastSearchPrev(ref TKey key, out TValue value, out KeyValueFast btnFast) 315 | { 316 | bool bNext = false; 317 | return _BtnSearchPrev(ref key, out value, _btnRoot, ref bNext, out btnFast); 318 | } 319 | ////////////////////////// 320 | #if KEY_VALUE_PAIR 321 | public virtual KeyValuePair? BtnFastSearchPrev(TKey key, uint idxFast) 322 | { 323 | bool bNext = false; 324 | if (_BtnSearchPrev(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[idxFast]) == true) 325 | return new KeyValuePair(key, valueOut); 326 | else 327 | return null; 328 | } 329 | #else 330 | public virtual (TKey key, TValue value)? BtnFastSearchPrev(TKey key, uint idxFast) 331 | { 332 | bool bNext = false; 333 | if (_BtnSearchPrev(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[idxFast]) == true) 334 | return (key: key, value: valueOut); 335 | else 336 | return null; 337 | } 338 | #endif 339 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 340 | ///////////////////////////////////////////// IEnumerator ////////////////////////////////////////////////////// 341 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 342 | public FcsFastBTreeN.BtnEnumeratorFast GetEnumeratorFastEx(bool reverse) 343 | { 344 | return new BtnEnumeratorFast(this, default(TKey), default(TKey), reverse, -2); 345 | } 346 | ////////////////////////// 347 | public FcsFastBTreeN.BtnEnumeratorFast GetEnumeratorFastEx(bool reverse, int maxCount) 348 | { 349 | return new BtnEnumeratorFast(this, default(TKey), default(TKey), reverse, maxCount); 350 | } 351 | ////////////////////////// 352 | public FcsFastBTreeN.BtnEnumeratorFast GetEnumeratorFastEx(TKey keyLo, TKey keyHi, bool reverse) 353 | { 354 | return new BtnEnumeratorFast(this, keyLo, keyHi, reverse, -3); 355 | } 356 | ////////////////////////// 357 | public FcsFastBTreeN.BtnEnumeratorFast GetEnumeratorFastEx(TKey keyLo, TKey keyHi, bool reverse, int maxCount) 358 | { 359 | return new BtnEnumeratorFast(this, keyLo, keyHi, reverse, maxCount); 360 | } 361 | ////////////////////////// 362 | public new IEnumerator> GetEnumerator() 363 | { 364 | return new BtnEnumeratorFast(this, default(TKey), default(TKey), false, -1); 365 | } 366 | ////////////////////////// 367 | public class BtnEnumeratorFast : IEnumerator> 368 | { 369 | // constructor 370 | private FcsFastBTreeN _btn = null; 371 | private TKey _keyLo; 372 | private TKey _keyHi; 373 | private int _maxCount; 374 | private bool _reverse; 375 | // locals 376 | private bool _bOK; 377 | private TKey _key; 378 | private TValue _value; 379 | private int _count; 380 | private KeyValueFast _btnFast; 381 | ////////////////////////// 382 | public BtnEnumeratorFast(FcsFastBTreeN btn, TKey keyLo, TKey keyHi, bool reverse, int maxCount) 383 | { 384 | _btn = btn ?? throw new NullReferenceException(); 385 | _keyLo = keyLo; 386 | _keyHi = keyHi; 387 | _maxCount = maxCount; 388 | _reverse = reverse; 389 | Reset(); 390 | } 391 | ////////////////////////// 392 | public bool MoveNext() 393 | { 394 | if ((_count == 0) || (!_bOK)) 395 | return false; 396 | else if (_count > 0) 397 | _count--; 398 | 399 | if (_btnFast.version == int.MinValue) 400 | { 401 | _btnFast = default(KeyValueFast); 402 | if ((_keyLo.Equals(default(TKey))) && (!_reverse)) 403 | _bOK = (_btn.BtnFastFirst(out _key, out _value, out _btnFast) != null); 404 | else if ((_keyHi.Equals(default(TKey))) && (_reverse)) 405 | _bOK = (_btn.BtnFastLast(out _key, out _value, out _btnFast) != null); 406 | else 407 | { 408 | if (_reverse) 409 | { 410 | _key = _keyHi; 411 | _bOK = (_btn.BtnFastSearchPrev(ref _key, out _value, out _btnFast)!=null); 412 | if ((!_keyLo.Equals(default(TKey))) && (_bOK)) 413 | _bOK = (_key.CompareTo(_keyLo) >= 0); 414 | } 415 | else 416 | { 417 | _key = _keyLo; 418 | _bOK = (_btn.BtnFastSearch(ref _key, out _value, out _btnFast) != null); 419 | if ((!_keyHi.Equals(default(TKey))) && (_bOK)) 420 | _bOK = (_key.CompareTo(_keyHi) <= 0); 421 | } 422 | } 423 | } 424 | else 425 | { 426 | if (_reverse) 427 | { 428 | _bOK = (_btn.BtnFastPrev(ref _key, out _value, ref _btnFast) != null); 429 | if ((!_keyLo.Equals(default(TKey))) && (_bOK)) 430 | _bOK = (_key.CompareTo(_keyLo) >= 0); 431 | } 432 | else 433 | { 434 | _bOK = (_btn.BtnFastNext(ref _key, out _value, ref _btnFast) != null); 435 | if ((!_keyHi.Equals(default(TKey))) && (_bOK)) 436 | _bOK = (_key.CompareTo(_keyHi) <= 0); 437 | } 438 | } 439 | return _bOK; 440 | } 441 | ////////////////////////// 442 | public KeyValuePair Current 443 | { 444 | get 445 | { 446 | if (!_bOK) 447 | return new KeyValuePair(default(TKey), default(TValue)); 448 | return new KeyValuePair(_key, _value); 449 | } 450 | } 451 | ////////////////////////// 452 | object IEnumerator.Current 453 | { 454 | get 455 | { 456 | if (!_bOK) 457 | return new KeyValuePair(default(TKey), default(TValue)); 458 | return new KeyValuePair(_key, _value); 459 | } 460 | } 461 | ////////////////////////// 462 | public void Dispose() { _btn = null; _btnFast.Dispose(); } 463 | ////////////////////////// 464 | public void Reset() 465 | { 466 | _count = _maxCount; 467 | _bOK = true; 468 | _btnFast = default(KeyValueFast); 469 | _btnFast.version = int.MinValue; 470 | } 471 | } 472 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 473 | ///////////////////////////////////////////// !IEnumerator ////////////////////////////////////////////////////// 474 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 475 | } 476 | } 477 | -------------------------------------------------------------------------------- /FriendlyCSharp.Databases/BTreeN/FcsFastLockBTreeN.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the KUBDAT® under one or more agreements. 2 | // The KUBDAT® licenses this file to you under the Apache-2.0 license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace FriendlyCSharp.Databases 9 | { 10 | public partial class FcsFastLockBTreeN : FcsFastBTreeN 11 | where TKey : struct, IComparable 12 | { 13 | private object _btnLock; 14 | ////////////////////////// 15 | public FcsFastLockBTreeN(uint idxFast) : base(_btnDefaultBTreeN, idxFast, null) 16 | { 17 | _btnLock = _btnLockAdd; 18 | } 19 | ////////////////////////// 20 | protected FcsFastLockBTreeN(uint idxFast, object objCmp) : base(_btnDefaultBTreeN, idxFast, objCmp) 21 | { 22 | _btnLock = _btnLockAdd; 23 | } 24 | ////////////////////////// 25 | public FcsFastLockBTreeN(int btnBTreeN, uint idxFast) : base(btnBTreeN, idxFast, null) 26 | { 27 | _btnLock = _btnLockAdd; 28 | } 29 | ////////////////////////// 30 | protected FcsFastLockBTreeN(int btnBTreeN, uint idxFast, object objCmp) : base(btnBTreeN, idxFast, objCmp) 31 | { 32 | _btnLock = _btnLockAdd; 33 | } 34 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 35 | ///////////////////////////////////////////// BtnFind ////////////////////////////////////////////////////// 36 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 37 | public override bool? BtnFind(TKey key, out TValue value) 38 | { 39 | lock (_btnLock) 40 | return _BtnFind(ref key, out value, _btnRoot, out _btnKVFast[0]); 41 | } 42 | ////////////////////////// 43 | // Specify if necessary, the symbol of: Project -> Properties -> Build -> Conditional Compilation Symbols 44 | #if KEY_VALUE_PAIR 45 | public override KeyValuePair? BtnFind(TKey key) 46 | { 47 | lock (_btnLock) 48 | { 49 | if (_BtnFind(ref key, out TValue valueOut, _btnRoot, out _btnKVFast[0]) == true) 50 | return new KeyValuePair(key, valueOut); 51 | else 52 | return null; 53 | } 54 | } 55 | #else 56 | public override (TKey key, TValue value)? BtnFind(TKey key) 57 | { 58 | lock (_btnLock) 59 | { 60 | if (_BtnFind(ref key, out TValue valueOut, _btnRoot, out _btnKVFast[0]) == true) 61 | return (key: key, value: valueOut); 62 | else 63 | return null; 64 | } 65 | } 66 | #endif 67 | ////////////////////////// 68 | public override bool? BtnFastFind(TKey key, out TValue value, uint idxFast) 69 | { 70 | lock (_btnLock) 71 | return base.BtnFastFind(key, out value, idxFast); 72 | } 73 | ////////////////////////// 74 | protected override bool? BtnFastFind(TKey key, out TValue value, out KeyValueFast btnFast) 75 | { 76 | lock (_btnLock) 77 | return base.BtnFastFind(key, out value, out btnFast); 78 | } 79 | ////////////////////////// 80 | #if KEY_VALUE_PAIR 81 | public override KeyValuePair? BtnFastFind(TKey key, uint idxFast) 82 | { 83 | lock (_btnLock) 84 | return base.BtnFastFind(key, idxFast); 85 | } 86 | #else 87 | public override (TKey key, TValue value)? BtnFastFind(TKey key, uint idxFast) 88 | { 89 | lock (_btnLock) 90 | return base.BtnFastFind(key, idxFast); 91 | } 92 | #endif 93 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 94 | ///////////////////////////////////////////// BtnFirst ////////////////////////////////////////////////////// 95 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 96 | public override bool? BtnFirst(out TKey key, out TValue value) 97 | { 98 | lock (_btnLock) 99 | return _BtnFirst(out key, out value, out _btnKVFast[0]); 100 | } 101 | ////////////////////////// 102 | #if KEY_VALUE_PAIR 103 | public override KeyValuePair? BtnFirst() 104 | { 105 | lock (_btnLock) 106 | return _BtnFirst(out _btnKVFast[0]); 107 | } 108 | #else 109 | public override (TKey key, TValue value)? BtnFirst() 110 | { 111 | lock (_btnLock) 112 | return _BtnFirst(out _btnKVFast[0]); 113 | } 114 | #endif 115 | ////////////////////////// 116 | public override bool? BtnFastFirst(out TKey key, out TValue value, uint idxFast) 117 | { 118 | lock (_btnLock) 119 | return base.BtnFastFirst(out key, out value, idxFast); 120 | } 121 | ////////////////////////// 122 | protected override bool? BtnFastFirst(out TKey key, out TValue value, out KeyValueFast btnFast) 123 | { 124 | lock (_btnLock) 125 | return base.BtnFastFirst(out key, out value, out btnFast); 126 | } 127 | ////////////////////////// 128 | #if KEY_VALUE_PAIR 129 | public override KeyValuePair? BtnFastFirst(uint idxFast) 130 | { 131 | lock (_btnLock) 132 | return base.BtnFastFirst(idxFast); 133 | } 134 | #else 135 | public override (TKey key, TValue value)? BtnFastFirst(uint idxFast) 136 | { 137 | lock (_btnLock) 138 | return base.BtnFastFirst(idxFast); 139 | } 140 | #endif 141 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 142 | ///////////////////////////////////////////// BtnLast ////////////////////////////////////////////////////// 143 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 144 | public override bool? BtnLast(out TKey key, out TValue value) 145 | { 146 | lock (_btnLock) 147 | return _BtnLast(out key, out value, out _btnKVFast[0]); 148 | } 149 | ////////////////////////// 150 | #if KEY_VALUE_PAIR 151 | public override KeyValuePair? BtnLast() 152 | { 153 | lock (_btnLock) 154 | return _BtnLast(out _btnKVFast[0]); 155 | } 156 | #else 157 | public override (TKey key, TValue value)? BtnLast() 158 | { 159 | lock (_btnLock) 160 | return _BtnLast(out _btnKVFast[0]); 161 | } 162 | #endif 163 | ////////////////////////// 164 | public override bool? BtnFastLast(out TKey key, out TValue value, uint idxFast) 165 | { 166 | lock (_btnLock) 167 | return base.BtnFastLast(out key, out value, idxFast); 168 | } 169 | ////////////////////////// 170 | protected override bool? BtnFastLast(out TKey key, out TValue value, out KeyValueFast btnFast) 171 | { 172 | lock (_btnLock) 173 | return base.BtnFastLast(out key, out value, out btnFast); 174 | } 175 | ////////////////////////// 176 | #if KEY_VALUE_PAIR 177 | public override KeyValuePair? BtnFastLast(uint idxFast) 178 | { 179 | lock (_btnLock) 180 | return base.BtnFastLast(idxFast); 181 | } 182 | #else 183 | public override (TKey key, TValue value)? BtnFastLast(uint idxFast) 184 | { 185 | lock (_btnLock) 186 | return base.BtnFastLast(idxFast); 187 | } 188 | #endif 189 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 190 | ///////////////////////////////////////////// BtnNext ////////////////////////////////////////////////////// 191 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 192 | public override bool? BtnNext(ref TKey key, out TValue value) 193 | { 194 | lock (_btnLock) 195 | { 196 | bool bNext = false; 197 | return _BtnNext(ref key, out value, _btnRoot, ref bNext, out _btnKVFast[0]); 198 | } 199 | } 200 | ////////////////////////// 201 | #if KEY_VALUE_PAIR 202 | public override KeyValuePair? BtnNext(TKey key) 203 | { 204 | lock (_btnLock) 205 | { 206 | bool bNext = false; 207 | if (_BtnNext(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 208 | return new KeyValuePair(key, valueOut); 209 | else 210 | return null; 211 | } 212 | } 213 | #else 214 | public override (TKey key, TValue value)? BtnNext(TKey key) 215 | { 216 | lock (_btnLock) 217 | { 218 | bool bNext = false; 219 | if (_BtnNext(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 220 | return (key: key, value: valueOut); 221 | else 222 | return null; 223 | } 224 | } 225 | #endif 226 | ////////////////////////// 227 | public override bool? BtnFastNext(ref TKey key, out TValue value, uint idxFast) 228 | { 229 | lock (_btnLock) 230 | return base.BtnFastNext(ref key, out value, idxFast); 231 | } 232 | ////////////////////////// 233 | protected override bool? BtnFastNext(ref TKey key, out TValue value, ref KeyValueFast btnFast) 234 | { 235 | lock (_btnLock) 236 | return base.BtnFastNext(ref key, out value, ref btnFast); 237 | } 238 | ////////////////////////// 239 | #if KEY_VALUE_PAIR 240 | public override KeyValuePair? BtnFastNext(TKey key, uint idxFast) 241 | { 242 | lock (_btnLock) 243 | return base.BtnFastNext(key, idxFast); 244 | } 245 | #else 246 | public override (TKey key, TValue value)? BtnFastNext(TKey key, uint idxFast) 247 | { 248 | lock (_btnLock) 249 | return base.BtnFastNext(key, idxFast); 250 | } 251 | #endif 252 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 253 | ///////////////////////////////////////////// BtnPrev ////////////////////////////////////////////////////// 254 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 255 | public override bool? BtnPrev(ref TKey key, out TValue value) 256 | { 257 | lock (_btnLock) 258 | { 259 | bool bNext = false; 260 | return _BtnPrev(ref key, out value, _btnRoot, ref bNext, out _btnKVFast[0]); 261 | } 262 | } 263 | ////////////////////////// 264 | #if KEY_VALUE_PAIR 265 | public override KeyValuePair? BtnPrev(TKey key) 266 | { 267 | lock (_btnLock) 268 | { 269 | bool bNext = false; 270 | if (_BtnPrev(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 271 | return new KeyValuePair(key, valueOut); 272 | else 273 | return null; 274 | } 275 | } 276 | #else 277 | public override (TKey key, TValue value)? BtnPrev(TKey key) 278 | { 279 | lock (_btnLock) 280 | { 281 | bool bNext = false; 282 | if (_BtnPrev(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 283 | return (key: key, value: valueOut); 284 | else 285 | return null; 286 | } 287 | } 288 | #endif 289 | ////////////////////////// 290 | public override bool? BtnFastPrev(ref TKey key, out TValue value, uint idxFast) 291 | { 292 | lock (_btnLock) 293 | return base.BtnFastPrev(ref key, out value, idxFast); 294 | } 295 | ////////////////////////// 296 | protected override bool? BtnFastPrev(ref TKey key, out TValue value, ref KeyValueFast btnFast) 297 | { 298 | lock (_btnLock) 299 | return base.BtnFastPrev(ref key, out value, ref btnFast); 300 | } 301 | ////////////////////////// 302 | #if KEY_VALUE_PAIR 303 | public override KeyValuePair? BtnFastPrev(TKey key, uint idxFast) 304 | { 305 | lock (_btnLock) 306 | return base.BtnFastPrev(key, idxFast); 307 | } 308 | #else 309 | public override (TKey key, TValue value)? BtnFastPrev(TKey key, uint idxFast) 310 | { 311 | lock (_btnLock) 312 | return base.BtnFastPrev(key, idxFast); 313 | } 314 | #endif 315 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 316 | ///////////////////////////////////////////// BtnSearch ////////////////////////////////////////////////////// 317 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 318 | public override bool? BtnSearch(ref TKey key, out TValue value) 319 | { 320 | bool bNext = false; 321 | lock (_btnLock) 322 | return _BtnSearch(ref key, out value, _btnRoot, ref bNext, out _btnKVFast[0]); 323 | } 324 | ////////////////////////// 325 | #if KEY_VALUE_PAIR 326 | public override KeyValuePair? BtnSearch(TKey key) 327 | { 328 | lock (_btnLock) 329 | { 330 | bool bNext = false; 331 | if (_BtnSearch(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 332 | return new KeyValuePair(key, valueOut); 333 | else 334 | return null; 335 | } 336 | } 337 | #else 338 | public override (TKey key, TValue value)? BtnSearch(TKey key) 339 | { 340 | lock (_btnLock) 341 | { 342 | bool bNext = false; 343 | if (_BtnSearch(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 344 | return (key: key, value: valueOut); 345 | else 346 | return null; 347 | } 348 | } 349 | #endif 350 | ////////////////////////// 351 | public override bool? BtnFastSearch(ref TKey key, out TValue value, uint idxFast) 352 | { 353 | lock (_btnLock) 354 | return base.BtnFastSearch(ref key, out value, idxFast); 355 | } 356 | ////////////////////////// 357 | protected override bool? BtnFastSearch(ref TKey key, out TValue value, out KeyValueFast btnFast) 358 | { 359 | lock (_btnLock) 360 | return base.BtnFastSearch(ref key, out value, out btnFast); 361 | } 362 | ////////////////////////// 363 | #if KEY_VALUE_PAIR 364 | public override KeyValuePair? BtnFastSearch(TKey key, uint idxFast) 365 | { 366 | lock (_btnLock) 367 | return base.BtnFastSearch(key, idxFast); 368 | } 369 | #else 370 | public override (TKey key, TValue value)? BtnFastSearch(TKey key, uint idxFast) 371 | { 372 | lock (_btnLock) 373 | return base.BtnFastSearch(key, idxFast); 374 | } 375 | #endif 376 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 377 | ///////////////////////////////////////////// BtnSearchPrev ////////////////////////////////////////////////////// 378 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 379 | public override bool? BtnSearchPrev(ref TKey key, out TValue value) 380 | { 381 | bool bNext = false; 382 | lock (_btnLock) 383 | return _BtnSearchPrev(ref key, out value, _btnRoot, ref bNext, out _btnKVFast[0]); 384 | } 385 | ////////////////////////// 386 | #if KEY_VALUE_PAIR 387 | public override KeyValuePair? BtnSearchPrev(TKey key) 388 | { 389 | lock (_btnLock) 390 | { 391 | bool bNext = false; 392 | if (_BtnSearchPrev(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 393 | return new KeyValuePair(key, valueOut); 394 | else 395 | return null; 396 | } 397 | } 398 | #else 399 | public override (TKey key, TValue value)? BtnSearchPrev(TKey key) 400 | { 401 | lock (_btnLock) 402 | { 403 | bool bNext = false; 404 | if (_BtnSearchPrev(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 405 | return (key: key, value: valueOut); 406 | else 407 | return null; 408 | } 409 | } 410 | #endif 411 | ////////////////////////// 412 | public override bool? BtnFastSearchPrev(ref TKey key, out TValue value, uint idxFast) 413 | { 414 | lock (_btnLock) 415 | return base.BtnFastSearchPrev(ref key, out value, idxFast); 416 | } 417 | ////////////////////////// 418 | protected override bool? BtnFastSearchPrev(ref TKey key, out TValue value, out KeyValueFast btnFast) 419 | { 420 | lock (_btnLock) 421 | return base.BtnFastSearchPrev(ref key, out value, out btnFast); 422 | } 423 | ////////////////////////// 424 | #if KEY_VALUE_PAIR 425 | public override KeyValuePair? BtnFastSearchPrev(TKey key, uint idxFast) 426 | { 427 | lock (_btnLock) 428 | return base.BtnFastSearchPrev(key, idxFast); 429 | } 430 | #else 431 | public override (TKey key, TValue value)? BtnFastSearchPrev(TKey key, uint idxFast) 432 | { 433 | lock (_btnLock) 434 | return base.BtnFastSearchPrev(key, idxFast); 435 | } 436 | #endif 437 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 438 | /////////////////////////////////////////// BtnUsedKeys /////////////////////////////////////////////////// 439 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 440 | public override uint BtnUsedKeys() 441 | { 442 | lock (_btnLock) 443 | { 444 | return base.BtnUsedKeys(); 445 | } 446 | } 447 | } 448 | } 449 | -------------------------------------------------------------------------------- /FriendlyCSharp.Databases/BTreeN/FcsLockBTreeN.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the KUBDAT® under one or more agreements. 2 | // The KUBDAT® licenses this file to you under the Apache-2.0 license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace FriendlyCSharp.Databases 9 | { 10 | public partial class FcsLockBTreeN : FcsBTreeN 11 | where TKey : struct, IComparable 12 | { 13 | private object _btnLock; 14 | ////////////////////////// 15 | public FcsLockBTreeN() : base(_btnDefaultBTreeN, 1, null) 16 | { 17 | _btnLock = _btnLockAdd; 18 | } 19 | ////////////////////////// 20 | protected FcsLockBTreeN(object objCmp) : base(_btnDefaultBTreeN, 1, objCmp) 21 | { 22 | _btnLock = _btnLockAdd; 23 | } 24 | ////////////////////////// 25 | public FcsLockBTreeN(int btnBTreeN) : base(btnBTreeN, 1, null) 26 | { 27 | _btnLock = _btnLockAdd; 28 | } 29 | ////////////////////////// 30 | protected FcsLockBTreeN(int btnBTreeN, object objCmp) : base(btnBTreeN, 1, objCmp) 31 | { 32 | _btnLock = _btnLockAdd; 33 | } 34 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 35 | ///////////////////////////////////////////// BtnFind ////////////////////////////////////////////////////// 36 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 37 | public override bool? BtnFind(TKey key, out TValue value) 38 | { 39 | lock (_btnLock) 40 | return _BtnFind(ref key, out value, _btnRoot, out _btnKVFast[0]); 41 | } 42 | ////////////////////////// 43 | // Specify if necessary, the symbol of: Project -> Properties -> Build -> Conditional Compilation Symbols 44 | #if KEY_VALUE_PAIR 45 | public override KeyValuePair? BtnFind(TKey key) 46 | { 47 | lock (_btnLock) 48 | { 49 | if (_BtnFind(ref key, out TValue valueOut, _btnRoot, out _btnKVFast[0]) == true) 50 | return new KeyValuePair(key, valueOut); 51 | else 52 | return null; 53 | } 54 | } 55 | #else 56 | public override (TKey key, TValue value)? BtnFind(TKey key) 57 | { 58 | lock (_btnLock) 59 | { 60 | if (_BtnFind(ref key, out TValue valueOut, _btnRoot, out _btnKVFast[0]) == true) 61 | return (key: key, value: valueOut); 62 | else 63 | return null; 64 | } 65 | } 66 | #endif 67 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 68 | ///////////////////////////////////////////// BtnFirst ////////////////////////////////////////////////////// 69 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 70 | public override bool? BtnFirst(out TKey key, out TValue value) 71 | { 72 | lock (_btnLock) 73 | return _BtnFirst(out key, out value, out _btnKVFast[0]); 74 | } 75 | ////////////////////////// 76 | #if KEY_VALUE_PAIR 77 | public override KeyValuePair? BtnFirst() 78 | { 79 | lock (_btnLock) 80 | return _BtnFirst(out _btnKVFast[0]); 81 | } 82 | #else 83 | public override (TKey key, TValue value)? BtnFirst() 84 | { 85 | lock (_btnLock) 86 | return _BtnFirst(out _btnKVFast[0]); 87 | } 88 | #endif 89 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 90 | ///////////////////////////////////////////// BtnLast ////////////////////////////////////////////////////// 91 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 92 | public override bool? BtnLast(out TKey key, out TValue value) 93 | { 94 | lock (_btnLock) 95 | return _BtnLast(out key, out value, out _btnKVFast[0]); 96 | } 97 | ////////////////////////// 98 | #if KEY_VALUE_PAIR 99 | public override KeyValuePair? BtnLast() 100 | { 101 | lock (_btnLock) 102 | return _BtnLast(out _btnKVFast[0]); 103 | } 104 | #else 105 | public override (TKey key, TValue value)? BtnLast() 106 | { 107 | lock (_btnLock) 108 | return _BtnLast(out _btnKVFast[0]); 109 | } 110 | #endif 111 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 112 | ///////////////////////////////////////////// BtnNext ////////////////////////////////////////////////////// 113 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 114 | public override bool? BtnNext(ref TKey key, out TValue value) 115 | { 116 | lock (_btnLock) 117 | { 118 | bool bNext = false; 119 | return _BtnNext(ref key, out value, _btnRoot, ref bNext, out _btnKVFast[0]); 120 | } 121 | } 122 | ////////////////////////// 123 | #if KEY_VALUE_PAIR 124 | public override KeyValuePair? BtnNext(TKey key) 125 | { 126 | lock (_btnLock) 127 | { 128 | bool bNext = false; 129 | if (_BtnNext(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 130 | return new KeyValuePair(key, valueOut); 131 | else 132 | return null; 133 | } 134 | } 135 | #else 136 | public override (TKey key, TValue value)? BtnNext(TKey key) 137 | { 138 | lock (_btnLock) 139 | { 140 | bool bNext = false; 141 | if (_BtnNext(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 142 | return (key: key, value: valueOut); 143 | else 144 | return null; 145 | } 146 | } 147 | #endif 148 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 149 | ///////////////////////////////////////////// BtnPrev ////////////////////////////////////////////////////// 150 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 151 | public override bool? BtnPrev(ref TKey key, out TValue value) 152 | { 153 | lock (_btnLock) 154 | { 155 | bool bNext = false; 156 | return _BtnPrev(ref key, out value, _btnRoot, ref bNext, out _btnKVFast[0]); 157 | } 158 | } 159 | ////////////////////////// 160 | #if KEY_VALUE_PAIR 161 | public override KeyValuePair? BtnPrev(TKey key) 162 | { 163 | lock (_btnLock) 164 | { 165 | bool bNext = false; 166 | if (_BtnPrev(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 167 | return new KeyValuePair(key, valueOut); 168 | else 169 | return null; 170 | } 171 | } 172 | #else 173 | public override (TKey key, TValue value)? BtnPrev(TKey key) 174 | { 175 | lock (_btnLock) 176 | { 177 | bool bNext = false; 178 | if (_BtnPrev(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 179 | return (key: key, value: valueOut); 180 | else 181 | return null; 182 | } 183 | } 184 | #endif 185 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 186 | ///////////////////////////////////////////// BtnSearch ////////////////////////////////////////////////////// 187 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 188 | public override bool? BtnSearch(ref TKey key, out TValue value) 189 | { 190 | bool bNext = false; 191 | lock (_btnLock) 192 | return _BtnSearch(ref key, out value, _btnRoot, ref bNext, out _btnKVFast[0]); 193 | } 194 | ////////////////////////// 195 | #if KEY_VALUE_PAIR 196 | public override KeyValuePair? BtnSearch(TKey key) 197 | { 198 | lock (_btnLock) 199 | { 200 | bool bNext = false; 201 | if (_BtnSearch(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 202 | return new KeyValuePair(key, valueOut); 203 | else 204 | return null; 205 | } 206 | } 207 | #else 208 | public override (TKey key, TValue value)? BtnSearch(TKey key) 209 | { 210 | lock (_btnLock) 211 | { 212 | bool bNext = false; 213 | if (_BtnSearch(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 214 | return (key: key, value: valueOut); 215 | else 216 | return null; 217 | } 218 | } 219 | #endif 220 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 221 | ///////////////////////////////////////////// BtnSearchPrev ////////////////////////////////////////////////////// 222 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 223 | ////////////////////////// 224 | public override bool? BtnSearchPrev(ref TKey key, out TValue value) 225 | { 226 | bool bNext = false; 227 | lock (_btnLock) 228 | return _BtnSearchPrev(ref key, out value, _btnRoot, ref bNext, out _btnKVFast[0]); 229 | } 230 | ////////////////////////// 231 | #if KEY_VALUE_PAIR 232 | public override KeyValuePair? BtnSearchPrev(TKey key) 233 | { 234 | lock (_btnLock) 235 | { 236 | bool bNext = false; 237 | if (_BtnSearchPrev(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 238 | return new KeyValuePair(key, valueOut); 239 | else 240 | return null; 241 | } 242 | } 243 | #else 244 | public override (TKey key, TValue value)? BtnSearchPrev(TKey key) 245 | { 246 | lock (_btnLock) 247 | { 248 | bool bNext = false; 249 | if (_BtnSearchPrev(ref key, out TValue valueOut, _btnRoot, ref bNext, out _btnKVFast[0]) == true) 250 | return (key: key, value: valueOut); 251 | else 252 | return null; 253 | } 254 | } 255 | #endif 256 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 257 | /////////////////////////////////////////// BtnUsedKeys /////////////////////////////////////////////////// 258 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 259 | public override uint BtnUsedKeys() 260 | { 261 | lock (_btnLock) 262 | return BtnUsedKeys(); 263 | } 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /FriendlyCSharp.Databases/FriendlyCSharp.Databases.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | True 5 | KUBDAT® 6 | inmem, s.r.o. 7 | https://github.com/inmem/FriendlyCSharp.Databases/blob/master/LICENSE 8 | 9 | https://github.com/inmem/FriendlyCSharp.Databases 10 | C# cross-platform netstandard key-value nosql in-memory cache database b-tree btree Bayer fulltext elastic search KUBDAT inmem 11 | Copyright 2017 (c) KUBDAT® & inmem, s.r.o. 12 | Generic B-tree written in C#, which can be replaced with NoSQL database stored in the memory. 13 | 14 | The B-tree is a generalization of a binary search tree in that a node can have more than two children (Comer 1979, p. 123). Unlike self-balancing binary search trees, the B-tree is optimized for systems that read and write large blocks of data. 15 | 16 | Upgrades FcsBTreeN and FcsDuplValueFastBTreeN, including addition BtnAddNoLock 17 | 18 | 19 | 20 | netstandard2.0 21 | 2.0.4 22 | 2.0.4.0 23 | 2.0.4.0 24 | false 25 | 26 | 27 | 28 | TRACE;DEBUG;NETSTANDARD1_1;KEY_VALUE_PAIR 29 | 30 | 31 | 32 | TRACE;RELEASE;NETSTANDARD1_1;KEY_VALUE_PAIR 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /FriendlyCSharp.Databases/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | FileSystem 9 | Release 10 | netstandard2.0 11 | bin\Release\PublishOutput 12 | 13 | -------------------------------------------------------------------------------- /FriendlyCSharp.Databases/Storage/FcsInmemStream.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the KUBDAT® under one or more agreements. 2 | // The KUBDAT® licenses this file to you under the Apache-2.0 license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Collections; 7 | using System.Collections.Generic; 8 | using System.IO; 9 | using System.Runtime.InteropServices; 10 | using TImsId = System.UInt32; 11 | 12 | namespace FriendlyCSharp.Databases 13 | { 14 | public class FcsInmemStream : Stream, IDisposable, IEnumerable, IEnumerable 15 | where T : struct, ICloneable 16 | { 17 | public static readonly TImsId NoDelete = default(TImsId); 18 | public static readonly TImsId ErrorId = default(TImsId); 19 | protected short _delta64KPerPageT; 20 | protected int _recPageCols = 0x00010000; // 65536 21 | protected int _recPageRows; 22 | protected int _recPageRowsCount; 23 | protected RecPage[] _recPage; 24 | protected bool _bRecDelete; 25 | protected TImsId _capacity; 26 | protected TImsId _length; 27 | protected bool _isOpen; 28 | private TImsId _position; 29 | protected readonly object _lockAppend = new object(); 30 | public readonly TImsId OFFSET_ERROR = TImsId.MaxValue; 31 | // 32 | private TImsId _offsetPosition; 33 | public TImsId OFFSET_POSITION { get => _offsetPosition; } 34 | // 35 | private bool _bFuncPosition; 36 | public bool FuncPosition 37 | { 38 | get 39 | { 40 | return _bFuncPosition; 41 | } 42 | set 43 | { 44 | if (_bFuncPosition) 45 | _offsetPosition = OFFSET_ERROR; 46 | else 47 | _offsetPosition = 0; 48 | _bFuncPosition = value; 49 | } 50 | } 51 | // 52 | private bool _bFuncException; 53 | public bool FuncException { get => _bFuncException; set => _bFuncException = value; } 54 | // 55 | private bool _disposed = false; 56 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 57 | ///////////////////////////////////////////// Transaction ////////////////////////////////////////////////////// 58 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 59 | public struct Transaction : ICloneable 60 | { 61 | public TImsId keyPos; 62 | public UInt16 keyCount; 63 | public bool valueOK; 64 | public T[] valueARec; 65 | ///////////////////////////////////////////// 66 | public Transaction(TImsId pos, UInt16 count) 67 | { 68 | keyPos = pos; 69 | keyCount = count; 70 | valueOK = false; 71 | valueARec = null; 72 | } 73 | ///////////////////////////////////////////// 74 | public Transaction(Transaction Trans) 75 | { 76 | keyPos = Trans.keyPos; 77 | keyCount = Trans.keyCount; 78 | valueOK = false; 79 | valueARec = null; 80 | } 81 | ///////////////////////////////////////////// 82 | public static Transaction[] Copy(Transaction[] aTransSrc) 83 | { 84 | if (aTransSrc == null) 85 | return null; 86 | Transaction[] aTransDesc = new Transaction[aTransSrc.Length]; 87 | for (int uu = 0; uu < aTransSrc.Length; uu++) 88 | aTransDesc[uu] = new Transaction(aTransSrc[uu]); 89 | return aTransDesc; 90 | } 91 | ///////////////////////////////////////////// 92 | public object Clone() 93 | { 94 | Transaction Trans = (Transaction)MemberwiseClone(); 95 | Trans.valueARec = (T[])valueARec.Clone(); 96 | return Trans; 97 | } 98 | } 99 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 100 | ///////////////////////////////////////////// RecPage ////////////////////////////////////////////////////// 101 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 102 | protected class RecPage : IDisposable 103 | { 104 | public int iUpdate; 105 | public DateTime timeRead; 106 | public DateTime timeWrite; 107 | public T[] aRec; 108 | public TImsId[] aDel; 109 | private bool disposed = false; 110 | ///////////////////////////////////////////// 111 | public RecPage(int iRecCount, bool bRecDelete) 112 | { 113 | iUpdate = 0; 114 | timeRead = DateTime.MinValue; 115 | timeWrite = DateTime.MinValue; 116 | aRec = new T[iRecCount]; 117 | if (bRecDelete) 118 | aDel = new TImsId[iRecCount]; 119 | else 120 | aDel = null; 121 | } 122 | ///////////////////////////////////////////// 123 | protected virtual void Dispose(bool disposing) 124 | { 125 | if (!disposed) 126 | { 127 | disposed = true; 128 | // TODO: Nastavte velká pole na hodnotu null. 129 | aRec = null; 130 | aDel = null; 131 | // Call base class implementation. 132 | //base.Dispose(disposing); 133 | } 134 | } 135 | ///////////////////////////////////////////// 136 | public void Dispose() 137 | { 138 | Dispose(true); 139 | // TODO: Zrušte komentář následujícího řádku, pokud se přepisuje finalizační metoda. 140 | //GC.SuppressFinalize(this); 141 | } 142 | } 143 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 144 | ///////////////////////////////////////////// FcsInmemStream ////////////////////////////////////////////////////// 145 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 146 | public FcsInmemStream() : this(0, false) 147 | { 148 | } 149 | ///////////////////////////////////////////// 150 | public FcsInmemStream(short delta64KPerPageT) : this(delta64KPerPageT, false) 151 | { 152 | } 153 | ///////////////////////////////////////////// 154 | public FcsInmemStream(short delta64KPerPageT, bool bRecDelete) 155 | { 156 | if (typeof(T) == typeof(DateTime)) 157 | throw new ArgumentOutOfRangeException("Type DateTime can not be directly insert it into the structure."); 158 | _delta64KPerPageT = delta64KPerPageT; 159 | // min.T 4096, max.T 1048576 (rec per page), maxRows = 32768, min.T 128M, max.T 32G 160 | // deltaPage == -4 up 2^12T, == -3 up 2^13T, == -2 up 2^14T, == -1 up 2^15T (rec per page) 161 | // deltaPage == 0 up 2^16T (rec per page) 162 | // deltaPage == 1 up 2^17T, == 2 up 2^18T, == 3 up 2^19T, == 4 up 2^20T (rec per page) 163 | if ((delta64KPerPageT < -4) || (delta64KPerPageT > 4)) 164 | throw new ArgumentOutOfRangeException(nameof(delta64KPerPageT)); 165 | if (delta64KPerPageT < 0) 166 | _recPageCols >>= Math.Abs(delta64KPerPageT); 167 | else if (delta64KPerPageT > 0) 168 | _recPageCols <<= Math.Abs(delta64KPerPageT); 169 | _recPageRows = 0x0100; // 256 BufferPage 170 | _recPage = new RecPage[_recPageRows]; 171 | _bRecDelete = bRecDelete; 172 | _recPageRowsCount = 0; 173 | _capacity = 0; 174 | _length = 0; 175 | _position = 0; 176 | FuncPosition = false; 177 | FuncException = true; 178 | _isOpen = true; 179 | } 180 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 181 | ///////////////////////////////////////////// Append ////////////////////////////////////////////////////// 182 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 183 | public virtual TImsId Append(T value) 184 | { 185 | T[] aValue = new T[1]; 186 | aValue[0] = value; 187 | return Append(aValue, null, 0, (UInt16)aValue.Length); 188 | } 189 | ///////////////////////////////////////////// 190 | public virtual TImsId Append(T[] aValue) 191 | { 192 | if (_bFuncException) 193 | { 194 | if (aValue == null) 195 | throw new ArgumentOutOfRangeException(nameof(aValue)); 196 | if ((aValue.Length <= 0) || (aValue.Length > UInt16.MaxValue)) 197 | throw new ArgumentOutOfRangeException(nameof(aValue.Length)); 198 | } 199 | 200 | return Append(aValue, null, 0, (UInt16)aValue.Length); 201 | } 202 | ///////////////////////////////////////////// 203 | public virtual TImsId Append(T[] aValue, int index, UInt16 count) 204 | { 205 | if (_bFuncException) 206 | { 207 | if (aValue == null) 208 | throw new ArgumentOutOfRangeException(nameof(aValue)); 209 | if ((aValue.Length <= 0) || (aValue.Length > UInt16.MaxValue)) 210 | throw new ArgumentOutOfRangeException(nameof(aValue.Length)); 211 | } 212 | 213 | return Append(aValue, null, index, count); 214 | } 215 | ///////////////////////////////////////////// 216 | protected virtual TImsId Append(T[] aValue, TImsId[] aDel, int index, UInt16 count) 217 | { 218 | if (!CanWrite) 219 | return OFFSET_ERROR; 220 | 221 | if (_bFuncException) 222 | { 223 | if (aValue == null) 224 | throw new ArgumentOutOfRangeException(nameof(aValue)); 225 | if ((index < 0) || (index >= aValue.Length)) 226 | throw new ArgumentOutOfRangeException(nameof(index)); 227 | if ((count == 0) || (count + index > aValue.Length)) 228 | throw new ArgumentOutOfRangeException(nameof(count)); 229 | } 230 | 231 | TImsId lengthTemp = OFFSET_ERROR; 232 | lock (_lockAppend) 233 | { 234 | if (Length < 0) 235 | throw new ArgumentOutOfRangeException(nameof(Length)); 236 | lengthTemp = (TImsId)Length; 237 | long lNewLen = lengthTemp + count; 238 | while (lNewLen > Capacity) 239 | { 240 | if (_recPageRowsCount >= _recPageRows) 241 | { 242 | _recPageRows <<= 1; 243 | if (_recPageRows >= 0x00008000) // 32768 244 | throw new OutOfMemoryException(); 245 | Array.Resize(ref _recPage, _recPageRows); 246 | } 247 | _recPage[_recPageRowsCount++] = new RecPage(_recPageCols, _bRecDelete); 248 | long lCapacity = _recPageCols * _recPageRowsCount; 249 | if (lCapacity < 0) 250 | throw new ArgumentOutOfRangeException(); 251 | else 252 | _capacity = (TImsId)lCapacity; 253 | } 254 | int iWrite = _BlockCopyInternal(false, lengthTemp, aValue, aDel, index, count); 255 | if (iWrite == count) 256 | { 257 | _length += (TImsId)iWrite; 258 | if (FuncPosition) 259 | Position = Length; 260 | } 261 | else 262 | lengthTemp = OFFSET_ERROR; 263 | } // !lock 264 | return lengthTemp; 265 | } 266 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 267 | //////////////////////////////////////// CanRead, CanSeek, CanWrite ////////////////////////////////////////////////// 268 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 269 | public override bool CanRead 270 | { 271 | get { return _isOpen; } 272 | } 273 | ///////////////////////////////////////////// 274 | public override bool CanSeek 275 | { 276 | get { return _isOpen; } 277 | } 278 | ///////////////////////////////////////////// 279 | public override bool CanWrite 280 | { 281 | get { return _isOpen; } 282 | } 283 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 284 | ///////////////////////////////////////////// Capacity, Close ////////////////////////////////////////////////////// 285 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 286 | public virtual TImsId Capacity { get => _capacity; } 287 | ///////////////////////////////////////////// 288 | public override void Close() 289 | { 290 | _isOpen = false; 291 | Dispose(); 292 | base.Close(); 293 | } 294 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 295 | ///////////////////////////////////////////// Delete ////////////////////////////////////////////////////// 296 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 297 | public virtual bool Delete(TImsId offset) 298 | { 299 | return Delete(offset, ErrorId); 300 | } 301 | ///////////////////////////////////////////// 302 | public virtual bool Delete(TImsId offset, TImsId offsetNew) 303 | { 304 | RecPage[] buffPageLocal = _recPage; 305 | if ((offset < 0) || (offset >= Length) || (!_RowColsOffset(buffPageLocal, offset, out int iRow, out int iCols))) 306 | throw new ArgumentOutOfRangeException(nameof(offset)); 307 | if (!_bRecDelete) 308 | { 309 | lock (_lockAppend) 310 | { 311 | if (!_bRecDelete) 312 | { 313 | _bRecDelete = true; 314 | for (int idx = 0; idx < _recPageRowsCount; idx++) 315 | buffPageLocal[idx].aDel = new TImsId[_recPageCols]; 316 | } 317 | } 318 | } 319 | if (buffPageLocal[iRow].aDel == null) 320 | throw new ArgumentNullException("", "_bufferPage[iRow].aDel"); 321 | 322 | buffPageLocal[iRow].aDel[iCols] = offsetNew; 323 | return true; 324 | } 325 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 326 | ///////////////////////////////////////////// Dispose, Flush ////////////////////////////////////////////////////// 327 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 328 | public new void Dispose() 329 | { 330 | Dispose(true); 331 | //GC.SuppressFinalize(this); 332 | base.Dispose(true); 333 | } 334 | ///////////////////////////////////////////// 335 | protected override void Dispose(bool disposing) 336 | { 337 | if (!_disposed) 338 | { 339 | _disposed = true; 340 | _isOpen = false; 341 | if (_recPage != null) 342 | { 343 | for (int ii = 0; ii < _recPageRowsCount; ii++) 344 | { 345 | _recPage[ii].Dispose(); 346 | _recPage[ii] = null; 347 | } 348 | } 349 | _recPage = null; 350 | // Call base class implementation. 351 | base.Dispose(disposing); 352 | } 353 | } 354 | ///////////////////////////////////////////// 355 | public override void Flush() 356 | { 357 | throw new NotImplementedException("Cannot Flush() to this FcsInmemStream."); 358 | } 359 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 360 | ///////////////////////////////////////////// IsDelete ////////////////////////////////////////////////////// 361 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 362 | public virtual long IsDelete(TImsId offset) 363 | { 364 | if (!_bRecDelete) 365 | return 0; 366 | 367 | RecPage[] buffPageLocal = _recPage; 368 | if ((offset < 0) || (offset >= Length) || (!_RowColsOffset(buffPageLocal, offset, out int iRow, out int iCols))) 369 | throw new ArgumentOutOfRangeException(nameof(offset)); 370 | if (buffPageLocal[iRow].aDel == null) 371 | throw new ArgumentNullException("", "_bufferPage[iRow].aDel"); 372 | return buffPageLocal[iRow].aDel[iCols]; 373 | } 374 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 375 | ///////////////////////////////////////////// Length, Open, Position ////////////////////////////////////////////////////// 376 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 377 | public override long Length { get => _length; } 378 | ///////////////////////////////////////////// 379 | public static FcsInmemStream Open() 380 | { 381 | return new FcsInmemStream(0, false); 382 | } 383 | ///////////////////////////////////////////// 384 | public static FcsInmemStream Open(short delta64KPerPageT) 385 | { 386 | return new FcsInmemStream(delta64KPerPageT, false); 387 | } 388 | ///////////////////////////////////////////// 389 | public static FcsInmemStream Open(short delta64KPerPageT, bool bRecDelete) 390 | { 391 | return new FcsInmemStream(delta64KPerPageT, bRecDelete); 392 | } 393 | ///////////////////////////////////////////// 394 | public override long Position 395 | { 396 | get 397 | { 398 | if (FuncPosition) 399 | return _position; 400 | throw new NotImplementedException("Cannot Position() to this FcsInmemStream."); 401 | } 402 | set 403 | { 404 | if (FuncPosition) 405 | { 406 | long lengthTemp = Length; 407 | if ((value >= 0) && (value <= lengthTemp)) 408 | _position = (TImsId)value; 409 | else 410 | _position = (TImsId)lengthTemp; 411 | } 412 | else 413 | throw new NotImplementedException("Cannot Position() to this FcsInmemStream."); 414 | } 415 | } 416 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 417 | ///////////////////////////////////////////// Read ////////////////////////////////////////////////////// 418 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 419 | public override int Read(byte[] buffer, int offset, int count) 420 | { 421 | if (!_bFuncPosition) 422 | throw new NotImplementedException("Cannot Read() to this FcsInmemStream."); 423 | if (!CanRead) 424 | return 0; 425 | 426 | int sizeT = Marshal.SizeOf(); 427 | int countT = Math.Abs(count) / sizeT; 428 | if ((count > 0) && (countT <= 0)) 429 | countT = sizeT; 430 | countT &= 0xFFFF; 431 | if (_bFuncException) 432 | { 433 | if (buffer == null) 434 | throw new ArgumentOutOfRangeException(nameof(buffer)); 435 | if ((offset < 0) || (offset >= buffer.Length)) 436 | throw new ArgumentOutOfRangeException(nameof(offset)); 437 | if ((count <= 0) || (count + offset > buffer.Length)) 438 | throw new ArgumentOutOfRangeException(nameof(count)); 439 | } 440 | 441 | long lengthTemp = Length; 442 | long position = Position; 443 | if (position == lengthTemp) // foreach must return 0 444 | return 0; 445 | if ((position < 0) || (position > lengthTemp)) 446 | throw new ArgumentOutOfRangeException(nameof(Position)); 447 | 448 | if (position + countT > lengthTemp) 449 | countT = (UInt16)(lengthTemp - position); 450 | T[] aValue = new T[countT]; 451 | int iRead = _BlockCopyInternal(true, position, aValue, null, 0, countT); 452 | // 453 | int size = iRead * sizeT; 454 | IntPtr ptr = Marshal.AllocHGlobal(size); 455 | Marshal.StructureToPtr(aValue, ptr, false); 456 | Marshal.Copy(ptr, buffer, offset, size); 457 | Marshal.FreeHGlobal(ptr); 458 | // 459 | lock (_lockAppend) 460 | Position = position + iRead; 461 | return iRead * sizeT; 462 | } 463 | ///////////////////////////////////////////// 464 | public virtual int Read(out T value) 465 | { 466 | if (FuncPosition) 467 | return Read(OFFSET_POSITION, out value); 468 | value = default(T); 469 | return 0; 470 | } 471 | ///////////////////////////////////////////// 472 | public virtual int Read(out T[] aValue, int count) 473 | { 474 | if (FuncPosition) 475 | return Read(OFFSET_POSITION, out aValue, count); 476 | aValue = new T[0]; 477 | return 0; 478 | } 479 | ///////////////////////////////////////////// 480 | public virtual int Read(TImsId offset, out T value, out TImsId DeleteRecId) 481 | { 482 | value = default(T); 483 | DeleteRecId = NoDelete; 484 | if ((FuncPosition) && (offset == OFFSET_POSITION)) 485 | offset = (TImsId)Position; 486 | if ((!CanRead) || (offset < 0) || (offset >= Length)) 487 | return 0; 488 | 489 | T[] aValue = new T[1]; 490 | TImsId[] aDel = new TImsId[1]; 491 | int iRead = _BlockCopyInternal(true, offset, aValue, aDel, 0, 1); 492 | if (FuncPosition) 493 | { 494 | lock (_lockAppend) 495 | Position = offset + iRead; 496 | } 497 | if (iRead != 1) 498 | return 0; 499 | value = aValue[0]; 500 | DeleteRecId = aDel[0]; 501 | return iRead; 502 | } 503 | ///////////////////////////////////////////// 504 | public virtual int Read(TImsId offset, out T value) 505 | { 506 | value = default(T); 507 | if ((FuncPosition) && (offset == OFFSET_POSITION)) 508 | offset = (TImsId)Position; 509 | if ((!CanRead) || (offset < 0) || (offset >= Length)) 510 | return 0; 511 | 512 | T[] aValue = new T[1]; 513 | int iRead = _BlockCopyInternal(true, offset, aValue, null, 0, 1); 514 | if (FuncPosition) 515 | { 516 | lock (_lockAppend) 517 | Position = offset + iRead; 518 | } 519 | if (iRead != 1) 520 | return 0; 521 | value = aValue[0]; 522 | return iRead; 523 | } 524 | ///////////////////////////////////////////// 525 | public virtual int Read(TImsId offset, out T[] aValue, int count) 526 | { 527 | if (_bFuncException) 528 | { 529 | if ((count <= 0) || (count > UInt16.MaxValue)) 530 | throw new ArgumentOutOfRangeException(nameof(count)); 531 | } 532 | aValue = new T[count]; 533 | return Read(offset, aValue, null, 0, (UInt16)count); 534 | } 535 | ///////////////////////////////////////////// 536 | public virtual int Read(TImsId offset, out T[] aValue, out TImsId[] aDel, int count) 537 | { 538 | if (_bFuncException) 539 | { 540 | if ((count <= 0) || (count > UInt16.MaxValue)) 541 | throw new ArgumentOutOfRangeException(nameof(count)); 542 | } 543 | aValue = new T[count]; 544 | aDel = new TImsId[count]; 545 | return Read(offset, aValue, aDel, 0, (UInt16)count); 546 | } 547 | ///////////////////////////////////////////// 548 | public virtual int Read(TImsId offset, T[] aValue) 549 | { 550 | if (_bFuncException) 551 | { 552 | if (aValue == null) 553 | throw new ArgumentOutOfRangeException(nameof(aValue)); 554 | if ((aValue.Length == 0) || (aValue.Length > UInt16.MaxValue)) 555 | throw new ArgumentOutOfRangeException(nameof(aValue.Length)); 556 | } 557 | return Read(offset, aValue, null, 0, (UInt16)aValue.Length); 558 | } 559 | ///////////////////////////////////////////// 560 | public virtual int Read(TImsId offset, T[] aValue, int count) 561 | { 562 | if (_bFuncException) 563 | { 564 | if (aValue == null) 565 | throw new ArgumentOutOfRangeException(nameof(aValue)); 566 | if ((aValue.Length == 0) || (aValue.Length > UInt16.MaxValue)) 567 | throw new ArgumentOutOfRangeException(nameof(aValue.Length)); 568 | if ((count <= 0) || (count > UInt16.MaxValue)) 569 | throw new ArgumentOutOfRangeException(nameof(count)); 570 | } 571 | return Read(offset, aValue, null, 0, (UInt16)count); 572 | } 573 | ///////////////////////////////////////////// 574 | public virtual int Read(TImsId offset, T[] aValue, TImsId[] aDel, int count) 575 | { 576 | if (_bFuncException) 577 | { 578 | if (aValue == null) 579 | throw new ArgumentOutOfRangeException(nameof(aValue)); 580 | if ((aValue.Length == 0) || (aValue.Length > UInt16.MaxValue)) 581 | throw new ArgumentOutOfRangeException(nameof(aValue.Length)); 582 | if ((count <= 0) || (count > UInt16.MaxValue)) 583 | throw new ArgumentOutOfRangeException(nameof(count)); 584 | } 585 | return Read(offset, aValue, aDel, 0, (UInt16)count); 586 | } 587 | ///////////////////////////////////////////// 588 | public virtual int Read(Transaction[] aTrans, int index, UInt16 count) 589 | { 590 | if (!CanRead) 591 | return 0; 592 | 593 | if (_bFuncException) 594 | { 595 | if (aTrans == null) 596 | throw new ArgumentOutOfRangeException(nameof(aTrans)); 597 | if ((index < 0) || (index >= aTrans.Length)) 598 | throw new ArgumentOutOfRangeException(nameof(index)); 599 | if ((count == 0) || (count + index > aTrans.Length)) 600 | throw new ArgumentOutOfRangeException(nameof(count)); 601 | } 602 | 603 | int iRead = 0; 604 | for (int pr = index; pr < index + count; pr++) 605 | { 606 | UInt16 iCount = aTrans[pr].keyCount; 607 | if ( (iCount > 0) && (iCount <= UInt16.MaxValue) && 608 | (aTrans[pr].keyPos >= 0) && (aTrans[pr].keyPos + iCount <= Length) ) 609 | { 610 | aTrans[pr].valueARec = new T[iCount]; 611 | if (_BlockCopyInternal(true, aTrans[pr].keyPos, aTrans[pr].valueARec, null, 0, iCount) == iCount) 612 | { 613 | aTrans[pr].valueOK = true; 614 | iRead++; 615 | } 616 | else 617 | { 618 | aTrans[pr].valueARec = null; 619 | aTrans[pr].valueOK = false; 620 | } 621 | } 622 | else 623 | { 624 | aTrans[pr].valueARec = null; 625 | aTrans[pr].valueOK = false; 626 | } 627 | } 628 | return iRead; 629 | } 630 | ///////////////////////////////////////////// 631 | public virtual int Read(TImsId offset, T[] aValue, TImsId[] aDel, int index, UInt16 count) 632 | { 633 | if (!CanRead) 634 | return 0; 635 | 636 | if (_bFuncException) 637 | { 638 | if (aValue == null) 639 | throw new ArgumentOutOfRangeException(nameof(aValue)); 640 | if ((index < 0) || (index >= aValue.Length)) 641 | throw new ArgumentOutOfRangeException(nameof(index)); 642 | if ((count == 0) || (count + index > aValue.Length)) 643 | throw new ArgumentOutOfRangeException(nameof(count)); 644 | } 645 | 646 | long lengthTemp = Length; 647 | if ((FuncPosition) && (offset == OFFSET_POSITION)) 648 | offset = (TImsId)Position; 649 | if (offset == lengthTemp) // foreach must return 0 650 | return 0; 651 | if ((offset < 0) || (offset > lengthTemp)) 652 | throw new ArgumentOutOfRangeException(nameof(offset)); 653 | 654 | if (offset + count > lengthTemp) 655 | count = (UInt16)(lengthTemp - offset); 656 | int iRead = _BlockCopyInternal(true, offset, aValue, aDel, index, count); 657 | if (FuncPosition) 658 | { 659 | lock (_lockAppend) 660 | Position = offset + iRead; 661 | } 662 | return iRead; 663 | } 664 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 665 | ///////////////////////////////////////////// ReadNoLock ////////////////////////////////////////////////////// 666 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 667 | public virtual int ReadNoLock(TImsId offset, out T value) 668 | { 669 | value = default(T); 670 | if ((!CanRead) || (offset < 0) || (offset >= Length)) 671 | return 0; 672 | 673 | T[] aValue = new T[1]; 674 | int iRead = _BlockReadNoLockInternal(offset, aValue, null, 0, 1); 675 | if (iRead != 1) 676 | return 0; 677 | value = aValue[0]; 678 | return iRead; 679 | } 680 | ///////////////////////////////////////////// 681 | public virtual int ReadNoLock(TImsId offset, out T value, out TImsId DeleteRecId) 682 | { 683 | value = default(T); 684 | DeleteRecId = NoDelete; 685 | if ((!CanRead) || (offset < 0) || (offset >= Length)) 686 | return 0; 687 | 688 | T[] aValue = new T[1]; 689 | TImsId[] aDel = new TImsId[1]; 690 | int iRead = _BlockReadNoLockInternal(offset, aValue, aDel, 0, 1); 691 | if (iRead != 1) 692 | return 0; 693 | value = aValue[0]; 694 | DeleteRecId = aDel[0]; 695 | return iRead; 696 | } 697 | ///////////////////////////////////////////// 698 | public virtual int ReadNoLock(TImsId offset, out T[] aValue, UInt16 count) 699 | { 700 | if ((!CanRead) || (offset < 0) || (offset >= Length)) 701 | { 702 | aValue = new T[0]; 703 | return 0; 704 | } 705 | 706 | aValue = new T[count]; 707 | int iRead = _BlockReadNoLockInternal(offset, aValue, null, 0, 1); 708 | if (iRead <= 0) 709 | { 710 | aValue = new T[0]; 711 | return 0; 712 | } 713 | return iRead; 714 | } 715 | ///////////////////////////////////////////// 716 | public virtual int ReadNoLock(TImsId offset, out T[] aValue, out TImsId[] aDel, UInt16 count) 717 | { 718 | if ((!CanRead) || (offset < 0) || (offset >= Length)) 719 | { 720 | aValue = new T[0]; 721 | aDel = new TImsId[0]; 722 | return 0; 723 | } 724 | 725 | aValue = new T[count]; 726 | aDel = new TImsId[count]; 727 | int iRead = _BlockReadNoLockInternal(offset, aValue, aDel, 0, count); 728 | if (iRead <= 0) 729 | { 730 | aValue = new T[0]; 731 | aDel = new TImsId[0]; 732 | return 0; 733 | } 734 | return iRead; 735 | } 736 | ///////////////////////////////////////////// 737 | public virtual int ReadNoLock(TImsId offset, T[] aValue, TImsId[] aDel, int index, UInt16 count) 738 | { 739 | if (!CanRead) 740 | return 0; 741 | 742 | if (_bFuncException) 743 | { 744 | if (aValue == null) 745 | throw new ArgumentOutOfRangeException(nameof(aValue)); 746 | if ((index < 0) || (index >= aValue.Length)) 747 | throw new ArgumentOutOfRangeException(nameof(index)); 748 | if ((count == 0) || (count + index > aValue.Length)) 749 | throw new ArgumentOutOfRangeException(nameof(count)); 750 | } 751 | 752 | long lengthTemp = Length; 753 | if ((FuncPosition) && (offset == OFFSET_POSITION)) 754 | offset = (TImsId)Position; 755 | if (offset == lengthTemp) // foreach must return 0 756 | return 0; 757 | if ((offset < 0) || (offset > lengthTemp)) 758 | throw new ArgumentOutOfRangeException(nameof(offset)); 759 | 760 | if (offset + count > lengthTemp) 761 | count = (UInt16)(lengthTemp - offset); 762 | int iRead = _BlockReadNoLockInternal(offset, aValue, aDel, index, count); 763 | if (FuncPosition) 764 | { 765 | lock (_lockAppend) 766 | Position = offset + iRead; 767 | } 768 | return iRead; 769 | } 770 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 771 | ///////////////////////////////////////////// Seek, SetLength ////////////////////////////////////////////////////// 772 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 773 | public override long Seek(long deltaOffset, SeekOrigin origin) 774 | { 775 | if (!FuncPosition) 776 | throw new NotImplementedException("Cannot Seek() to this FcsInmemStream."); 777 | 778 | if (!CanSeek) 779 | return OFFSET_ERROR; 780 | 781 | long tempPosition = OFFSET_ERROR; 782 | switch (origin) 783 | { 784 | case SeekOrigin.Begin: 785 | { 786 | if (deltaOffset < 0) 787 | return OFFSET_ERROR; 788 | tempPosition = unchecked(deltaOffset); 789 | break; 790 | } 791 | case SeekOrigin.Current: 792 | { 793 | tempPosition = unchecked(Position + deltaOffset); 794 | break; 795 | } 796 | case SeekOrigin.End: 797 | { 798 | tempPosition = unchecked(Length + deltaOffset); 799 | break; 800 | } 801 | default: 802 | throw new ArgumentException(nameof(origin)); 803 | } 804 | if ((tempPosition < 0) || (tempPosition >= Length)) 805 | return OFFSET_ERROR; 806 | lock (_lockAppend) 807 | Position = tempPosition; 808 | return Position; 809 | } 810 | ///////////////////////////////////////////// 811 | public override void SetLength(long value) 812 | { 813 | throw new NotImplementedException("Cannot SetLength() to this FcsInmemStream."); 814 | } 815 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 816 | ///////////////////////////////////////////// Write ////////////////////////////////////////////////////// 817 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 818 | public override void Write(byte[] buffer, int offset, int count) 819 | { 820 | throw new NotImplementedException("Cannot Write() to this FcsInmemStream."); 821 | } 822 | ///////////////////////////////////////////// 823 | public virtual int Write(T value) 824 | { 825 | if (FuncPosition) 826 | return Write(OFFSET_POSITION, value); 827 | return 0; 828 | } 829 | ///////////////////////////////////////////// 830 | public virtual int Write(T[] aValue) 831 | { 832 | if (FuncPosition) 833 | return Write(OFFSET_POSITION, aValue); 834 | return 0; 835 | } 836 | ///////////////////////////////////////////// 837 | public virtual int Write(long offset, T value) 838 | { 839 | T[] aValue = new T[1]; 840 | aValue[0] = value; 841 | return Write(offset, aValue, null, 0, 1); 842 | } 843 | ///////////////////////////////////////////// 844 | public virtual int Write(long offset, T value, TImsId DeleteRecId) 845 | { 846 | T[] aValue = new T[1]; 847 | aValue[0] = value; 848 | TImsId[] aDel = new TImsId[1]; 849 | aDel[0] = DeleteRecId; 850 | return Write(offset, aValue, aDel, 0, 1); 851 | } 852 | ///////////////////////////////////////////// 853 | public virtual int Write(long offset, T[] aValue) 854 | { 855 | if (_bFuncException) 856 | { 857 | if (aValue == null) 858 | throw new ArgumentOutOfRangeException(nameof(aValue)); 859 | if ((aValue.Length == 0) || (aValue.Length > UInt16.MaxValue)) 860 | throw new ArgumentOutOfRangeException(nameof(aValue.Length)); 861 | } 862 | return Write(offset, aValue, null, 0, (UInt16)aValue.Length); 863 | } 864 | ///////////////////////////////////////////// 865 | public virtual int Write(long offset, T[] aValue, int count) 866 | { 867 | if (_bFuncException) 868 | { 869 | if (aValue == null) 870 | throw new ArgumentOutOfRangeException(nameof(aValue)); 871 | if ((aValue.Length == 0) || (aValue.Length > UInt16.MaxValue)) 872 | throw new ArgumentOutOfRangeException(nameof(aValue.Length)); 873 | if ((count <= 0) || (count > UInt16.MaxValue)) 874 | throw new ArgumentOutOfRangeException(nameof(count)); 875 | } 876 | return Write(offset, aValue, null, 0, (UInt16)count); 877 | } 878 | ///////////////////////////////////////////// 879 | public virtual int Write(Transaction[] aTrans, int index, UInt16 count) 880 | { 881 | if (!CanWrite) 882 | return 0; 883 | 884 | if (_bFuncException) 885 | { 886 | if (aTrans == null) 887 | throw new ArgumentOutOfRangeException(nameof(aTrans)); 888 | if ((index < 0) || (index >= aTrans.Length)) 889 | throw new ArgumentOutOfRangeException(nameof(index)); 890 | if ((count == 0) || (count + index > aTrans.Length)) 891 | throw new ArgumentOutOfRangeException(nameof(count)); 892 | } 893 | 894 | int iWrite = 0; 895 | for (int pr = index; pr < index + count; pr++) 896 | { 897 | UInt16 iCount = aTrans[pr].keyCount; 898 | if ((iCount > 0) && (iCount <= UInt16.MaxValue) && 899 | (aTrans[pr].keyPos >= 0) && (aTrans[pr].keyPos + iCount <= Length)) 900 | { 901 | aTrans[pr].valueARec = new T[iCount]; 902 | if (_BlockCopyInternal(false, aTrans[pr].keyPos, aTrans[pr].valueARec, null, 0, iCount) == iCount) 903 | { 904 | aTrans[pr].valueOK = true; 905 | iWrite++; 906 | } 907 | else 908 | { 909 | aTrans[pr].valueARec = null; 910 | aTrans[pr].valueOK = false; 911 | } 912 | } 913 | else 914 | { 915 | aTrans[pr].valueARec = null; 916 | aTrans[pr].valueOK = false; 917 | } 918 | } 919 | return iWrite; 920 | } 921 | ///////////////////////////////////////////// 922 | public virtual int Write(long offset, T[] aValue, TImsId[] aDel, int index, UInt16 count) 923 | { 924 | if (!CanWrite) 925 | return 0; 926 | 927 | if (_bFuncException) 928 | { 929 | if (aValue == null) 930 | throw new ArgumentOutOfRangeException(nameof(aValue)); 931 | if ((index < 0) || (index >= aValue.Length)) 932 | throw new ArgumentOutOfRangeException(nameof(index)); 933 | if ((count == 0) || (count + index > aValue.Length)) 934 | throw new ArgumentOutOfRangeException(nameof(count)); 935 | } 936 | 937 | if ((FuncPosition) && (offset == OFFSET_POSITION)) 938 | offset = Position; 939 | if ((offset < 0) || (offset + count > Length)) 940 | throw new ArgumentOutOfRangeException(nameof(offset)); 941 | 942 | int iWrite = _BlockCopyInternal(false, offset, aValue, aDel, index, count); 943 | if (FuncPosition) 944 | { 945 | lock (_lockAppend) 946 | Position = offset + iWrite; 947 | } 948 | return iWrite; 949 | } 950 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 951 | ///////////////////////////////////////////// Undelete ////////////////////////////////////////////////////// 952 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 953 | public virtual bool Undelete(long offset) 954 | { 955 | if (!_bRecDelete) 956 | return false; 957 | 958 | RecPage[] buffPageLocal = _recPage; 959 | if ((offset < 0) || (offset >= Length) || (!_RowColsOffset(buffPageLocal, offset, out int iRow, out int iCols))) 960 | throw new ArgumentOutOfRangeException(nameof(offset)); 961 | if (buffPageLocal[iRow].aDel == null) 962 | throw new ArgumentNullException("", "_bufferPage[iRow].aDel"); 963 | 964 | if (buffPageLocal[iRow].aDel[iCols] != 0) 965 | { 966 | buffPageLocal[iRow].aDel[iCols] = 0; 967 | return true; 968 | } 969 | return false; 970 | } 971 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 972 | ///////////////////////////////////////////// locals ////////////////////////////////////////////////////// 973 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 974 | private int _BlockCopyInternal(bool bReadArrayBuff, long srcOffset, T[] aRW, TImsId[] aDelRW, int aRWOffset, int count) 975 | { 976 | RecPage[] buffPageLocal = _recPage; 977 | if (!_RowColsOffset(buffPageLocal, srcOffset, out int iRow, out int iCols)) 978 | throw new ArgumentOutOfRangeException(nameof(srcOffset)); 979 | 980 | int iResult = 0; 981 | int iCount = _recPageCols - iCols; 982 | if (iCount > count) 983 | iCount = count; 984 | 985 | while (iCount > 0) 986 | { 987 | if (buffPageLocal[iRow].aRec == null) 988 | throw new ArgumentNullException("", "_bufferPage[iRow].aRec[]"); 989 | 990 | lock (buffPageLocal[iRow]) 991 | { 992 | if (bReadArrayBuff) 993 | { 994 | Array.Copy(buffPageLocal[iRow].aRec, iCols, aRW, aRWOffset, iCount); 995 | if ((aDelRW != null) && (buffPageLocal[iRow].aDel != null)) 996 | Array.Copy(buffPageLocal[iRow].aDel, iCols, aDelRW, aRWOffset, iCount); 997 | buffPageLocal[iRow].timeRead = DateTime.Now; 998 | } 999 | else 1000 | { 1001 | Array.Copy(aRW, aRWOffset, buffPageLocal[iRow].aRec, iCols, iCount); 1002 | if ((aDelRW != null) && (buffPageLocal[iRow].aDel != null)) 1003 | Array.Copy(aDelRW, aRWOffset, buffPageLocal[iRow].aDel, iCols, iCount); 1004 | buffPageLocal[iRow].timeWrite = DateTime.Now; 1005 | buffPageLocal[iRow].iUpdate++; 1006 | } 1007 | } 1008 | 1009 | iResult += iCount; 1010 | count -= iCount; 1011 | aRWOffset += iCount; 1012 | // nastavi iCount, iCols, iRows pro pripadne opakovani 1013 | if (count > _recPageCols) 1014 | iCount = _recPageCols; 1015 | else 1016 | iCount = count; 1017 | iCols = 0; 1018 | iRow++; 1019 | } 1020 | return iResult; 1021 | } 1022 | ///////////////////////////////////////////// 1023 | private int _BlockReadNoLockInternal(long srcOffset, T[] aRW, TImsId[] aDelRW, int aRWOffset, int count) 1024 | { 1025 | RecPage[] buffPageLocal = _recPage; 1026 | if (!_RowColsOffset(buffPageLocal, srcOffset, out int iRow, out int iCols)) 1027 | throw new ArgumentOutOfRangeException(nameof(srcOffset)); 1028 | 1029 | int iResult = 0; 1030 | int iCount = _recPageCols - iCols; 1031 | if (iCount > count) 1032 | iCount = count; 1033 | 1034 | while (iCount > 0) 1035 | { 1036 | if (buffPageLocal[iRow].aRec == null) 1037 | throw new ArgumentNullException("", "_bufferPage[iRow].aRec[]"); 1038 | 1039 | Array.Copy(buffPageLocal[iRow].aRec, iCols, aRW, aRWOffset, iCount); 1040 | if ((aDelRW != null) && (buffPageLocal[iRow].aDel != null)) 1041 | Array.Copy(buffPageLocal[iRow].aDel, iCols, aDelRW, aRWOffset, iCount); 1042 | buffPageLocal[iRow].timeRead = DateTime.Now; 1043 | 1044 | iResult += iCount; 1045 | count -= iCount; 1046 | aRWOffset += iCount; 1047 | // nastavi iCount, iCols, iRows pro pripadne opakovani 1048 | if (count > _recPageCols) 1049 | iCount = _recPageCols; 1050 | else 1051 | iCount = count; 1052 | iCols = 0; 1053 | iRow++; 1054 | } 1055 | return iResult; 1056 | } 1057 | ///////////////////////////////////////////// 1058 | private bool _RowColsOffset(RecPage[] buffPageLocal, long offset, out int iRow, out int iCols) 1059 | { 1060 | iRow = (int)(offset / _recPageCols); 1061 | iCols = (int)(offset % _recPageCols); 1062 | if ((iRow >= _recPageRowsCount) || (buffPageLocal == null)) 1063 | return false; 1064 | else 1065 | return true; 1066 | } 1067 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1068 | ///////////////////////////////////////////// IEnumerator ////////////////////////////////////////////////////// 1069 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1070 | private static int _imsEnumeratorCacheLen = 32; 1071 | public static int ImsEnumeratorCacheLen 1072 | { 1073 | get => _imsEnumeratorCacheLen; 1074 | set 1075 | { 1076 | if (value < 16) 1077 | _imsEnumeratorCacheLen = 16; 1078 | else if (value > 1024) 1079 | _imsEnumeratorCacheLen = 1024; 1080 | else 1081 | _imsEnumeratorCacheLen = value; 1082 | } 1083 | } 1084 | ///////////////////////////////////////////// 1085 | public FcsInmemStream.ImsEnumerator GetEnumeratorEx(TImsId posLo) 1086 | { 1087 | return new ImsEnumerator(this, posLo, -1); 1088 | } 1089 | ///////////////////////////////////////////// 1090 | public FcsInmemStream.ImsEnumerator GetEnumeratorEx(TImsId posLo, int countMax) 1091 | { 1092 | return new ImsEnumerator(this, posLo, countMax); 1093 | } 1094 | ///////////////////////////////////////////// 1095 | IEnumerator IEnumerable.GetEnumerator() 1096 | { 1097 | // call the generic version of the method 1098 | return GetEnumerator(); 1099 | } 1100 | ///////////////////////////////////////////// 1101 | public IEnumerator GetEnumerator() 1102 | { 1103 | return new ImsEnumerator(this, ErrorId, -1); 1104 | } 1105 | ///////////////////////////////////////////// 1106 | public class ImsEnumerator : IEnumerator 1107 | { 1108 | // constructor 1109 | private TImsId _posLo; 1110 | private int _countMax; 1111 | private FcsInmemStream _inmem; 1112 | // locals 1113 | private int _count; 1114 | private TImsId _pos; 1115 | private int _idx; 1116 | private int _len; 1117 | private UInt16 _cacheLen; 1118 | private T[] _aT; 1119 | ///////////////////////////////////////////// 1120 | public ImsEnumerator(FcsInmemStream inmem, TImsId posLo, int countMax) 1121 | { 1122 | _inmem = inmem ?? throw new NullReferenceException(); 1123 | _posLo = posLo; 1124 | _countMax = countMax; 1125 | Reset(); 1126 | } 1127 | ///////////////////////////////////////////// 1128 | public bool MoveNext() 1129 | { 1130 | if (_count == 0) 1131 | return false; 1132 | else if (_count > 0) 1133 | _count--; 1134 | 1135 | int iRead = 1; 1136 | if ((_idx >= 0) && (_idx < _len)) 1137 | _idx++; 1138 | else 1139 | { 1140 | iRead = _inmem.Read(_pos, _aT, null, 0, _cacheLen); 1141 | _pos += (TImsId)iRead; 1142 | _idx = 0; 1143 | _len = iRead - 1; 1144 | } 1145 | return (iRead > 0); 1146 | } 1147 | ///////////////////////////////////////////// 1148 | public T Current => _aT[_idx]; 1149 | ///////////////////////////////////////////// 1150 | object IEnumerator.Current => _aT[_idx]; 1151 | ///////////////////////////////////////////// 1152 | public void Dispose() 1153 | { 1154 | _aT = null; 1155 | _inmem = null; 1156 | } 1157 | ///////////////////////////////////////////// 1158 | public void Reset() 1159 | { 1160 | _count = _countMax; 1161 | if (_posLo < 0) 1162 | _pos = 0; 1163 | else 1164 | _pos = _posLo; 1165 | if ( (_pos > _inmem.Length) || ((_count > 0) && (_pos + _count > _inmem.Length)) ) 1166 | throw new ArgumentOutOfRangeException(nameof(_posLo)); 1167 | _idx = -1; 1168 | _len = 0; 1169 | _cacheLen = (UInt16)FcsInmemStream.ImsEnumeratorCacheLen; 1170 | _aT = new T[_cacheLen]; 1171 | } 1172 | } 1173 | } 1174 | } -------------------------------------------------------------------------------- /FriendlyCSharp.Git.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.26923.0 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FriendlyCSharp.Databases", "FriendlyCSharp.Databases\FriendlyCSharp.Databases.csproj", "{025F885E-8B28-410E-8059-EF5FE70EE1C7}" 6 | EndProject 7 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BtnEnumerator.Multi.sample", "Samples\BtnEnumerator.Multi.sample\BtnEnumerator.Multi.sample.csproj", "{A8A0F38B-D324-4EC3-B87E-8731773E052C}" 8 | EndProject 9 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FcsInmemStream.Multi.sample", "Samples\FcsInmemStream.Multi.sample\FcsInmemStream.Multi.sample.csproj", "{58D9270A-D1CF-4CB2-8A0F-222A99B906ED}" 10 | EndProject 11 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FcsFastBTreeN.Multi.benchmark", "Samples\FcsFastBTreeN.Multi.benchmark\FcsFastBTreeN.Multi.benchmark.csproj", "{9EFD0AF3-3F32-4ECA-8D1B-A635928F278D}" 12 | EndProject 13 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultipleKeys.Multi.sample", "Samples\MultipleKeys.Multi.sample\MultipleKeys.Multi.sample.csproj", "{8438A9C7-1A14-46A6-9664-15FEBA8E108B}" 14 | EndProject 15 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{4657E7EB-D8BC-4ABA-BA7D-D977C684C2F4}" 16 | EndProject 17 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DuplicityKeys.Multi.sample", "Samples\DuplicityKeys.Multi.sample\DuplicityKeys.Multi.sample.csproj", "{6D7333A7-D3D4-4655-B9AF-A79EDE7A8BCF}" 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|Any CPU = Debug|Any CPU 22 | Release|Any CPU = Release|Any CPU 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {025F885E-8B28-410E-8059-EF5FE70EE1C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {025F885E-8B28-410E-8059-EF5FE70EE1C7}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {025F885E-8B28-410E-8059-EF5FE70EE1C7}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {025F885E-8B28-410E-8059-EF5FE70EE1C7}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {A8A0F38B-D324-4EC3-B87E-8731773E052C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {A8A0F38B-D324-4EC3-B87E-8731773E052C}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {A8A0F38B-D324-4EC3-B87E-8731773E052C}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {A8A0F38B-D324-4EC3-B87E-8731773E052C}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {58D9270A-D1CF-4CB2-8A0F-222A99B906ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {58D9270A-D1CF-4CB2-8A0F-222A99B906ED}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {58D9270A-D1CF-4CB2-8A0F-222A99B906ED}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {58D9270A-D1CF-4CB2-8A0F-222A99B906ED}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {9EFD0AF3-3F32-4ECA-8D1B-A635928F278D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {9EFD0AF3-3F32-4ECA-8D1B-A635928F278D}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {9EFD0AF3-3F32-4ECA-8D1B-A635928F278D}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {9EFD0AF3-3F32-4ECA-8D1B-A635928F278D}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {8438A9C7-1A14-46A6-9664-15FEBA8E108B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {8438A9C7-1A14-46A6-9664-15FEBA8E108B}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {8438A9C7-1A14-46A6-9664-15FEBA8E108B}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {8438A9C7-1A14-46A6-9664-15FEBA8E108B}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {6D7333A7-D3D4-4655-B9AF-A79EDE7A8BCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 46 | {6D7333A7-D3D4-4655-B9AF-A79EDE7A8BCF}.Debug|Any CPU.Build.0 = Debug|Any CPU 47 | {6D7333A7-D3D4-4655-B9AF-A79EDE7A8BCF}.Release|Any CPU.ActiveCfg = Release|Any CPU 48 | {6D7333A7-D3D4-4655-B9AF-A79EDE7A8BCF}.Release|Any CPU.Build.0 = Release|Any CPU 49 | EndGlobalSection 50 | GlobalSection(SolutionProperties) = preSolution 51 | HideSolutionNode = FALSE 52 | EndGlobalSection 53 | GlobalSection(NestedProjects) = preSolution 54 | {A8A0F38B-D324-4EC3-B87E-8731773E052C} = {4657E7EB-D8BC-4ABA-BA7D-D977C684C2F4} 55 | {58D9270A-D1CF-4CB2-8A0F-222A99B906ED} = {4657E7EB-D8BC-4ABA-BA7D-D977C684C2F4} 56 | {9EFD0AF3-3F32-4ECA-8D1B-A635928F278D} = {4657E7EB-D8BC-4ABA-BA7D-D977C684C2F4} 57 | {8438A9C7-1A14-46A6-9664-15FEBA8E108B} = {4657E7EB-D8BC-4ABA-BA7D-D977C684C2F4} 58 | {6D7333A7-D3D4-4655-B9AF-A79EDE7A8BCF} = {4657E7EB-D8BC-4ABA-BA7D-D977C684C2F4} 59 | EndGlobalSection 60 | GlobalSection(ExtensibilityGlobals) = postSolution 61 | SolutionGuid = {E25EA411-3B16-44B4-9FFA-A375A06F46F7} 62 | EndGlobalSection 63 | EndGlobal 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | FriendlyCSharp.Databases 2 | Copyright (c) KUBDAT & inmem, s.r.o. All rights reserved. 3 | --------------------------------------------------------- 4 | 5 | Apache License 6 | Version 2.0, January 2004 7 | http://www.apache.org/licenses/ 8 | 9 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 10 | 11 | 1. Definitions. 12 | 13 | "License" shall mean the terms and conditions for use, reproduction, 14 | and distribution as defined by Sections 1 through 9 of this document. 15 | 16 | "Licensor" shall mean the copyright owner or entity authorized by 17 | the copyright owner that is granting the License. 18 | 19 | "Legal Entity" shall mean the union of the acting entity and all 20 | other entities that control, are controlled by, or are under common 21 | control with that entity. For the purposes of this definition, 22 | "control" means (i) the power, direct or indirect, to cause the 23 | direction or management of such entity, whether by contract or 24 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 25 | outstanding shares, or (iii) beneficial ownership of such entity. 26 | 27 | "You" (or "Your") shall mean an individual or Legal Entity 28 | exercising permissions granted by this License. 29 | 30 | "Source" form shall mean the preferred form for making modifications, 31 | including but not limited to software source code, documentation 32 | source, and configuration files. 33 | 34 | "Object" form shall mean any form resulting from mechanical 35 | transformation or translation of a Source form, including but 36 | not limited to compiled object code, generated documentation, 37 | and conversions to other media types. 38 | 39 | "Work" shall mean the work of authorship, whether in Source or 40 | Object form, made available under the License, as indicated by a 41 | copyright notice that is included in or attached to the work 42 | (an example is provided in the Appendix below). 43 | 44 | "Derivative Works" shall mean any work, whether in Source or Object 45 | form, that is based on (or derived from) the Work and for which the 46 | editorial revisions, annotations, elaborations, or other modifications 47 | represent, as a whole, an original work of authorship. For the purposes 48 | of this License, Derivative Works shall not include works that remain 49 | separable from, or merely link (or bind by name) to the interfaces of, 50 | the Work and Derivative Works thereof. 51 | 52 | "Contribution" shall mean any work of authorship, including 53 | the original version of the Work and any modifications or additions 54 | to that Work or Derivative Works thereof, that is intentionally 55 | submitted to Licensor for inclusion in the Work by the copyright owner 56 | or by an individual or Legal Entity authorized to submit on behalf of 57 | the copyright owner. For the purposes of this definition, "submitted" 58 | means any form of electronic, verbal, or written communication sent 59 | to the Licensor or its representatives, including but not limited to 60 | communication on electronic mailing lists, source code control systems, 61 | and issue tracking systems that are managed by, or on behalf of, the 62 | Licensor for the purpose of discussing and improving the Work, but 63 | excluding communication that is conspicuously marked or otherwise 64 | designated in writing by the copyright owner as "Not a Contribution." 65 | 66 | "Contributor" shall mean Licensor and any individual or Legal Entity 67 | on behalf of whom a Contribution has been received by Licensor and 68 | subsequently incorporated within the Work. 69 | 70 | 2. Grant of Copyright License. Subject to the terms and conditions of 71 | this License, each Contributor hereby grants to You a perpetual, 72 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 73 | copyright license to reproduce, prepare Derivative Works of, 74 | publicly display, publicly perform, sublicense, and distribute the 75 | Work and such Derivative Works in Source or Object form. 76 | 77 | 3. Grant of Patent License. Subject to the terms and conditions of 78 | this License, each Contributor hereby grants to You a perpetual, 79 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 80 | (except as stated in this section) patent license to make, have made, 81 | use, offer to sell, sell, import, and otherwise transfer the Work, 82 | where such license applies only to those patent claims licensable 83 | by such Contributor that are necessarily infringed by their 84 | Contribution(s) alone or by combination of their Contribution(s) 85 | with the Work to which such Contribution(s) was submitted. If You 86 | institute patent litigation against any entity (including a 87 | cross-claim or counterclaim in a lawsuit) alleging that the Work 88 | or a Contribution incorporated within the Work constitutes direct 89 | or contributory patent infringement, then any patent licenses 90 | granted to You under this License for that Work shall terminate 91 | as of the date such litigation is filed. 92 | 93 | 4. Redistribution. You may reproduce and distribute copies of the 94 | Work or Derivative Works thereof in any medium, with or without 95 | modifications, and in Source or Object form, provided that You 96 | meet the following conditions: 97 | 98 | (a) You must give any other recipients of the Work or 99 | Derivative Works a copy of this License; and 100 | 101 | (b) You must cause any modified files to carry prominent notices 102 | stating that You changed the files; and 103 | 104 | (c) You must retain, in the Source form of any Derivative Works 105 | that You distribute, all copyright, patent, trademark, and 106 | attribution notices from the Source form of the Work, 107 | excluding those notices that do not pertain to any part of 108 | the Derivative Works; and 109 | 110 | (d) If the Work includes a "NOTICE" text file as part of its 111 | distribution, then any Derivative Works that You distribute must 112 | include a readable copy of the attribution notices contained 113 | within such NOTICE file, excluding those notices that do not 114 | pertain to any part of the Derivative Works, in at least one 115 | of the following places: within a NOTICE text file distributed 116 | as part of the Derivative Works; within the Source form or 117 | documentation, if provided along with the Derivative Works; or, 118 | within a display generated by the Derivative Works, if and 119 | wherever such third-party notices normally appear. The contents 120 | of the NOTICE file are for informational purposes only and 121 | do not modify the License. You may add Your own attribution 122 | notices within Derivative Works that You distribute, alongside 123 | or as an addendum to the NOTICE text from the Work, provided 124 | that such additional attribution notices cannot be construed 125 | as modifying the License. 126 | 127 | You may add Your own copyright statement to Your modifications and 128 | may provide additional or different license terms and conditions 129 | for use, reproduction, or distribution of Your modifications, or 130 | for any such Derivative Works as a whole, provided Your use, 131 | reproduction, and distribution of the Work otherwise complies with 132 | the conditions stated in this License. 133 | 134 | 5. Submission of Contributions. Unless You explicitly state otherwise, 135 | any Contribution intentionally submitted for inclusion in the Work 136 | by You to the Licensor shall be under the terms and conditions of 137 | this License, without any additional terms or conditions. 138 | Notwithstanding the above, nothing herein shall supersede or modify 139 | the terms of any separate license agreement you may have executed 140 | with Licensor regarding such Contributions. 141 | 142 | 6. Trademarks. This License does not grant permission to use the trade 143 | names, trademarks, service marks, or product names of the Licensor, 144 | except as required for reasonable and customary use in describing the 145 | origin of the Work and reproducing the content of the NOTICE file. 146 | 147 | 7. Disclaimer of Warranty. Unless required by applicable law or 148 | agreed to in writing, Licensor provides the Work (and each 149 | Contributor provides its Contributions) on an "AS IS" BASIS, 150 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 151 | implied, including, without limitation, any warranties or conditions 152 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 153 | PARTICULAR PURPOSE. You are solely responsible for determining the 154 | appropriateness of using or redistributing the Work and assume any 155 | risks associated with Your exercise of permissions under this License. 156 | 157 | 8. Limitation of Liability. In no event and under no legal theory, 158 | whether in tort (including negligence), contract, or otherwise, 159 | unless required by applicable law (such as deliberate and grossly 160 | negligent acts) or agreed to in writing, shall any Contributor be 161 | liable to You for damages, including any direct, indirect, special, 162 | incidental, or consequential damages of any character arising as a 163 | result of this License or out of the use or inability to use the 164 | Work (including but not limited to damages for loss of goodwill, 165 | work stoppage, computer failure or malfunction, or any and all 166 | other commercial damages or losses), even if such Contributor 167 | has been advised of the possibility of such damages. 168 | 169 | 9. Accepting Warranty or Additional Liability. While redistributing 170 | the Work or Derivative Works thereof, You may choose to offer, 171 | and charge a fee for, acceptance of support, warranty, indemnity, 172 | or other liability obligations and/or rights consistent with this 173 | License. However, in accepting such obligations, You may act only 174 | on Your own behalf and on Your sole responsibility, not on behalf 175 | of any other Contributor, and only if You agree to indemnify, 176 | defend, and hold each Contributor harmless for any liability 177 | incurred by, or claims asserted against, such Contributor by reason 178 | of your accepting any such warranty or additional liability. 179 | 180 | END OF TERMS AND CONDITIONS 181 | 182 | APPENDIX: How to apply the Apache License to your work. 183 | 184 | To apply the Apache License to your work, attach the following 185 | boilerplate notice, with the fields enclosed by brackets "{}" 186 | replaced with your own identifying information. (Don't include 187 | the brackets!) The text should be enclosed in the appropriate 188 | comment syntax for the file format. We also recommend that a 189 | file or class name and description of purpose be included on the 190 | same "printed page" as the copyright notice for easier 191 | identification within third-party archives. 192 | 193 | Copyright {yyyy} {name of copyright owner} 194 | 195 | Licensed under the Apache License, Version 2.0 (the "License"); 196 | you may not use this file except in compliance with the License. 197 | You may obtain a copy of the License at 198 | 199 | http://www.apache.org/licenses/LICENSE-2.0 200 | 201 | Unless required by applicable law or agreed to in writing, software 202 | distributed under the License is distributed on an "AS IS" BASIS, 203 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 204 | See the License for the specific language governing permissions and 205 | limitations under the License. 206 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FriendlyCSharp.Databases 2 | 3 | A library of cross platform C# data structures. Generic [**B-tree**](https://en.wikipedia.org/wiki/B-tree) written in C#, which can be replaced with NoSQL database stored in the memory of discharge requirements in real-time (*Firebase, Redis Cache, SAP HANA, Exadata, OLTP, etc.*). Basic information B-tree can be found in the book N. Wirth, Algorithms + data structures = programs and on Wikipedia, namely: 4 | >"*In computer science, a B-tree is a self-balancing tree data structure that keeps data sorted and allows searches, sequential access, insertions, and deletions in logarithmic time. The B-tree is a generalization of a binary search tree in that a node can have more than two children (Comer 1979, p. 123). Unlike self-balancing binary search trees, the B-tree is optimized for systems that read and write large blocks of data. B-trees are a good example of a data structure for external memory. It is commonly used in databases and filesystems. (...) Rudolf Bayer and Ed McCreight invented the B-tree while working at Boeing Research Labs in 1971 (Bayer & McCreight 1972), but they did not explain what, if anything, the B stands for.*" - [Wikipedia](https://en.wikipedia.org/wiki/B-tree). 5 | 6 |   7 | ## B-Tree generic class 8 | #### [FcsBTreeN<TKey, TValue>](FriendlyCSharp.Databases/BTreeN/FcsBTreeN.cs) \[where TKey : struct, IComparable<TKey>\] 9 | + `Methods:` BtnAddFirst, BtnCompares, BtnUpdates, BtnAdd, BtnDeleteAll, BtnFind, BtnFirst, BtnLast, BtnNext, BtnPrev, BtnSearch, BtnSearchPrev, BtnUpdate and BtnUsedKeys. 10 | #### [FcsFastBTreeN<TKey, TValue>](FriendlyCSharp.Databases/BTreeN/FcsFastBTreeN.cs) \[where TKey : struct, IComparable<TKey>\] 11 | + `Methods:` BtnAddFirst, BtnCompares, BtnUpdates, BtnAdd, BtnDeleteAll, BtnFind, BtnFirst, BtnLast, BtnNext, BtnPrev, BtnSearch, BtnSearchPrev, BtnUpdate and BtnUsedKeys. 12 | + `Methods:` BtnFastFind, BtnFastFirst, BtnFastLast, BtnFastNext, BtnFastPrev, BtnFastSearch, BtnFastSearchPrev. 13 | #### [FcsDuplValueFastBTreeN<TKey, TValue>](FriendlyCSharp.Databases/BTreeN/FcsDuplValueFastBTreeN.cs) \[where TKey : struct, IComparable<TKey>\] 14 | + `Methods:` BtnAddFirst, BtnCompares, BtnUpdates, BtnAdd, BtnDeleteAll, BtnFind, BtnFirst, BtnLast, BtnNext, BtnPrev, BtnSearch, BtnSearchPrev, BtnUpdate and BtnUsedKeys. 15 | + `Methods:` BtnFastFind, BtnFastFirst, BtnFastLast, BtnFastNext, BtnFastPrev, BtnFastSearch, BtnFastSearchPrev. 16 | #### [FcsKeyFastBTreeN<TKeyValue>](FriendlyCSharp.Databases/BTreeN/FcsKeyFastBTreeN.cs) \[where TKeyValue : struct\] 17 | + `Methods:` BtnAdd, BtnDeleteAll, BtnFind, BtnFirst, BtnLast, BtnNext, BtnPrev, BtnSearch, BtnSearchPrev, BtnUpdate and BtnUsedKeys. 18 | + `Methods:` BtnFastFind, BtnFastFirst, BtnFastLast, BtnFastNext, BtnFastPrev, BtnFastSearch, BtnFastSearchPrev. 19 | #### [FcsLockBTreeN<TKey, TValue>](FriendlyCSharp.Databases/BTreeN/FcsLockBTreeN.cs) \[where TKey : struct, IComparable<TKey>\] 20 | + `Methods:` BtnAddFirst, BtnCompares, BtnUpdates, BtnAdd, BtnDeleteAll, BtnFind, BtnFirst, BtnLast, BtnNext, BtnPrev, BtnSearch, BtnSearchPrev, BtnUpdate and BtnUsedKeys. 21 | #### [FcsFastLockBTreeN<TKey, TValue>](FriendlyCSharp.Databases/BTreeN/FcsFastLockBTreeN.cs) \[where TKey : struct, IComparable<TKey>\] 22 | + `Methods:` BtnAddFirst, BtnCompares, BtnUpdates, BtnAdd, BtnDeleteAll, BtnFind, BtnFirst, BtnLast, BtnNext, BtnPrev, BtnSearch, BtnSearchPrev, BtnUpdate and BtnUsedKeys. 23 | + `Methods:` BtnFastFind, BtnFastFirst, BtnFastLast, BtnFastNext, BtnFastPrev, BtnFastSearch, BtnFastSearchPrev. 24 | 25 | ### Samples 26 | * [BtnEnumerator.Multi.sample](Samples/BtnEnumerator.Multi.sample) 27 | * [FcsFastBTreeN.Multi.benchmark](Samples/FcsFastBTreeN.Multi.benchmark) 28 | * [MultipleKeys.Multi.sample](Samples/MultipleKeys.Multi.sample) 29 | * [DuplicityKeys.Multi.sample](Samples/DuplicityKeys.Multi.sample) 30 | 31 | ### Performance 32 | A [**B-tree**](https://en.wikipedia.org/wiki/B-tree) of order m is a tree which satisfies the following properties: 33 | 1. Every node has at most m children. 34 | 2. Every non-leaf node (except root) has at least ⌈m/2⌉ children. 35 | 3. The root has at least two children if it is not a leaf node. 36 | 4. A non-leaf node with k children contains k−1 keys. 37 | 5. All leaves appear in the same level. 38 | 39 | | generic class | sorted by key | duplicate keys | B-tree | locking records | 40 | | --- | :---: | :---: | :---: | :---: | 41 | | [**fastDB<...>**](http://www.inmem.cz/inmem_letak.pdf) | **Yes** | **Yes** | **Yes** | **Yes** | 42 | | [**FcsBTreeN<TKey, TValue>**](#fcsbtreentkey-tvalue-where-tkey--struct-icomparabletkey) | **Yes** | **Yes** | **Yes** | No | 43 | | [**FcsFastBTreeN<TKey, TValue>**](#fcsfastbtreentkey-tvalue-where-tkey--struct-icomparabletkey) | **Yes** | **Yes** | **Yes** | No | 44 | | [**FcsLockBTreeN<TKey, TValue>**](#fcslockbtreentkey-tvalue-where-tkey--struct-icomparabletkey) | **Yes** | **Yes** | **Yes** | No | 45 | | [**FcsFastLockBTreeN<TKey, TValue>**](#fcsfastlockbtreentkey-tvalue-where-tkey--struct-icomparabletkey) | **Yes** | **Yes** | **Yes** | No | 46 | | [**FcsKeyFastBTreeN<TKeyValue>**](#fcskeyfastbtreentkeyvalue-where-tkeyvalue--struct---new-200-preview2-install) | **Yes** | **Yes** | **Yes** | No | 47 | | SortedSet<KeyValuePair<TKey, TValue>> | **Yes** | No | No | No | 48 | | HashSet<KeyValuePair<TKey, TValue>> | No | No | No | No | 49 | | Dictionary<TKey, TValue> | No | No | No | No | 50 | 51 | ### Benchmark 52 | The benchmark was configured as follows: 53 | * CPU: Intel Xeon E3-1245 @ 3.3 GHz; 54 | * Windows 10, 64bit, .NET Standard 2.0 55 | * 4x4GB DDR3 Kingston @ 1333 MHz 56 | 57 | >**Adding in a single thread:** 58 | 59 | | <int, uint> | sorted by key | iteration | total (ms) | one time (ns) | speed | RAM (MB) | occupied | 60 | | --- | :---: | ---: | ---: | ---: | :---: | :---: | :---: | 61 | | [**FcsFastBTreeN<...>**](#fcsfastbtreentkey-tvalue) | **Yes** | 10,000,000 | **6,185** | **619** | **100%** | **131** | **100%** | 62 | | SortedSet<...> | **Yes** | 10,000,000 | ~~ 19,443 ~~ | ~~ 1,944 ~~ | ~~ 32% ~~ | ~~ 458 ~~ |  358%  | 63 | | HashSet<...> | No | 10,000,000 | 2,017 | 202 | 307% | 229 | 179% | 64 | | Dictionary<...> | No | 10,000,000 | 1,378 | 138 | 449% | 229 | 179% | 65 | 66 | >**Foreach in a single thread:** 67 | 68 | | <int, uint> | sorted by key | iteration | total (ms) | one time (ns) | speed | IOPS | 69 | | --- | :---: | ---: | ---: | ---: | :---: | ---: | 70 | | [**fastDB<...>**](http://www.inmem.cz/inmem_letak.pdf) | **Yes** | 10,000,000 | **100** | **10** | **200%** | **100**,000,000 | 71 | | [**FcsFastBTreeN<...>**](#fcsfastbtreentkey-tvalue) | **Yes** | 10,000,000 | **200** | **20** | **100%** | 50,000,000 | 72 | | SortedSet<...> | **Yes** | 10,000,000 | ~~ 1,230 ~~ | ~~ 123 ~~ | ~~ 16% ~~ | 8,000,000 | 73 | | HashSet<...> | No | 10,000,000 | 47.3 | 4,73 | 422% | **210**,000,000 | 74 | | Dictionary<...> | No | 10,000,000 | 86.5 | 8,65 | 231% | **115**,000,000 | 75 | 76 | ### Functions 77 | Various methods used throughout the library. 78 | 79 | #### Comparator 80 | Some data structures require a comparator method to automatically keep their elements sorted upon insertion. 81 | 82 | >Default comparator is initialized as follows: 83 | 84 | ```cs 85 | protected virtual int BtnCompares(TKey keyX, TKey keyY, object objCmp) 86 | { 87 | return keyX.CompareTo(keyY); 88 | } 89 | ``` 90 | 91 | >**Writing custom class with comparators is easy:** 92 | 93 | ```cs 94 | public class MyBtnKeyValue : FcsBTreeN 95 | { 96 | protected override bool BtnUpdates(int keyAdd, uint valueAdd, ref uint valueUpdates, object objUpdates) 97 | { 98 | valueUpdates++; 99 | return true; 100 | } 101 | ////////////////////////// 102 | protected override int BtnCompares(int keyX, int keyY, object objCmp) 103 | { 104 | return keyX - keyY; 105 | } 106 | ////////////////////////// 107 | public MyBtnKeyValue() : base() 108 | { 109 | } 110 | } 111 | ``` 112 | 113 | #### Iterator 114 | 115 | Tree gradually passes from the lowest, from the specified keys or higher. 116 | 117 | >Typical usage: 118 | 119 | ```cs 120 | foreach(KeyValuePair? btnKV in MyBtnKeyValue) 121 | { 122 | } 123 | ``` 124 | 125 | >Other usages: 126 | 127 | ```cs 128 | if (MyBtnKeyValue.BtnFirst(out btnKey, out btnValue) != null) 129 | { 130 | do 131 | { 132 | } 133 | while (MyBtnKeyValue.BtnNext(ref btnKey, out btnValue) != null) 134 | } 135 | ``` 136 | 137 | ```cs 138 | if (MyBtnKeyValue.BtnFind(btnKey, out btnValue) != null) 139 | { 140 | do 141 | { 142 | } 143 | while (MyBtnKeyValue.BtnNext(ref btnKey, out btnValue) != null) 144 | } 145 | ``` 146 | 147 | ```cs 148 | if (MyBtnKeyValue.BtnSearch(ref btnKey, out btnValue) != null) 149 | { 150 | do 151 | { 152 | } 153 | while (MyBtnKeyValue.BtnNext(ref btnKey, out btnValue) != null) 154 | } 155 | ``` 156 | 157 | #### Reverse Iterator 158 | 159 | The tree passes successively from the last or entered or lower than the specified key. 160 | 161 | >Typical usage of iteration in reverse: 162 | 163 | ```cs 164 | if (MyBtnKeyValue.BtnLast(out btnKey, out btnValue) != null) 165 | { 166 | do 167 | { 168 | } 169 | while (MyBtnKeyValue.BtnPrev(ref btnKey, out btnValue) != null) 170 | } 171 | ``` 172 | 173 | >Other usages: 174 | 175 | ```cs 176 | if (MyBtnKeyValue.BtnFind(btnKey, out btnValue) != null) 177 | { 178 | do 179 | { 180 | } 181 | while (MyBtnKeyValue.BtnPrev(ref btnKey, out btnValue) != null) 182 | } 183 | ``` 184 | 185 | ```cs 186 | if (MyBtnKeyValue.BtnSearchPrev(btnKey, out btnValue) != null) 187 | { 188 | do 189 | { 190 | } 191 | while (MyBtnKeyValue.BtnPrev(ref btnKey, out btnValue) != null) 192 | } 193 | ``` 194 | 195 | ### Searching 196 | 197 | Methods that seek the desired key and returns the key value pair or null. 198 | 199 | >**Find** 200 | 201 | The method finds the specified key and returns the key value pair or null. 202 | 203 | ```cs 204 | public virtual bool? BtnFind(TKey key, out TValue value) 205 | { 206 | } 207 | public virtual KeyValuePair? BtnFind(TKey key) 208 | { 209 | } 210 | ``` 211 | 212 | >**First** 213 | 214 | The method finds the first key and returns the key value pair or null. 215 | 216 | ```cs 217 | public virtual bool? BtnFirst(out TKey key, out TValue value) 218 | { 219 | } 220 | public virtual KeyValuePair? BtnFirst() 221 | { 222 | } 223 | ``` 224 | 225 | >**Last** 226 | 227 | The method finds the last key and returns the key value pair or null. 228 | 229 | ```cs 230 | public virtual bool? BtnLast(out TKey key, out TValue value) 231 | { 232 | } 233 | public virtual KeyValuePair? BtnLast() 234 | { 235 | } 236 | ``` 237 | 238 | >**Search** 239 | 240 | The method finds the specified key or the next higher and returns the key value pair or null. 241 | 242 | ```cs 243 | public virtual bool? BtnSearch(ref TKey key, out TValue value) 244 | { 245 | } 246 | public virtual KeyValuePair? BtnSearch(TKey key) 247 | { 248 | } 249 | ``` 250 | 251 | >**SearchPrev** 252 | 253 | The method finds the specified key or the previous and returns the key value pair or null. 254 | 255 | ```cs 256 | public virtual bool? BtnSearchPrev(ref TKey key, out TValue value) 257 | { 258 | } 259 | public virtual KeyValuePair? BtnSearchPrev(TKey key) 260 | { 261 | } 262 | ``` 263 | 264 |   265 | ## MemoryStream generic class 266 | #### [FcsInmemStream<T>](FriendlyCSharp.Databases/Storage/FcsInmemStream.cs) \[where T : struct, ICloneable\] 267 | + `Methods:` Append, Close, Length, Open, Position, Read, Seek, Write. 268 | 269 | ### Samples 270 | * [FcsInmemStream.Multi.sample](Samples/FcsInmemStream.Multi.sample) 271 | 272 | ### Benchmark 273 | The benchmark was configured as follows: 274 | * CPU: Intel Xeon E3-1245 @ 3.3 GHz; 275 | * Windows 10, 64bit, .NET Standard 2.0 276 | * 4x4 GB DDR3 Kingston @ 1333 MHz 277 | * Append, Read, Write (*cache 1,000 T*) and foreach (*cache 128 T*) 278 | 279 | | [FcsInmemStream<T>](FriendlyCSharp.Databases/Storage/FcsInmemStream.cs) | Append | Read | Write | foreach | 280 | | --- | ---: | ---: | ---: | ---: | 281 | | IOPS \[T = 8 Byte\] | **160**,000,000 | **800**,000,000 | **800**,000,000 | 80,000,000 | 282 | | IOPS \[T = 16 Byte\] | **140**,000,000 | **500**,000,000 | **400**,000,000 | 80,000,000 | 283 | | IOPS \[T = 32 Byte\] | 90,000,000 | **280**,000,000 | **280**,000,000 | 70,000,000 | 284 | | IOPS \[T = 64 Byte\] | 45,000,000 | **150**,000,000 | **150**,000,000 | 60,000,000 | 285 | | IOPS \[T = 128 Byte\] | 20,000,000 | 75,000,000 | 50,000,000 | 33,000,000 | 286 | | IOPS \[T = 256 Byte\] | 12,000,000 | 35,000,000 | 33,000,000 | 22,000,000 | 287 | | IOPS \[T = 1024 Byte\] | 3,000,000 | 8,000,000 | 8,000,000 | 6,000,000 | 288 | | IOPS \[T = 4096 Byte\] | 700,000 | 1,600,000 | 1,200,000 | 1,300,000 | 289 | 290 |    291 | ## INSTALL 292 | 293 | Instal Visual Studio 2017 version 15.4.0 preview 3.0 & .NET Core 2.0 & support for multiple target frameworks 294 | * [Pre-release Visual Studio 2017 | Visual Studio Preview](https://www.visualstudio.com/vs/preview/) 295 | * [Visual Studio 2017 (version 15.4 - Preview 3.0) Release Notes](https://www.visualstudio.com/en-us/news/releasenotes/vs2017-preview-relnotes) 296 | * [Announcing .NET Core 2.0](https://blogs.msdn.microsoft.com/dotnet/2017/08/14/announcing-net-core-2-0/) 297 | * [GitHUB .NET Core](https://github.com/dotnet/core/tree/master/release-notes) 298 | * [.NET Core 2.0 download](https://github.com/dotnet/core/blob/master/release-notes/download-archives/2.0.0-download.md) 299 | 300 | Install via Nuget Package Manager [version 2.0.0](https://www.nuget.org/packages/FriendlyCSharp.Databases/2.0.0) 301 | 302 | ``` 303 | PM> Install-Package FriendlyCSharp.Databases 304 | ``` 305 | 306 |   307 | ## LICENSE 308 | See the [LICENSE](LICENSE). 309 | -------------------------------------------------------------------------------- /Samples/BtnEnumerator.Multi.sample/BtnEnumerator.Multi.sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp2.0;net461 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Samples/BtnEnumerator.Multi.sample/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using FriendlyCSharp.Databases; 4 | 5 | namespace BtnEnumerator.Multi.sample 6 | { 7 | public class TestKV : FcsBTreeN 8 | { 9 | protected override bool BtnUpdates(int keyAdd, uint valueAdd, ref uint valueUpdates, object objUpdates) 10 | { 11 | valueUpdates++; 12 | return true; 13 | } 14 | ////////////////////////// 15 | protected override int BtnCompares(int keyX, int keyY, object objCmp) 16 | { 17 | // return less < 0, equal = 0, greater > 0 18 | return keyX - keyY; 19 | } 20 | ////////////////////////// 21 | public TestKV() : base(2) 22 | { 23 | } 24 | } 25 | 26 | class Program 27 | { 28 | static void Main(string[] args) 29 | { 30 | Console.OutputEncoding = System.Text.Encoding.UTF8; 31 | Console.WriteLine(String.Format("BtnEnumerator.Multi.sample, {0}", (IntPtr.Size == 4) ? "32 bit" : "64 bit")); 32 | Console.WriteLine("-----------------------------------"); 33 | 34 | uint uiCount = 1; 35 | TestKV btnTest = new TestKV(); 36 | // Build the tree 37 | btnTest.BtnAdd(20, uiCount); 38 | btnTest.BtnAdd(40, uiCount); 39 | btnTest.BtnAdd(10, uiCount); 40 | btnTest.BtnAdd(30, uiCount); 41 | btnTest.BtnAdd(15, uiCount); // 42 | btnTest.BtnAdd(35, uiCount); 43 | btnTest.BtnAdd(7, uiCount); 44 | btnTest.BtnAdd(26, uiCount); 45 | btnTest.BtnAdd(18, uiCount); 46 | btnTest.BtnAdd(22, uiCount); // 47 | btnTest.BtnAdd(5, uiCount); // 48 | btnTest.BtnAdd(42, uiCount); 49 | btnTest.BtnAdd(13, uiCount); 50 | btnTest.BtnAdd(46, uiCount); 51 | btnTest.BtnAdd(27, uiCount); 52 | btnTest.BtnAdd(27, uiCount); // duplicity call BtnUpdates() 53 | btnTest.BtnAdd(8, uiCount); 54 | btnTest.BtnAdd(32, uiCount); // 55 | btnTest.BtnAdd(38, uiCount); 56 | btnTest.BtnAdd(24, uiCount); 57 | btnTest.BtnAdd(27, uiCount); // duplicity call BtnUpdates() 58 | btnTest.BtnAdd(45, uiCount); 59 | btnTest.BtnAdd(25, uiCount); // 60 | 61 | // output: 5,7,8,10,13,15,18,20,22,24,25,26,27,30,32,35,38,40,42,45,46, 62 | foreach(KeyValuePair? keyValue in btnTest) 63 | Console.Write(keyValue.GetValueOrDefault().Key + ","); 64 | Console.WriteLine(); 65 | 66 | // output: 5,7,8,10,13,15,18,20,22,24,25,26, 67 | FcsBTreeN.BtnEnumerator btnEn = btnTest.GetEnumeratorEx(false, 12); 68 | while (btnEn.MoveNext()) 69 | Console.Write(btnEn.Current.Key + ","); 70 | btnEn.Dispose(); 71 | Console.WriteLine(); 72 | 73 | int keyLo = 22; 74 | int keyHi = 38; 75 | // output: 5,7,8,10,13,15,18,20,22,24,25,26,27,30,32,35,38, 76 | btnEn = btnTest.GetEnumeratorEx(default(int), keyHi, false); 77 | while (btnEn.MoveNext()) 78 | Console.Write(btnEn.Current.Key + ","); 79 | Console.WriteLine(); 80 | btnEn.Dispose(); 81 | 82 | // output: 22,24,25,26,27,30,32,35,38,40,42,45,46, 83 | btnEn = btnTest.GetEnumeratorEx(keyLo, default(int), false); 84 | while (btnEn.MoveNext()) 85 | Console.Write(btnEn.Current.Key + ","); 86 | Console.WriteLine(); 87 | btnEn.Dispose(); 88 | 89 | // output: 22,24,25,26,27,30,32,35,38, 90 | btnEn = btnTest.GetEnumeratorEx(keyLo, keyHi, false); 91 | while (btnEn.MoveNext()) 92 | Console.Write(btnEn.Current.Key + ","); 93 | Console.WriteLine(); 94 | // output: 22,24,25,26,27,30,32,35,38, 95 | btnEn.Reset(); 96 | while (btnEn.MoveNext()) 97 | Console.Write(btnEn.Current.Key + ","); 98 | Console.WriteLine(); 99 | btnEn.Dispose(); 100 | 101 | // output: 22,24,25,26,27, 102 | btnEn = btnTest.GetEnumeratorEx(keyLo, keyHi, false, 5); 103 | while (btnEn.MoveNext()) 104 | Console.Write(btnEn.Current.Key + ","); 105 | Console.WriteLine(); 106 | btnEn.Dispose(); 107 | 108 | // ---------- REVERSE ---------- 109 | Console.WriteLine("-----------------------------------"); 110 | // output: 46,45,42,40,38,35,32,30,27,26,25,24,22,20,18,15,13,10,8,7,5, 111 | btnEn = btnTest.GetEnumeratorEx(true); 112 | while (btnEn.MoveNext()) 113 | Console.Write(btnEn.Current.Key + ","); 114 | Console.WriteLine(); 115 | btnEn.Dispose(); 116 | 117 | // output: 46,45,42,40,38,35,32,30,27,26,25,24, 118 | btnEn = btnTest.GetEnumeratorEx(true, 12); 119 | while (btnEn.MoveNext()) 120 | Console.Write(btnEn.Current.Key + ","); 121 | Console.WriteLine(); 122 | btnEn.Dispose(); 123 | 124 | // output: 38,35,32,30,27,26,25,24,22,20,18,15,13,10,8,7,5, 125 | btnEn = btnTest.GetEnumeratorEx(default(int), keyHi, true); 126 | while (btnEn.MoveNext()) 127 | Console.Write(btnEn.Current.Key + ","); 128 | Console.WriteLine(); 129 | btnEn.Dispose(); 130 | 131 | // output: 46,45,42,40,38,35,32,30,27,26,25,24,22, 132 | btnEn = btnTest.GetEnumeratorEx(keyLo, default(int), true); 133 | while (btnEn.MoveNext()) 134 | Console.Write(btnEn.Current.Key + ","); 135 | Console.WriteLine(); 136 | btnEn.Dispose(); 137 | 138 | // output: 38,35,32,30,27,26,25,24,22, 139 | btnEn = btnTest.GetEnumeratorEx(keyLo, keyHi, true); 140 | while (btnEn.MoveNext()) 141 | Console.Write(btnEn.Current.Key + ","); 142 | Console.WriteLine(); 143 | btnEn.Dispose(); 144 | 145 | // output: 38,35,32,30,27, 146 | btnEn = btnTest.GetEnumeratorEx(keyLo, keyHi, true, 5); 147 | while (btnEn.MoveNext()) 148 | Console.Write(btnEn.Current.Key + ","); 149 | Console.WriteLine(); 150 | btnEn.Dispose(); 151 | 152 | Console.WriteLine("-----------------------------------"); 153 | Console.WriteLine("Key ENTER press."); 154 | Console.ReadLine(); 155 | } 156 | } 157 | } -------------------------------------------------------------------------------- /Samples/DuplicityKeys.Multi.sample/DuplicityKeys.Multi.sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp2.0;net461 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Samples/DuplicityKeys.Multi.sample/Program.cs: -------------------------------------------------------------------------------- 1 | using FriendlyCSharp.Databases; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace DuplicityKeys.Multi.sample 8 | { 9 | class Program 10 | { 11 | // 12 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 13 | private struct BtnKey 14 | { 15 | public string keyCity; 16 | public long keyId; 17 | //public DateTime key0; 18 | //public string key1; 19 | //public long key2; 20 | public int valueCount; 21 | public DateTime[] aValueDateTime; 22 | public uint[] aValueRand; 23 | // 24 | static int CmpBtnKey(BtnKey keyX, BtnKey keyY, object objCmp, object objCmp2) 25 | { 26 | // return < 0 (less), = 0 (equal), > 0 (greater) 27 | int iResult = String.Compare(keyX.keyCity, keyY.keyCity, StringComparison.Ordinal); 28 | if (iResult == 0) 29 | { 30 | iResult = keyX.keyId.CompareTo(keyY.keyId); 31 | //if (iResult == 0) 32 | //{ 33 | // iResult = DateTime.Compare(key0, keyY.key0); 34 | // if (iResult == 0) 35 | // { 36 | // iResult = string.Compare(key1, keyY.key1, true); 37 | // if (iResult == 0) 38 | // { 39 | // iResult = key2.CompareTo(keyY.key2); 40 | // } 41 | // } 42 | //} 43 | } 44 | return iResult; 45 | } 46 | // 47 | static bool FuncUpdate(BtnKey keyAdd, ref BtnKey keyUpdate, object objUpdate) 48 | { 49 | // Resize ? 50 | if ((keyUpdate.aValueDateTime.Length <= keyUpdate.valueCount) || (keyUpdate.aValueRand.Length <= keyUpdate.valueCount)) 51 | { 52 | if ((keyUpdate.aValueDateTime.Length >= 1024) || (keyUpdate.aValueRand.Length >= 1024)) 53 | { 54 | Array.Resize(ref keyUpdate.aValueDateTime, keyUpdate.aValueDateTime.Length + 1024); 55 | Array.Resize(ref keyUpdate.aValueRand, keyUpdate.aValueRand.Length + 1024); 56 | } 57 | else 58 | { 59 | Array.Resize(ref keyUpdate.aValueDateTime, keyUpdate.aValueDateTime.Length * 2); 60 | Array.Resize(ref keyUpdate.aValueRand, keyUpdate.aValueRand.Length * 2); 61 | } 62 | } 63 | // Update 64 | keyUpdate.aValueDateTime[keyUpdate.valueCount] = keyAdd.aValueDateTime[0]; 65 | keyUpdate.aValueRand[keyUpdate.valueCount] = keyAdd.aValueRand[0]; 66 | keyUpdate.valueCount++; 67 | return true; 68 | } 69 | // 70 | public static FcsKeyFastBTreeN CreateFcsKeyFastBTreeN() 71 | { 72 | return new FcsKeyFastBTreeN(CmpBtnKey, FuncUpdate, 32); 73 | } 74 | } 75 | // 76 | // 77 | // 78 | static void Main(string[] args) 79 | { 80 | Console.OutputEncoding = System.Text.Encoding.UTF8; 81 | Console.WriteLine(String.Format("DuplicityKeys.Milti.sample, {0}", (IntPtr.Size == 4) ? "32 bit" : "64 bit")); 82 | Console.WriteLine("-----------------------------------"); 83 | 84 | int max = 36000; 85 | string[] aCity = { "London", "Moscow", "Warsaw", "Berlin", "Paris", "Prague", "Brussels", "Vienna", "Zagreb", "Helsinki" }; 86 | int iPocetAdd = 0; 87 | Random r = new Random((int)DateTime.Now.Ticks); 88 | uint[] aRand = new uint[max]; 89 | var hashSetRand = new HashSet(); 90 | while (iPocetAdd < max) 91 | { 92 | uint rand = (uint)r.Next(0, Int32.MaxValue - 1); 93 | if (hashSetRand.Contains(rand) == false) 94 | { 95 | hashSetRand.Add(rand); 96 | aRand[iPocetAdd] = rand; 97 | iPocetAdd++; 98 | } 99 | } 100 | hashSetRand = null; 101 | long iMem = GC.GetTotalMemory(true); 102 | Console.WriteLine("UsedMemory {0,4} MB", iMem >> 20); 103 | long iMemOld = iMem; 104 | // 105 | // 106 | iPocetAdd = 0; 107 | Console.WriteLine("-----------------------------------"); 108 | Console.WriteLine("FcsFastBTreeN"); 109 | BtnKey key; 110 | key.aValueRand = new uint[1]; 111 | key.aValueDateTime = new DateTime[1]; 112 | FcsKeyFastBTreeN btnTest = BtnKey.CreateFcsKeyFastBTreeN(); 113 | var swFcsKV = Stopwatch.StartNew(); 114 | for (int iter = 0; iter < 100; iter++) 115 | { 116 | for (int idx = 0; idx < max; idx++) 117 | { 118 | key.keyCity = aCity[idx % aCity.Length]; 119 | key.keyId = idx % 1200; 120 | key.valueCount = 1; 121 | key.aValueRand[0] = aRand[idx]; 122 | key.aValueDateTime[0] = DateTime.Now; 123 | if (btnTest.BtnAdd(key) != null) 124 | iPocetAdd++; 125 | } 126 | } 127 | swFcsKV.Stop(); 128 | iMem = GC.GetTotalMemory(true); 129 | Console.WriteLine("UsedMemory {0,5} MB [{1,5:N1} s] | {3} keys | Δ {2,3} MB | {4,8:N0} ns | {5,10:N0} values | sizeT {6,2} Byte", iMem >> 20, swFcsKV.Elapsed.TotalSeconds, (iMem - iMemOld) >> 20, 130 | btnTest.BtnUsedKeys(), ((double)(swFcsKV.Elapsed.TotalMilliseconds * 1000000) / iPocetAdd), iPocetAdd, Marshal.SizeOf()); 131 | iMemOld = iMem; 132 | int iCompareCount = 0; 133 | // generate code at run time 134 | foreach (BtnKey? value in btnTest) 135 | iCompareCount++; 136 | // 137 | iCompareCount = 0; 138 | swFcsKV.Restart(); 139 | foreach (BtnKey? value in btnTest) 140 | iCompareCount++; 141 | swFcsKV.Stop(); 142 | Console.WriteLine("\nFcsKeyFastBTreeN - foreach()"); 143 | Console.WriteLine($"{((double)(swFcsKV.Elapsed.TotalMilliseconds * 1000000) / iCompareCount),9:N2} ns [{swFcsKV.Elapsed.TotalMilliseconds,11} ms | {iCompareCount} keys ]{iCompareCount / swFcsKV.Elapsed.TotalSeconds,20:N0} IOPS"); 144 | 145 | iCompareCount = 0; 146 | FcsKeyFastBTreeN.KeyEnumerator btnEn = btnTest.GetEnumeratorFastEx(false); 147 | swFcsKV.Restart(); 148 | while (btnEn.MoveNext()) 149 | { 150 | BtnKey? value = btnEn.Current; 151 | iCompareCount++; 152 | } 153 | swFcsKV.Stop(); 154 | btnEn.Dispose(); 155 | Console.WriteLine("\nFcsKeyFastBTreeN - foreach()"); 156 | Console.WriteLine($"{((double)(swFcsKV.Elapsed.TotalMilliseconds * 1000000) / iCompareCount),9:N2} ns [{swFcsKV.Elapsed.TotalMilliseconds,11} ms | {iCompareCount} keys ]{iCompareCount / swFcsKV.Elapsed.TotalSeconds,20:N0} IOPS"); 157 | 158 | iCompareCount = 0; 159 | FcsKeyFastBTreeN.KeyFast btnFast; 160 | swFcsKV.Restart(); 161 | if (btnTest.BtnFastFirst(out BtnKey fcsKey2, out btnFast) != null) 162 | { 163 | do 164 | { 165 | iCompareCount++; 166 | } 167 | while (btnTest.BtnFastNext(ref fcsKey2, ref btnFast) != null); 168 | } 169 | swFcsKV.Stop(); 170 | btnFast.Dispose(); 171 | Console.WriteLine("\nFcsFastBTreeN - BtnFastFirst()/BtnFastNext()"); 172 | Console.WriteLine($"{((double)(swFcsKV.Elapsed.TotalMilliseconds * 1000000) / iCompareCount),9:N2} ns [{swFcsKV.Elapsed.TotalMilliseconds,11} ms | {iCompareCount} keys ]{iCompareCount / swFcsKV.Elapsed.TotalSeconds,20:N0} IOPS"); 173 | // 174 | // 175 | Console.WriteLine("-----------------------------------"); 176 | Console.WriteLine("Key ENTER press."); 177 | Console.ReadLine(); 178 | } 179 | } 180 | } -------------------------------------------------------------------------------- /Samples/FcsFastBTreeN.Multi.benchmark/FcsFastBTreeN.Multi.benchmark.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp2.0;net461 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Samples/FcsFastBTreeN.Multi.benchmark/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using FriendlyCSharp.Databases; 5 | 6 | namespace FcsFastBTreeN.Multi.benchmark 7 | { 8 | class Program 9 | { 10 | private class TestKV : FcsFastBTreeN 11 | { 12 | protected override bool BtnUpdates(int keyAdd, uint valueAdd, ref uint valueUpdates, object objUpdates) 13 | { 14 | valueUpdates++; 15 | return true; 16 | } 17 | ////////////////////////// 18 | protected override int BtnCompares(int keyX, int keyY, object objCmp) 19 | { 20 | // return less < 0, equal = 0, greater > 0 21 | return keyX - keyY; 22 | } 23 | ////////////////////////// 24 | public TestKV() : base(32, 32) 25 | { 26 | } 27 | } 28 | // 29 | private struct StructBtn 30 | { 31 | public int key; 32 | public uint value; 33 | public int CompareTo(StructBtn keyY) 34 | { 35 | return key - keyY.key; 36 | } 37 | } 38 | // EqualityComparer 39 | private class StructBtnComparer : EqualityComparer 40 | { 41 | public override bool Equals(StructBtn x, StructBtn y) 42 | { 43 | return (x.key.CompareTo(y.key) == 0); 44 | } 45 | public override int GetHashCode(StructBtn x) 46 | { 47 | return x.key.GetHashCode(); 48 | } 49 | } 50 | // 51 | // 52 | // 53 | const int _max = 1; 54 | static void Main(string[] args) 55 | { 56 | Console.OutputEncoding = System.Text.Encoding.UTF8; 57 | Console.WriteLine(String.Format("FcsFastBTreeN.Multi.benchmark, {0}", (IntPtr.Size == 4) ? "32 bit" : "64 bit")); 58 | Console.WriteLine("--------------------------------------"); 59 | 60 | int iPocetAdd = 0; 61 | Random r = new Random((int)DateTime.Now.Ticks); 62 | int[] aRand = new int[10000000]; 63 | var hashSetRand = new HashSet(); 64 | while (iPocetAdd < 10000000) 65 | { 66 | int rand = r.Next(1, Int32.MaxValue); 67 | if (hashSetRand.Contains(rand) == false) 68 | { 69 | hashSetRand.Add(rand); 70 | aRand[iPocetAdd] = rand; 71 | iPocetAdd++; 72 | } 73 | } 74 | hashSetRand = null; 75 | long iMem = GC.GetTotalMemory(true); 76 | Console.WriteLine("UsedMemory {0,4} MB", iMem >> 20); 77 | long iMemOld = iMem; 78 | // 79 | // 80 | Console.WriteLine("--------------------------------------"); 81 | Console.WriteLine("FcsFastBTreeN"); 82 | TestKV btnTest = new TestKV(); 83 | var swFcsKV = Stopwatch.StartNew(); 84 | for (int i = 0; i < _max; i++) 85 | { 86 | uint value = 1; 87 | foreach (int ii in aRand) 88 | btnTest.BtnAdd(ii, ref value, null); 89 | } 90 | swFcsKV.Stop(); 91 | iMem = GC.GetTotalMemory(true); 92 | Console.WriteLine("UsedMemory {0,4} MB [{1,4:N1} s] | {3} | Δ {2,3} MB | {4,8:N0} ns", iMem >> 20, swFcsKV.Elapsed.TotalSeconds, (iMem - iMemOld) >> 20, 93 | btnTest.BtnUsedKeys(), ((double)(swFcsKV.Elapsed.TotalMilliseconds * 1000000) / _max / aRand.Length)); 94 | iMemOld = iMem; 95 | int iCompareCount = 0; 96 | swFcsKV.Restart(); 97 | foreach (KeyValuePair? value in btnTest) 98 | iCompareCount++; 99 | swFcsKV.Stop(); 100 | Console.WriteLine("FcsFastBTreeN - foreach()"); 101 | Console.WriteLine($"{((double)(swFcsKV.Elapsed.TotalMilliseconds * 1000000) / iCompareCount),7:N2} ns [{swFcsKV.Elapsed.TotalMilliseconds,11} ms | {iCompareCount} ]{iCompareCount / swFcsKV.Elapsed.TotalSeconds,20:N0} IOPS"); 102 | 103 | iCompareCount = 0; 104 | swFcsKV.Restart(); 105 | if (btnTest.BtnFastFirst(out int fcsKey2, out uint fcsValue2, 2) != null) 106 | { 107 | iCompareCount++; 108 | while (btnTest.BtnFastNext(ref fcsKey2, out fcsValue2, 2) != null) 109 | iCompareCount++; 110 | } 111 | swFcsKV.Stop(); 112 | Console.WriteLine("FcsFastBTreeN - BtnFastFirst()/BtnFastNext()"); 113 | Console.WriteLine($"{((double)(swFcsKV.Elapsed.TotalMilliseconds * 1000000) / iCompareCount),7:N2} ns [{swFcsKV.Elapsed.TotalMilliseconds,11} ms | {iCompareCount} ]{iCompareCount / swFcsKV.Elapsed.TotalSeconds,20:N0} IOPS"); 114 | // 115 | // 116 | Console.WriteLine("--------------------------------------"); 117 | Console.WriteLine("SortedSet"); 118 | SortedSet sorted = new SortedSet(Comparer.Create((a, b) => a.CompareTo(b))); 119 | var swSorted = Stopwatch.StartNew(); 120 | for (int i = 0; i < _max; i++) 121 | { 122 | StructBtn kvSet; 123 | kvSet.value = 1; 124 | foreach (int ii in aRand) 125 | { 126 | kvSet.key = ii; 127 | sorted.Add(kvSet); 128 | } 129 | } 130 | swSorted.Stop(); 131 | iMem = GC.GetTotalMemory(true); 132 | Console.WriteLine("UsedMemory {0,4} MB [{1,4:N1} s] | {3} | Δ {2,3} MB | {4,8:N0} ns", iMem >> 20, swSorted.Elapsed.TotalSeconds, (iMem - iMemOld) >> 20, 133 | sorted.Count, ((double)(swSorted.Elapsed.TotalMilliseconds * 1000000) / _max / aRand.Length)); 134 | iMemOld = iMem; 135 | iCompareCount = 0; 136 | swSorted.Restart(); 137 | foreach (StructBtn sortedSetX in sorted) 138 | iCompareCount++; 139 | swSorted.Stop(); 140 | Console.WriteLine("SortedSet - foreach()"); 141 | Console.WriteLine($"{((double)(swSorted.Elapsed.TotalMilliseconds * 1000000) / iCompareCount),7:N2} ns [{swSorted.Elapsed.TotalMilliseconds,11} ms | {iCompareCount} ]{iCompareCount / swSorted.Elapsed.TotalSeconds,20:N0} IOPS"); 142 | // 143 | // 144 | Console.WriteLine("--------------------------------------"); 145 | Console.WriteLine("HashSet"); 146 | var hash = new HashSet(new StructBtnComparer()); 147 | var swHash = Stopwatch.StartNew(); 148 | for (int i = 0; i < _max; i++) 149 | { 150 | StructBtn kvSet; 151 | kvSet.value = 1; 152 | foreach (int ii in aRand) 153 | { 154 | kvSet.key = ii; 155 | hash.Add(kvSet); 156 | } 157 | } 158 | swHash.Stop(); 159 | iMem = GC.GetTotalMemory(true); 160 | Console.WriteLine("UsedMemory {0,4} MB [{1,4:N1} s] | {3} | Δ {2,3} MB | {4,8:N0} ns", iMem >> 20, swHash.Elapsed.TotalSeconds, (iMem - iMemOld) >> 20, 161 | hash.Count, ((double)(swHash.Elapsed.TotalMilliseconds * 1000000) / _max / aRand.Length)); 162 | iMemOld = iMem; 163 | iCompareCount = 0; 164 | swHash.Restart(); 165 | foreach (StructBtn sortedSetH in hash) 166 | iCompareCount++; 167 | swSorted.Stop(); 168 | Console.WriteLine("HashSet - foreach()"); 169 | Console.WriteLine($"{((double)(swHash.Elapsed.TotalMilliseconds * 1000000) / iCompareCount),7:N2} ns [{swSorted.Elapsed.TotalMilliseconds,11} ms | {iCompareCount} ]{iCompareCount / swHash.Elapsed.TotalSeconds,20:N0} IOPS"); 170 | // 171 | // 172 | Console.WriteLine("--------------------------------------"); 173 | Console.WriteLine("Dictionary"); 174 | var dic = new Dictionary(); 175 | var swDic = Stopwatch.StartNew(); 176 | for (int i = 0; i < _max; i++) 177 | { 178 | foreach (int ii in aRand) 179 | dic.Add(ii, 1); 180 | } 181 | swDic.Stop(); 182 | iMem = GC.GetTotalMemory(true); 183 | Console.WriteLine("UsedMemory {0,4} MB [{1,4:N1} s] | {3} | Δ {2,3} MB | {4,8:N0} ns", iMem >> 20, swDic.Elapsed.TotalSeconds, (iMem - iMemOld) >> 20, 184 | dic.Count, ((double)(swDic.Elapsed.TotalMilliseconds * 1000000) / _max / aRand.Length)); 185 | iMemOld = iMem; 186 | iCompareCount = 0; 187 | swDic.Restart(); 188 | foreach (KeyValuePair sortedSetD in dic) 189 | iCompareCount++; 190 | swSorted.Stop(); 191 | Console.WriteLine("Dictionary - foreach()"); 192 | Console.WriteLine($"{((double)(swDic.Elapsed.TotalMilliseconds * 1000000) / iCompareCount),7:N2} ns [{swSorted.Elapsed.TotalMilliseconds,11} ms | {iCompareCount} ]{iCompareCount / swDic.Elapsed.TotalSeconds,20:N0} IOPS"); 193 | // 194 | // 195 | iCompareCount = 0; 196 | int iCompareEquals = 0; 197 | Console.WriteLine("--------------------------------------"); 198 | Console.WriteLine("Checking for sorting and matching"); 199 | btnTest.BtnFastFirst(out fcsKey2, out fcsValue2, 2); 200 | foreach (StructBtn sortedSet in sorted) 201 | { 202 | iCompareCount++; 203 | // Compare 204 | if (sortedSet.key == fcsKey2) 205 | iCompareEquals++; 206 | // FcsBTreeN verze 2 207 | if (btnTest.BtnFastNext(ref fcsKey2, out fcsValue2, 2) == null) 208 | break; 209 | } 210 | Console.WriteLine($"count FcsFastBTreeN: {btnTest.BtnUsedKeys()}"); 211 | Console.WriteLine($"count SortedSet: {iCompareCount}"); 212 | Console.WriteLine($"checking: {iCompareEquals}"); 213 | 214 | Console.WriteLine("--------------------------------------"); 215 | Console.WriteLine("Key ENTER press."); 216 | Console.ReadLine(); 217 | } 218 | } 219 | } -------------------------------------------------------------------------------- /Samples/FcsInmemStream.Multi.sample/FcsInmemStream.Multi.sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp2.0;net461 6 | 7 | 8 | 9 | True 10 | 11 | 12 | 13 | True 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Samples/FcsInmemStream.Multi.sample/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.InteropServices; 4 | using FriendlyCSharp.Databases; 5 | 6 | namespace FcsInmemStream.Multi.sample 7 | { 8 | class Program 9 | { 10 | public unsafe struct StructIms : ICloneable 11 | { 12 | public int key; 13 | public uint value; 14 | // 15 | public DateTime dt; 16 | // 17 | public Guid guid; 18 | // 19 | public fixed byte buff[32]; // 4064, 992, 480, 224, 96, 32 20 | 21 | public object Clone() 22 | { 23 | return base.MemberwiseClone(); 24 | } 25 | } 26 | 27 | static void Main(string[] args) 28 | { 29 | Console.OutputEncoding = System.Text.Encoding.UTF8; 30 | Console.WriteLine(String.Format("FcsInmemStream.Multi.sample, {0}", (IntPtr.Size == 4) ? "32 bit" : "64 bit")); 31 | Console.WriteLine("------------------------------------"); 32 | 33 | int iSizeT = Marshal.SizeOf(default(StructIms)); 34 | int iRepeat = 6000; 35 | if (iSizeT > 128) 36 | iRepeat = 4000; 37 | else if (iSizeT > 1024) 38 | iRepeat = 1000; 39 | int iID = 0; 40 | int cacheCount = 1000; 41 | StructIms[] aIms = new StructIms[cacheCount]; 42 | FcsInmemStream.ImsEnumeratorCacheLen = 128; 43 | FcsInmemStream ims = FcsInmemStream.Open(-4); 44 | #if DEBUG 45 | ims.FuncException = true; 46 | #else 47 | ims.FuncException = false; 48 | #endif 49 | Stopwatch swX = new Stopwatch(); 50 | for (int te = 0; te < iRepeat; te++) 51 | { 52 | for (int ui = 0; ui < cacheCount; ui++) 53 | { 54 | aIms[ui].key = iID++; 55 | aIms[ui].value = 0; 56 | aIms[ui].dt = DateTime.Now; 57 | aIms[ui].guid = Guid.NewGuid(); 58 | } 59 | swX.Start(); 60 | ims.Append(aIms); 61 | swX.Stop(); 62 | } 63 | Console.WriteLine($"Records: {ims.Length} | size: {iSizeT} Byte"); 64 | Console.WriteLine("\nAppend IOPS: {0,13:N0} [{1:N7} s] | count: {2,10:N0}", iID / swX.Elapsed.TotalSeconds, swX.Elapsed.TotalSeconds, iID); 65 | 66 | // foreach() 67 | iID = 0; 68 | foreach (StructIms value in ims) 69 | { 70 | if (value.key != iID) 71 | break; 72 | iID++; 73 | } 74 | iID = 0; 75 | swX.Reset(); 76 | swX.Start(); 77 | foreach (StructIms value in ims) 78 | { 79 | if (value.key != iID) 80 | break; 81 | iID++; 82 | } 83 | swX.Stop(); 84 | Console.WriteLine("foreach IOPS: {0,13:N0} [{1:N7} s] | count: {2,10:N0}", iID / swX.Elapsed.TotalSeconds, swX.Elapsed.TotalSeconds, iID); 85 | 86 | // Write() 87 | uint pos = 0; 88 | while (pos < ims.Length) 89 | { 90 | int iRead = ims.Read(pos, aIms, (UInt16)cacheCount); 91 | pos += (uint)iRead; 92 | } 93 | Array.Clear(aIms, 0, aIms.Length); 94 | iID = 0; 95 | pos = 0; 96 | swX.Reset(); 97 | while (pos < ims.Length) 98 | { 99 | ims.Read(pos, aIms, (UInt16)cacheCount); 100 | for (int ui = 0; ui < cacheCount; ui++) 101 | { 102 | aIms[ui].key *= 10; 103 | iID++; 104 | } 105 | swX.Start(); 106 | ims.Write(pos, aIms, null, 0, (UInt16)cacheCount); 107 | swX.Stop(); 108 | pos += (uint)cacheCount; 109 | } 110 | Console.WriteLine("Write IOPS: {0,13:N0} [{1:N7} s] | count: {2,10:N0}", iID / swX.Elapsed.TotalSeconds, swX.Elapsed.TotalSeconds, iID); 111 | 112 | // Read() 113 | Array.Clear(aIms, 0, aIms.Length); 114 | iID = 0; 115 | pos = 0; 116 | swX.Reset(); 117 | while (pos < ims.Length) 118 | { 119 | swX.Start(); 120 | int iRead = ims.Read(pos, aIms, (UInt16)cacheCount); 121 | swX.Stop(); 122 | pos += (uint)iRead; 123 | for (int ui = 0; ui < iRead; ui++) 124 | { 125 | if (aIms[ui].key != iID) 126 | break; 127 | iID += 10; 128 | } 129 | } 130 | iID /= 10; 131 | Console.WriteLine("Read IOPS: {0,13:N0} [{1:N7} s] | count: {2,10:N0}", iID / swX.Elapsed.TotalSeconds, swX.Elapsed.TotalSeconds, iID); 132 | ims.Close(); 133 | 134 | Console.WriteLine("------------------------------------"); 135 | Console.WriteLine("Key ENTER press."); 136 | Console.ReadLine(); 137 | } 138 | } 139 | } -------------------------------------------------------------------------------- /Samples/MultipleKeys.Multi.sample/MultipleKeys.Multi.sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp2.0;net461 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Samples/MultipleKeys.Multi.sample/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using FriendlyCSharp.Databases; 5 | 6 | namespace MultipleKeys.Multi.sample 7 | { 8 | class Program 9 | { 10 | private class TestKV : FcsFastBTreeN 11 | { 12 | protected override bool BtnUpdates(BtnKey keyAdd, BtnValue valueAdd, ref BtnValue valueUpdates, object objUpdates) 13 | { 14 | // Resize ? 15 | if (valueUpdates.aDateTime.Length <= valueUpdates.count) 16 | { 17 | if (valueUpdates.aDateTime.Length >= 1024) 18 | Array.Resize(ref valueUpdates.aDateTime, valueUpdates.aDateTime.Length + 256); 19 | else 20 | Array.Resize(ref valueUpdates.aDateTime, valueUpdates.aDateTime.Length * 2); 21 | } 22 | // Resize ? 23 | if (valueUpdates.aRand.Length <= valueUpdates.count) 24 | { 25 | if (valueUpdates.aRand.Length >= 1024) 26 | Array.Resize(ref valueUpdates.aRand, valueUpdates.aRand.Length + 256); 27 | else 28 | Array.Resize(ref valueUpdates.aRand, valueUpdates.aRand.Length * 2); 29 | } 30 | // Update 31 | if (valueAdd.aDateTime == null) 32 | valueUpdates.aDateTime[valueUpdates.count] = DateTime.MinValue; 33 | else 34 | valueUpdates.aDateTime[valueUpdates.count] = valueAdd.aDateTime[0]; 35 | // Update 36 | if (valueAdd.aRand == null) 37 | valueUpdates.aRand[valueUpdates.count] = uint.MaxValue; 38 | else 39 | valueUpdates.aRand[valueUpdates.count] = valueAdd.aRand[0]; 40 | valueUpdates.count++; 41 | return true; 42 | } 43 | ////////////////////////// 44 | protected override void BtnAddFirst(BtnValue valueIn, out BtnValue valueAdd) 45 | { 46 | if (valueIn.count != 1) 47 | { 48 | valueIn.count = 1; 49 | valueIn.aDateTime = new DateTime[1]; 50 | valueIn.aRand = new uint[1]; 51 | } 52 | if (valueIn.aDateTime == null) 53 | { 54 | valueIn.aDateTime = new DateTime[1]; 55 | valueIn.aDateTime[0] = DateTime.MinValue; 56 | } 57 | if (valueIn.aRand == null) 58 | { 59 | valueIn.aRand = new uint[1]; 60 | valueIn.aRand[0] = uint.MaxValue; 61 | } 62 | base.BtnAddFirst(valueIn, out valueAdd); 63 | } 64 | ////////////////////////// 65 | private void _BtnUsedValues(ref uint Count, KeyValuePage QQ) 66 | { 67 | if (QQ != null) 68 | { 69 | if (QQ.kvPageNextRight != null) 70 | { 71 | _BtnUsedValues(ref Count, QQ.kvPageNextRight[0]); 72 | for (int II = 1; II <= QQ.iDataCount; II++) 73 | { 74 | _BtnUsedValues(ref Count, QQ.kvPageNextRight[II]); 75 | Count += (uint)QQ.aData[II].value.count; 76 | } 77 | } 78 | else 79 | { 80 | for (int II = 1; II <= QQ.iDataCount; II++) 81 | Count += (uint)QQ.aData[II].value.count; 82 | } 83 | } 84 | } 85 | ////////////////////////// 86 | public uint BtnUsedValues() 87 | { 88 | uint Count = 0; 89 | _BtnUsedValues(ref Count, _btnRoot); 90 | return Count; 91 | } 92 | ////////////////////////// 93 | public TestKV() : base(32, 32) 94 | { 95 | } 96 | } 97 | // 98 | private struct BtnKey : IComparable 99 | { 100 | public string keyCity; 101 | public long keyId; 102 | //public DateTime key0; 103 | //public string key1; 104 | //public long key2; 105 | public int CompareTo(BtnKey keyY) 106 | { 107 | // return < 0 (less), = 0 (equal), > 0 (greater) 108 | int iResult = String.Compare(keyCity, keyY.keyCity, StringComparison.Ordinal); 109 | if (iResult == 0) 110 | { 111 | iResult = keyId.CompareTo(keyY.keyId); 112 | //if (iResult == 0) 113 | //{ 114 | // iResult = DateTime.Compare(key0, keyY.key0); 115 | // if (iResult == 0) 116 | // { 117 | // iResult = string.Compare(key1, keyY.key1, true); 118 | // if (iResult == 0) 119 | // { 120 | // iResult = key2.CompareTo(keyY.key2); 121 | // } 122 | // } 123 | //} 124 | } 125 | return iResult; 126 | } 127 | } 128 | // 129 | private struct BtnValue 130 | { 131 | public int count; 132 | public DateTime[] aDateTime; 133 | public uint[] aRand; 134 | } 135 | // 136 | // 137 | // 138 | static void Main(string[] args) 139 | { 140 | Console.OutputEncoding = System.Text.Encoding.UTF8; 141 | Console.WriteLine(String.Format("MultipleKeys.Multi.sample, {0}", (IntPtr.Size == 4) ? "32 bit" : "64 bit")); 142 | Console.WriteLine("----------------------------------"); 143 | 144 | int max = 36000; 145 | string[] aCity = { "London", "Moscow", "Warsaw", "Berlin", "Paris", "Prague", "Brussels", "Vienna", "Zagreb", "Helsinki" }; 146 | int iPocetAdd = 0; 147 | Random r = new Random((int)DateTime.Now.Ticks); 148 | uint[] aRand = new uint[max]; 149 | var hashSetRand = new HashSet(); 150 | while (iPocetAdd < max) 151 | { 152 | uint rand = (uint)r.Next(0, Int32.MaxValue - 1); 153 | if (hashSetRand.Contains(rand) == false) 154 | { 155 | hashSetRand.Add(rand); 156 | aRand[iPocetAdd] = rand; 157 | iPocetAdd++; 158 | } 159 | } 160 | hashSetRand = null; 161 | long iMem = GC.GetTotalMemory(true); 162 | Console.WriteLine("UsedMemory {0,4} MB", iMem >> 20); 163 | long iMemOld = iMem; 164 | // 165 | // 166 | iPocetAdd = 0; 167 | Console.WriteLine("----------------------------------"); 168 | Console.WriteLine("FcsFastBTreeN"); 169 | TestKV btnTest = new TestKV(); 170 | var swFcsKV = Stopwatch.StartNew(); 171 | for (int iter = 0; iter < 100; iter++) 172 | { 173 | for (int idx = 0; idx < max; idx++) 174 | { 175 | BtnKey key; 176 | key.keyCity = aCity[idx % aCity.Length]; 177 | key.keyId = idx % 1200; 178 | BtnValue value; 179 | value.count = 1; 180 | if (idx % 50 == 12) 181 | value.aRand = null; 182 | else 183 | { 184 | value.aRand = new uint[1]; 185 | value.aRand[0] = aRand[idx]; 186 | } 187 | if (idx % 60 == 12) 188 | value.aDateTime = null; 189 | else 190 | { 191 | value.aDateTime = new DateTime[1]; 192 | value.aDateTime[0] = DateTime.Now; 193 | } 194 | if (btnTest.BtnAdd(key, ref value, null) != null) 195 | iPocetAdd++; 196 | } 197 | } 198 | swFcsKV.Stop(); 199 | iMem = GC.GetTotalMemory(true); 200 | Console.WriteLine("UsedMemory {0,5} MB [{1,5:N1} s] | {3} keys | Δ {2,3} MB | {4,8:N0} ns | {5,10:N0} values", iMem >> 20, swFcsKV.Elapsed.TotalSeconds, (iMem - iMemOld) >> 20, 201 | btnTest.BtnUsedKeys(), ((double)(swFcsKV.Elapsed.TotalMilliseconds * 1000000) / iPocetAdd), btnTest.BtnUsedValues()); 202 | iMemOld = iMem; 203 | int iCompareCount = 0; 204 | swFcsKV.Restart(); 205 | foreach (KeyValuePair? value in btnTest) 206 | iCompareCount++; 207 | swFcsKV.Stop(); 208 | Console.WriteLine("\nFcsFastBTreeN - foreach()"); 209 | Console.WriteLine($"{((double)(swFcsKV.Elapsed.TotalMilliseconds * 1000000) / iCompareCount),9:N2} ns [{swFcsKV.Elapsed.TotalMilliseconds,11} ms | {iCompareCount} keys ]{iCompareCount / swFcsKV.Elapsed.TotalSeconds,20:N0} IOPS"); 210 | 211 | iCompareCount = 0; 212 | FcsBTreeN.BtnEnumerator btnEn = btnTest.GetEnumeratorEx(false); 213 | swFcsKV.Restart(); 214 | while (btnEn.MoveNext()) 215 | { 216 | KeyValuePair? value = btnEn.Current; 217 | iCompareCount++; 218 | } 219 | swFcsKV.Stop(); 220 | Console.WriteLine("\nFcsBTreeN - foreach()"); 221 | Console.WriteLine($"{((double)(swFcsKV.Elapsed.TotalMilliseconds * 1000000) / iCompareCount),9:N2} ns [{swFcsKV.Elapsed.TotalMilliseconds,11} ms | {iCompareCount} keys ]{iCompareCount / swFcsKV.Elapsed.TotalSeconds,20:N0} IOPS"); 222 | 223 | iCompareCount = 0; 224 | swFcsKV.Restart(); 225 | if (btnTest.BtnFastFirst(out BtnKey fcsKey2, out BtnValue fcsValue2, 2) != null) 226 | { 227 | iCompareCount++; 228 | while (btnTest.BtnFastNext(ref fcsKey2, out fcsValue2, 2) != null) 229 | iCompareCount++; 230 | } 231 | swFcsKV.Stop(); 232 | Console.WriteLine("\nFcsFastBTreeN - BtnFastFirst()/BtnFastNext()"); 233 | Console.WriteLine($"{((double)(swFcsKV.Elapsed.TotalMilliseconds * 1000000) / iCompareCount),9:N2} ns [{swFcsKV.Elapsed.TotalMilliseconds,11} ms | {iCompareCount} keys ]{iCompareCount / swFcsKV.Elapsed.TotalSeconds,20:N0} IOPS"); 234 | // 235 | // 236 | 237 | Console.WriteLine("----------------------------------"); 238 | Console.WriteLine("Key ENTER press."); 239 | Console.ReadLine(); 240 | } 241 | } 242 | } --------------------------------------------------------------------------------