Showing preview only (489K chars total). Download the full file or copy to clipboard to get everything.
Repository: neuecc/MasterMemory
Branch: master
Commit: 863383d77681
Files: 142
Total size: 448.9 KB
Directory structure:
gitextract_t6q9u1cd/
├── .editorconfig
├── .github/
│ ├── dependabot.yaml
│ └── workflows/
│ ├── build-debug.yaml
│ ├── build-release.yaml
│ ├── prevent-github-change.yaml
│ ├── stale.yaml
│ └── toc.yaml
├── .gitignore
├── Directory.Build.props
├── LICENSE
├── MasterMemory.sln
├── README.md
├── sandbox/
│ ├── Benchmark/
│ │ ├── Benchmark.csproj
│ │ ├── Program.cs
│ │ └── Utils/
│ │ └── Helper.cs
│ ├── ConsoleApp/
│ │ ├── ConsoleApp.csproj
│ │ └── Program.cs
│ ├── GeneratorSandbox/
│ │ ├── GeneratorSandbox.csproj
│ │ └── Program.cs
│ └── PerfTest2/
│ ├── Engines/
│ │ ├── Dictionary_Test.cs
│ │ ├── ITest.cs
│ │ ├── LiteDB_Test.cs
│ │ ├── MasterMemory_Test.cs
│ │ ├── RavenDB_Test.cs
│ │ └── SQLite_Test.cs
│ ├── Generated/
│ │ ├── DatabaseBuilder.cs
│ │ ├── ImmutableBuilder.cs
│ │ ├── MasterMemoryResolver.cs
│ │ ├── MemoryDatabase.cs
│ │ └── Tables/
│ │ └── TestDocTable.cs
│ ├── PerfTest2.csproj
│ ├── Program.cs
│ └── Utils/
│ └── Helper.cs
├── src/
│ ├── MasterMemory/
│ │ ├── DatabaseBuilderBase.cs
│ │ ├── DatabaseBuilderBaseExtensions.cs
│ │ ├── IValidatable.cs
│ │ ├── ImmutableBuilderBase.cs
│ │ ├── Internal/
│ │ │ ├── BinarySearch.cs
│ │ │ ├── ByteBufferWriter.cs
│ │ │ ├── ExpandableArray.cs
│ │ │ ├── HeaderFormatterResolver.cs
│ │ │ └── InternStringResolver.cs
│ │ ├── MasterMemory.csproj
│ │ ├── MemoryDatabaseBase.cs
│ │ ├── Meta/
│ │ │ └── Meta.cs
│ │ ├── RangeView.cs
│ │ ├── TableBase.cs
│ │ ├── Validation/
│ │ │ ├── ExpressionDumper.cs
│ │ │ ├── ExpressionParameterNameModifier.cs
│ │ │ ├── ITableUniqueValidate.cs
│ │ │ ├── ReferenceSet.cs
│ │ │ ├── ValidatableSet.Sequential.cs
│ │ │ ├── ValidatableSet.Sequential.tt
│ │ │ ├── ValidatableSet.cs
│ │ │ ├── ValidateResult.cs
│ │ │ ├── ValidationDatabase.cs
│ │ │ └── Validator.cs
│ │ ├── _InternalVisibleTo.cs
│ │ └── _MessagePackResolver.cs
│ ├── MasterMemory.Annotations/
│ │ ├── Attributes.cs
│ │ └── MasterMemory.Annotations.csproj
│ ├── MasterMemory.SourceGenerator/
│ │ ├── DiagnosticDescriptors.cs
│ │ ├── GeneratorCore/
│ │ │ ├── CodeGenerator.cs
│ │ │ ├── DatabaseBuilderTemplate.cs
│ │ │ ├── DatabaseBuilderTemplate.tt
│ │ │ ├── GenerationContext.cs
│ │ │ ├── ImmutableBuilderTemplate.cs
│ │ │ ├── ImmutableBuilderTemplate.tt
│ │ │ ├── MemoryDatabaseTemplate.cs
│ │ │ ├── MemoryDatabaseTemplate.tt
│ │ │ ├── MessagePackResolverTemplate.cs
│ │ │ ├── MessagePackResolverTemplate.tt
│ │ │ ├── TableTemplate.cs
│ │ │ ├── TableTemplate.tt
│ │ │ └── Template.cs
│ │ ├── MasterMemory.SourceGenerator.csproj
│ │ ├── MasterMemoryGenerator.cs
│ │ ├── MasterMemoryGeneratorOptions.cs
│ │ ├── Polyfill/
│ │ │ └── System.CodeDom.cs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ └── Utility/
│ │ ├── EquatableArray.cs
│ │ └── IgnoreEquality.cs
│ └── MasterMemory.Unity/
│ ├── Assets/
│ │ ├── NuGet.config
│ │ ├── NuGet.config.meta
│ │ ├── Packages.meta
│ │ ├── Scenes/
│ │ │ ├── Main.unity
│ │ │ └── Main.unity.meta
│ │ ├── Scenes.meta
│ │ ├── Scripts/
│ │ │ ├── NewBehaviourScript.cs
│ │ │ └── NewBehaviourScript.cs.meta
│ │ ├── Scripts.meta
│ │ ├── packages.config
│ │ └── packages.config.meta
│ ├── Packages/
│ │ ├── manifest.json
│ │ └── packages-lock.json
│ └── ProjectSettings/
│ ├── AudioManager.asset
│ ├── ClusterInputManager.asset
│ ├── DynamicsManager.asset
│ ├── EditorBuildSettings.asset
│ ├── EditorSettings.asset
│ ├── GraphicsSettings.asset
│ ├── InputManager.asset
│ ├── MemorySettings.asset
│ ├── NavMeshAreas.asset
│ ├── NetworkManager.asset
│ ├── PackageManagerSettings.asset
│ ├── Physics2DSettings.asset
│ ├── PresetManager.asset
│ ├── ProjectSettings.asset
│ ├── ProjectVersion.txt
│ ├── QualitySettings.asset
│ ├── SceneTemplateSettings.json
│ ├── TagManager.asset
│ ├── TimeManager.asset
│ ├── UnityConnectSettings.asset
│ ├── VFXManager.asset
│ ├── VersionControlSettings.asset
│ └── XRSettings.asset
└── tests/
├── MasterMemory.SourceGenerator.Tests/
│ ├── AssemblyAtrributeTest.cs
│ ├── DiagnosticsTest.cs
│ ├── GenerateTest.cs
│ ├── IncrementalGeneratorTest.cs
│ ├── MasterMemory.SourceGenerator.Tests.csproj
│ ├── TestBase.cs
│ └── Utility/
│ ├── CSharpGeneratorRunner.cs
│ └── CodeGeneratorHelper.cs
└── MasterMemory.Tests/
├── BinarySearchTest.cs
├── DatabaseTest.cs
├── IssueTest.cs
├── MasterMemory.Tests.csproj
├── MemoryKeyTest.cs
├── MemoryTest.cs
├── MessagePackResolver.cs
├── MetaTest.cs
├── RangeViewTest.cs
├── TestStructures/
│ ├── PersonModel.cs
│ ├── QuestMaster.cs
│ ├── Sample.cs
│ ├── SkillMaster.cs
│ ├── TestMaster.cs
│ └── UserLevel.cs
└── ValidatorTest.cs
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
# top-most EditorConfig file
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
# Visual Studio Spell checker configs (https://learn.microsoft.com/en-us/visualstudio/ide/text-spell-checker?view=vs-2022#how-to-customize-the-spell-checker)
spelling_exclusion_path = ./exclusion.dic
[*.cs]
indent_size = 4
charset = utf-8-bom
end_of_line = unset
# Solution files
[*.{sln,slnx}]
end_of_line = unset
# MSBuild project files
[*.{csproj,props,targets}]
end_of_line = unset
# Xml config files
[*.{ruleset,config,nuspec,resx,runsettings,DotSettings}]
end_of_line = unset
[*{_AssemblyInfo.cs,.notsupported.cs}]
generated_code = true
# C# code style settings
[*.{cs}]
dotnet_diagnostic.IDE0044.severity = none # IDE0044: Make field readonly
# https://stackoverflow.com/questions/79195382/how-to-disable-fading-unused-methods-in-visual-studio-2022-17-12-0
dotnet_diagnostic.IDE0051.severity = none # IDE0051: Remove unused private member
dotnet_diagnostic.IDE0130.severity = none # IDE0130: Namespace does not match folder structure
================================================
FILE: .github/dependabot.yaml
================================================
# ref: https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly" # Check for updates to GitHub Actions every week
groups:
dependencies:
patterns:
- "*"
cooldown:
default-days: 14 # Wait 14 days before creating another PR for the same dependency. This will prevent vulnerability on the package impact.
ignore:
# I just want update action when major/minor version is updated. patch updates are too noisy.
- dependency-name: "*"
update-types:
- version-update:semver-patch
================================================
FILE: .github/workflows/build-debug.yaml
================================================
name: Build-Debug
on:
push:
branches:
- "master"
pull_request:
branches:
- "master"
jobs:
build-dotnet:
permissions:
contents: read
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
with:
dotnet-version: |
9.0.x
- run: dotnet build -c Release
- run: dotnet test -c Release --no-build
- run: dotnet pack -c Release --no-build -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg -o $GITHUB_WORKSPACE/artifacts
================================================
FILE: .github/workflows/build-release.yaml
================================================
name: Build-Release
on:
workflow_dispatch:
inputs:
tag:
description: "tag: git tag you want create. (sample 1.0.0)"
required: true
dry-run:
description: "dry-run: true will never create relase/nuget."
required: true
default: false
type: boolean
jobs:
build-dotnet:
permissions:
contents: read
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: Cysharp/Actions/.github/actions/checkout@main
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
# pack nuget
- run: dotnet build -c Release -p:Version=${{ inputs.tag }}
- run: dotnet test -c Release --no-build
- run: dotnet pack -c Release --no-build -p:Version=${{ inputs.tag }} -o ./publish
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
with:
name: nuget
path: ./publish
retention-days: 1
# release
create-release:
needs: [build-dotnet]
permissions:
contents: write
id-token: write # required for NuGet Trusted Publish
uses: Cysharp/Actions/.github/workflows/create-release.yaml@main
with:
commit-id: ${{ github.sha }}
dry-run: ${{ inputs.dry-run }}
tag: ${{ inputs.tag }}
nuget-push: true
secrets: inherit
================================================
FILE: .github/workflows/prevent-github-change.yaml
================================================
name: Prevent github change
on:
pull_request:
paths:
- ".github/**/*.yaml"
- ".github/**/*.yml"
jobs:
detect:
permissions:
contents: read
uses: Cysharp/Actions/.github/workflows/prevent-github-change.yaml@main
================================================
FILE: .github/workflows/stale.yaml
================================================
name: "Close stale issues"
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
jobs:
stale:
permissions:
contents: read
pull-requests: write
issues: write
uses: Cysharp/Actions/.github/workflows/stale-issue.yaml@main
================================================
FILE: .github/workflows/toc.yaml
================================================
name: TOC Generator
on:
push:
paths:
- 'README.md'
jobs:
toc:
permissions:
contents: write
uses: Cysharp/Actions/.github/workflows/toc-generator.yaml@main
with:
TOC_TITLE: "## Table of Contents"
secrets: inherit
================================================
FILE: .gitignore
================================================
# Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
[Bb]in/
[Oo]bj/
# mstest test results
TestResults
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
x64/
*_i.c
*_p.c
*.ilk
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.log
*.vspscc
*.vssscc
.builds
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*
# NCrunch
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
[Ee]xpress
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish
# Publish Web Output
*.Publish.xml
# NuGet Packages Directory
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
# packages # upm pacakge will use Packages
# **/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
# !**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Windows Azure Build Output
csx
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
[Bb]in
[Oo]bj
sql
TestResults
[Tt]est[Rr]esult*
*.Cache
ClientBin
[Ss]tyle[Cc]op.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
.vs/config/applicationhost.config
.vs/restore.dg
.vs
.vsconfig
# Unity
src/MasterMemory.Unity/bin/*
src/MasterMemory.Unity/Library/*
src/MasterMemory.Unity/obj/*
src/MasterMemory.Unity/Temp/*
src/MasterMemory.Unity/[Uu]ser[Ss]ettings/
src/MasterMemory.Unity/*.sln
src/MasterMemory.Unity/*.csproj
src/MasterMemory.Unity/*.unitypackage
!src/MasterMemory.Unity/Packages/
================================================
FILE: Directory.Build.props
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<LangVersion>13</LangVersion>
<!-- NuGet Package Information -->
<IsPackable>false</IsPackable>
<PackageVersion>$(Version)</PackageVersion>
<Company>Cysharp</Company>
<Authors>Cysharp</Authors>
<Copyright>© Cysharp, Inc.</Copyright>
<PackageTags>database, embedded, inmemory, unity</PackageTags>
<PackageProjectUrl>https://github.com/Cysharp/MasterMemory</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>$(PackageProjectUrl)</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Icon.png</PackageIcon>
</PropertyGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)Icon.png" Pack="true" PackagePath="\" />
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" PackagePath="\" />
<EmbeddedResource Include="$(MSBuildThisFileDirectory)LICENSE" />
</ItemGroup>
</Project>
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 Yoshifumi Kawai / Cysharp, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: MasterMemory.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35527.113
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{60662102-4523-441E-8D6C-D87A3246C648}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{BDAFF1CB-8E53-412B-B389-42A15343C7A3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandbox", "sandbox", "{FFAA235C-D30F-4958-BC4E-60CD08979464}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MasterMemory", "src\MasterMemory\MasterMemory.csproj", "{D2720BBB-C233-4A1E-9768-1F00C9602180}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MasterMemory.Tests", "tests\MasterMemory.Tests\MasterMemory.Tests.csproj", "{8C5EBACA-C6C7-463B-B85C-C6A05E5DEB9F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MasterMemory.Annotations", "src\MasterMemory.Annotations\MasterMemory.Annotations.csproj", "{A13F40DD-7777-4E97-9FC4-6324722CA964}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmark", "sandbox\Benchmark\Benchmark.csproj", "{205509EA-78C8-4ED0-B2B5-8030DDFB0BF0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "sandbox\ConsoleApp\ConsoleApp.csproj", "{2657C9C5-0BEA-4616-BE41-A19E8298C591}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerfTest2", "sandbox\PerfTest2\PerfTest2.csproj", "{AA5B5485-C42E-449C-843A-98A99A0D10B2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterMemory.SourceGenerator", "src\MasterMemory.SourceGenerator\MasterMemory.SourceGenerator.csproj", "{73F0ABAF-E55F-4E63-923B-4ABDE794D490}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GeneratorSandbox", "sandbox\GeneratorSandbox\GeneratorSandbox.csproj", "{D1D2B635-99CC-4C90-BAAB-57D188B5BE42}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterMemory.SourceGenerator.Tests", "tests\MasterMemory.SourceGenerator.Tests\MasterMemory.SourceGenerator.Tests.csproj", "{96F54302-35CD-4CDC-AAAC-8A6858DCAFEB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D2720BBB-C233-4A1E-9768-1F00C9602180}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D2720BBB-C233-4A1E-9768-1F00C9602180}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2720BBB-C233-4A1E-9768-1F00C9602180}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2720BBB-C233-4A1E-9768-1F00C9602180}.Release|Any CPU.Build.0 = Release|Any CPU
{8C5EBACA-C6C7-463B-B85C-C6A05E5DEB9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C5EBACA-C6C7-463B-B85C-C6A05E5DEB9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C5EBACA-C6C7-463B-B85C-C6A05E5DEB9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C5EBACA-C6C7-463B-B85C-C6A05E5DEB9F}.Release|Any CPU.Build.0 = Release|Any CPU
{A13F40DD-7777-4E97-9FC4-6324722CA964}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A13F40DD-7777-4E97-9FC4-6324722CA964}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A13F40DD-7777-4E97-9FC4-6324722CA964}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A13F40DD-7777-4E97-9FC4-6324722CA964}.Release|Any CPU.Build.0 = Release|Any CPU
{205509EA-78C8-4ED0-B2B5-8030DDFB0BF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{205509EA-78C8-4ED0-B2B5-8030DDFB0BF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{205509EA-78C8-4ED0-B2B5-8030DDFB0BF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{205509EA-78C8-4ED0-B2B5-8030DDFB0BF0}.Release|Any CPU.Build.0 = Release|Any CPU
{2657C9C5-0BEA-4616-BE41-A19E8298C591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2657C9C5-0BEA-4616-BE41-A19E8298C591}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2657C9C5-0BEA-4616-BE41-A19E8298C591}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2657C9C5-0BEA-4616-BE41-A19E8298C591}.Release|Any CPU.Build.0 = Release|Any CPU
{AA5B5485-C42E-449C-843A-98A99A0D10B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AA5B5485-C42E-449C-843A-98A99A0D10B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA5B5485-C42E-449C-843A-98A99A0D10B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA5B5485-C42E-449C-843A-98A99A0D10B2}.Release|Any CPU.Build.0 = Release|Any CPU
{73F0ABAF-E55F-4E63-923B-4ABDE794D490}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73F0ABAF-E55F-4E63-923B-4ABDE794D490}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73F0ABAF-E55F-4E63-923B-4ABDE794D490}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73F0ABAF-E55F-4E63-923B-4ABDE794D490}.Release|Any CPU.Build.0 = Release|Any CPU
{D1D2B635-99CC-4C90-BAAB-57D188B5BE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1D2B635-99CC-4C90-BAAB-57D188B5BE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1D2B635-99CC-4C90-BAAB-57D188B5BE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1D2B635-99CC-4C90-BAAB-57D188B5BE42}.Release|Any CPU.Build.0 = Release|Any CPU
{96F54302-35CD-4CDC-AAAC-8A6858DCAFEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{96F54302-35CD-4CDC-AAAC-8A6858DCAFEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96F54302-35CD-4CDC-AAAC-8A6858DCAFEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{96F54302-35CD-4CDC-AAAC-8A6858DCAFEB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{D2720BBB-C233-4A1E-9768-1F00C9602180} = {60662102-4523-441E-8D6C-D87A3246C648}
{8C5EBACA-C6C7-463B-B85C-C6A05E5DEB9F} = {BDAFF1CB-8E53-412B-B389-42A15343C7A3}
{A13F40DD-7777-4E97-9FC4-6324722CA964} = {60662102-4523-441E-8D6C-D87A3246C648}
{205509EA-78C8-4ED0-B2B5-8030DDFB0BF0} = {FFAA235C-D30F-4958-BC4E-60CD08979464}
{2657C9C5-0BEA-4616-BE41-A19E8298C591} = {FFAA235C-D30F-4958-BC4E-60CD08979464}
{AA5B5485-C42E-449C-843A-98A99A0D10B2} = {FFAA235C-D30F-4958-BC4E-60CD08979464}
{73F0ABAF-E55F-4E63-923B-4ABDE794D490} = {60662102-4523-441E-8D6C-D87A3246C648}
{D1D2B635-99CC-4C90-BAAB-57D188B5BE42} = {FFAA235C-D30F-4958-BC4E-60CD08979464}
{96F54302-35CD-4CDC-AAAC-8A6858DCAFEB} = {BDAFF1CB-8E53-412B-B389-42A15343C7A3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0121A3C4-6AE0-4622-BE04-05D9A3E729AC}
EndGlobalSection
EndGlobal
================================================
FILE: README.md
================================================
[](https://github.com/Cysharp/MasterMemory/actions) [](https://github.com/Cysharp/MasterMemory/releases)
MasterMemory
===
Source Generator based Embedded Typed Readonly In-Memory Document Database for .NET and Unity.

**4700** times faster than SQLite and achieves zero allocation per query. Also the DB size is small. When SQLite is 3560kb then MasterMemory is only 222kb.
Source Generator automatically generates a typed database structure from schemas (classes), which ensures that all queries are type-safe with full autocompletion support.


This ensures both optimal performance and excellent usability.
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
## Table of Contents
- [Concept](#concept)
- [Getting Started(.NET)](#getting-startednet)
- [Getting Started(Unity)](#getting-startedunity)
- [DataTable configuration](#datatable-configuration)
- [MemoryDatabase/RangeView](#memorydatabaserangeview)
- [Extend Table](#extend-table)
- [ImmutableBuilder](#immutablebuilder)
- [Validator](#validator)
- [Metadata](#metadata)
- [Inheritance](#inheritance)
- [Optimization](#optimization)
- [MasterMemoryGeneratorOptions](#mastermemorygeneratoroptions)
- [v2 -> v3 migration](#v2---v3-migration)
- [License](#license)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
Concept
---
* **Memory Efficient**, Only use underlying data memory and do aggressively string interning.
* **Performance**, Similar as dictionary lookup.
* **TypeSafe**, 100% Type safe by Source Generator.
* **Fast load speed**, MasterMemory save data by [MessagePack for C#, a fastest C# serializer](https://github.com/neuecc/MessagePack-CSharp) so load speed is blazing fast.
* **Flexible Search**, Supports multiple key, multiple result, range/closest query.
* **Validator**, You can define custom data validation by C#.
* **Metadata**, To make custom importer/exporter, get the all database metadata.
These features are suitable for master data management(write-once, read-heavy) on embedded application, data analysis, game, etc. MasterMemory has better performance than any other database solutions. [PalDB](https://github.com/linkedin/PalDB) developed by LinkedIn has a similar concept(embeddable write-once key-value store), but the implementation and performance characteristics are completely different.
Getting Started(.NET)
---
Install the [MasterMemory](https://www.nuget.org/packages/MasterMemory) library(Runtime, Source Generator(Analyzer) via NuGet.
```
dotnet add package MasterMemory
```
Prepare the example table definition like following.
```csharp
public enum Gender
{
Male, Female, Unknown
}
// table definition marked by MemoryTableAttribute.
// database-table must be serializable by MessagePack-CSsharp
[MemoryTable("person"), MessagePackObject(true)]
public record Person
{
// index definition by attributes.
[PrimaryKey]
public required int PersonId { get; init; }
// secondary index can add multiple(discriminated by index-number).
[SecondaryKey(0), NonUnique]
[SecondaryKey(1, keyOrder: 1), NonUnique]
public required int Age { get; init; }
[SecondaryKey(2), NonUnique]
[SecondaryKey(1, keyOrder: 0), NonUnique]
public required Gender Gender { get; init; }
public required string Name { get; init; }
}
```
Data in MasterMemory is readonly, so it is recommended to use an immutable structure. While both records and classes are supported, records might be preferable as they generate more readable ToString methods.
MasterMemory's Source Generator detects types marked with the `MemoryTable` attribute and automatically generates types like the following:

Finally, you can regsiter and query by these files.
```csharp
using ...; // Your project default namespace
// to create database, use DatabaseBuilder and Append method.
var builder = new DatabaseBuilder();
builder.Append(new Person[]
{
new (){ PersonId = 0, Age = 13, Gender = Gender.Male, Name = "Dana Terry" },
new (){ PersonId = 1, Age = 17, Gender = Gender.Male, Name = "Kirk Obrien" },
new (){ PersonId = 2, Age = 31, Gender = Gender.Male, Name = "Wm Banks" },
new (){ PersonId = 3, Age = 44, Gender = Gender.Male, Name = "Karl Benson" },
new (){ PersonId = 4, Age = 23, Gender = Gender.Male, Name = "Jared Holland" },
new (){ PersonId = 5, Age = 27, Gender = Gender.Female, Name = "Jeanne Phelps" },
new (){ PersonId = 6, Age = 25, Gender = Gender.Female, Name = "Willie Rose" },
new (){ PersonId = 7, Age = 11, Gender = Gender.Female, Name = "Shari Gutierrez" },
new (){ PersonId = 8, Age = 63, Gender = Gender.Female, Name = "Lori Wilson" },
new (){ PersonId = 9, Age = 34, Gender = Gender.Female, Name = "Lena Ramsey" },
});
// build database binary(you can also use `WriteToStream` for save to file).
byte[] data = builder.Build();
// -----------------------
// for query phase, create MemoryDatabase.
// (MemoryDatabase is recommended to store in singleton container(static field/DI)).
var db = new MemoryDatabase(data);
// .PersonTable.FindByPersonId is fully typed by code-generation.
Person person = db.PersonTable.FindByPersonId(5);
// Multiple key is also typed(***And * **), Return value is multiple if key is marked with `NonUnique`.
RangeView<Person> result = db.PersonTable.FindByGenderAndAge((Gender.Female, 23));
// Get nearest value(choose lower(default) or higher).
RangeView<Person> age1 = db.PersonTable.FindClosestByAge(31);
// Get range(min-max inclusive).
RangeView<Person> age2 = db.PersonTable.FindRangeByAge(20, 29);
```
All table(marked by `MemoryTableAttribute`) and methods(created by `PrimaryKeyAttribute` or `SecondaryKeyAttribute`) are typed.

You can invoke all indexed query by IntelliSense.
Getting Started(Unity)
---
The minimum supported Unity version will be `2022.3.12f1`, as it is necessary to support C# Incremental Source Generator(Compiler Version, 4.3.0).
Since this library is provided via NuGet, install [NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity), then navigate to Open Window from NuGet -> Manage NuGet Packages, Search "MasterMemory" and Press Install.
First, it is recommended to define assembly attributes in any cs file to enable the use of `init`.
```csharp
// Optional: Unity can't load default namespace to Source Generator
// If not specified, 'MasterMemory' will be used by default,
// but you can use this attribute if you want to specify a different namespace.
[assembly: MasterMemoryGeneratorOptions(Namespace = "MyProj")]
// Optional: If you want to use init keyword, copy-and-paste this.
namespace System.Runtime.CompilerServices
{
internal sealed class IsExternalInit { }
}
```
Everything else is the same as the standard .NET version. While the `required` keyword can't be used since it's from C# 11, using `init` alone is sufficient to guarantee immutability.
```csharp
public enum Gender
{
Male, Female, Unknown
}
// table definition marked by MemoryTableAttribute.
// database-table must be serializable by MessagePack-CSsharp
[MemoryTable("person"), MessagePackObject(true)]
public record Person
{
// index definition by attributes.
[PrimaryKey]
public int PersonId { get; init; }
// secondary index can add multiple(discriminated by index-number).
[SecondaryKey(0), NonUnique]
[SecondaryKey(1, keyOrder: 1), NonUnique]
public int Age { get; init; }
[SecondaryKey(2), NonUnique]
[SecondaryKey(1, keyOrder: 0), NonUnique]
public Gender Gender { get; init; }
public string Name { get; init; }
}
```
Also, for use with IL2CPP, you need to add the generated `MasterMemoryResolver` to MessagePack's Resolver. If you need other generated Resolvers, such as those from [MagicOnion](https://github.com/Cysharp/MagicOnion), please add and compose them here.
```csharp
public static class Initializer
{
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
public static void SetupMessagePackResolver()
{
// Create CompositeResolver
StaticCompositeResolver.Instance.Register(new[]{
MasterMemoryResolver.Instance, // set MasterMemory generated resolver
StandardResolver.Instance // set default MessagePack resolver
});
// Create options with resolver
var options = MessagePackSerializerOptions.Standard.WithResolver(StaticCompositeResolver.Instance);
// Optional: as default.
MessagePackSerializer.DefaultOptions = options;
}
}
```
DataTable configuration
---
Element type of datatable must be marked by `[MemoryTable(tableName)]`, datatable is generated from marked type. `string tableName` is saved in database binary, you can rename class name if tableName is same.
`[PrimaryKey(keyOrder = 0)]`, `[SecondaryKey(indexNo, keyOrder)]`, `[NonUnique]` can add to public property, `[PrimaryKey]` must use in MemoryTable, `[SecondaryKey]` is option.
Both `PrimaryKey` and `SecondaryKey` can add to multiple properties, it will be generated `***And***And***...`. `keyOrder` is order of column names, default is zero(sequential in which they appear).
```csharp
[MemoryTable("sample"), MessagePackObject(true)]
public class Sample
{
[PrimaryKey]
public int Foo { get; set; }
[PrimaryKey]
public int Bar { get; set; }
}
db.Sample.FindByFooAndBar((int Foo, int Bar))
// ----
[MemoryTable("sample"), MessagePackObject(true)]
public class Sample
{
[PrimaryKey(keyOrder: 1)]
public int Foo { get; set; }
[PrimaryKey(keyOrder: 0)]
public int Bar { get; set; }
}
db.Sample.FindByBarAndFoo((int Bar, int Foo))
```
Default of `FindBy***` return type is single(if not found, returns `null`). It means key is unique by default. If mark `[NonUnique]` in same AttributeList, return type is `RangeView<T>`(if not found, return empty).
```csharp
[MemoryTable("sample"), MessagePackObject(true)]
public class Sample
{
[PrimaryKey, NonUnique]
public int Foo { get; set; }
[PrimaryKey, NonUnique]
public int Bar { get; set; }
}
RangeView<Sample> q = db.Sample.FindByFooAndBar((int Foo, int Bar))
```
```csharp
[MemoryTable("sample"), MessagePackObject(true)]
public class Sample
{
[PrimaryKey]
[SecondaryKey(0)]
public int Foo { get; set; }
[SecondaryKey(0)]
[SecondaryKey(1)]
public int Bar { get; set; }
}
db.Sample.FindByFoo(int Foo)
db.Sample.FindByFooAndBar((int Foo, int Bar))
db.Sample.FindByBar(int Bar)
```
`[StringComparisonOption]` allow to configure how compare if key is string. Default is `Ordinal`.
```csharp
[MemoryTable("sample"), MessagePackObject(true)]
public class Sample
{
[PrimaryKey]
[StringComparisonOption(StringComparison.InvariantCultureIgnoreCase)]
public string Foo { get; set; }
}
```
If computation property exists, add `[IgnoreMember]` of MessagePack should mark.
```csharp
[MemoryTable("person"), MessagePackObject(true)]
public class Person
{
[PrimaryKey]
public int Id { get;}
public string FirstName { get; }
public string LastName { get; }
[IgnoreMember]
public string FullName => FirstName + LastName;
}
```
MemoryDatabase/RangeView
---
In default, `MemoryDatabase` do all string data automatically interning(see: [Wikipedia/String interning](https://en.wikipedia.org/wiki/String_interning)). If multiple same string value exists in database(ex: "goblin","goblin", "goblin", "goblin", "goblin"....), standard database creates string value per query or store multiple same values. But MasterMemory stores single string value reference, it can save much memory if data is denormalized.
Use intern or not is selected in constructor. If you want to disable automatically interning, use `internString:false`.
`MemoryDatabase(byte[] databaseBinary, bool internString = true, MessagePack.IFormatterResolver formatterResolver = null, int maxDegreeOfParallelism = 1)`.
MemoryDatabase has three(or four) query methods.
* `T|RangeView<T>` FindBy***(TKey key)
* bool TryFindBy***(TKey key, out T result)
* `T|RangeView<T>` FindClosestBy***(TKey key, bool selectLower = true)
* `RangeView<T>` FindRangeBy***(TKey min, TKey max, bool ascendant = true)
If index key is unique, generates `FindBy***` and `TryFindBy***` methods and then `FindBy***` throws `KeyNotFoundException` when key is not found.
`By***` is generated by `PrimaryKey` and `SecondaryKey` defines.
And has some utility properties.
* `int` Count
* `RangeView<T>` All
* `RangeView<T>` AllReverse
* `RangeView<T>` SortBy***
* `T[] GetRawDataUnsafe()`
`struct RangeView<T> : IEnumerable<T>` is the view of database elements. It has following property/method.
* `T` [int index]
* `int` Count
* `T` First
* `T` Last
* `RangeView<T>` Reverse
* `IEnumerator<T>` GetEnumerator()
Extend Table
---
Generated table class is defined partial class so create same namespace and class name's partial class on another file, you can add your custom method to generated table.
Table class also defined partial `OnAfterConstruct` method, it called after table has been constructed. You can use it to store custom data to field after all data has been constructed.
```csharp
// create MonsterTable.Partial.cs
public sealed partial class MonsterTable
{
int maxHp;
#pragma warning disable CS0649
readonly int minHp;
#pragma warning restore CS0649
// called after constructed
partial void OnAfterConstruct()
{
maxHp = All.Select(x => x.MaxHp).Max();
// you can use Unsafe.AsRef to set readonly field
Unsafe.AsRef(minHp) = All.Select(x => x.MaxHp).Min();
}
// add custom method other than standard Find method
public IEnumerable<Monster> GetRangedMonster(int arg1)
{
return All.Where....();
}
}
```
ImmutableBuilder
---
If you want to add/modify data to loaded database, you can use `ToImmutableBuilder` method.
```csharp
// Create ImmutableBuilder from original database.
var builder = db.ToImmutableBuilder();
// Add Or Replace compare with PrimaryKey
builder.Diff(addOrReplaceData);
// Remove by PrimaryKey
builder.RemovePerson(new[] { 1, 10, 100 });
// Replace all data
builder.ReplaceAll(newData);
// Finally create new database
MemoryDatabase newDatabase = builder.Build();
// If you want to save new database, you can convert to MemoryDatabase->DatabaseBuilder
var newBuilder = newDatabase.ToDatabaseBuilder();
var newBinary = newBuilder.Build(); // or use WriteToStream
```
MemoryDatabase's reference can use as snapshot.
```csharp
// 1 game per 1 instance
public class GameRoom
{
MemoryDatabase database;
// The reference is a snapshot of the timing of game begins.
public GameRoom(MemoryDatabase database)
{
this.database = database;
}
}
```
Validator
---
You can validate data by `MemoryDatabase.Validate` method. In default, it check unique key(data duplicated) and you can define custom validate logics.
```csharp
// Implements IValidatable<T> to targeted validation
[MemoryTable("quest_master"), MessagePackObject(true)]
public class Quest : IValidatable<Quest>
{
// If index is Unique, validate duplicate in default.
[PrimaryKey]
public int Id { get; }
public string Name { get; }
public int RewardId { get; }
public int Cost { get; }
void IValidatable<Quest>.Validate(IValidator<Quest> validator)
{
// get the external reference table
var items = validator.GetReferenceSet<Item>();
// Custom if logics.
if (this.RewardId > 0)
{
// RewardId must exists in Item.ItemId
items.Exists(x => x.RewardId, x => x.ItemId);
}
// Range check, Cost must be 10..20
validator.Validate(x => x.Cost >= 10);
validator.Validate(x => x.Cost <= 20);
// In this region, only called once so enable to validate overall of tables.
if (validator.CallOnce())
{
var quests = validator.GetTableSet();
// Check unique othe than index property.
quests.Where(x => x.RewardId != 0).Unique(x => x.RewardId);
}
}
}
[MemoryTable("item_master"), MessagePackObject(true)]
public class Item
{
[PrimaryKey]
public int ItemId { get; }
}
void Main()
{
var db = new MemoryDatabase(bin);
// Get the validate result.
var validateResult = db.Validate();
if (validateResult.IsValidationFailed)
{
// Output string format.
Console.WriteLine(validateResult.FormatFailedResults());
// Get the raw FaildItem[]. (.Type, .Message, .Data)
// validateResult.FailedResults
}
}
```
Following is list of validation methods.
```csharp
// all void methods are assert function, it stores message to ValidateResult if failed.
interface IValidator<T>
{
ValidatableSet<T> GetTableSet();
ReferenceSet<T, TRef> GetReferenceSet<TRef>();
void Validate(Expression<Func<T, bool>> predicate);
void Validate(Func<T, bool> predicate, string message);
void ValidateAction(Expression<Func<bool>> predicate);
void ValidateAction(Func<bool> predicate, string message);
void Fail(string message);
bool CallOnce();
}
class ReferenceSet<TElement, TReference>
{
IReadOnlyList<TReference> TableData { get; }
void Exists<TProperty>(Expression<Func<TElement, TProperty>> elementSelector, Expression<Func<TReference, TProperty>> referenceElementSelector);
void Exists<TProperty>(Expression<Func<TElement, TProperty>> elementSelector, Expression<Func<TReference, TProperty>> referenceElementSelector, EqualityComparer<TProperty> equalityComparer);
}
class ValidatableSet<TElement>
{
IReadOnlyList<TElement> TableData { get; }
void Unique<TProperty>(Expression<Func<TElement, TProperty>> selector);
void Unique<TProperty>(Expression<Func<TElement, TProperty>> selector, IEqualityComparer<TProperty> equalityComparer);
void Unique<TProperty>(Func<TElement, TProperty> selector, string message);
void Unique<TProperty>(Func<TElement, TProperty> selector, IEqualityComparer<TProperty> equalityComparer, string message);
void Sequential(Expression<Func<TElement, SByte|Int16|Int32|...>> selector, bool distinct = false);
ValidatableSet<TElement> Where(Func<TElement, bool> predicate);
}
```
Metadata
---
You can get the table-info, properties, indexes by metadata api. It helps to make custom importer/exporter application.
```csharp
var metaDb = MemoryDatabase.GetMetaDatabase();
foreach (var table in metaDb.GetTableInfos())
{
// for example, generate CSV header
var sb = new StringBuilder();
foreach (var prop in table.Properties)
{
if (sb.Length != 0) sb.Append(",");
// Name can convert to LowerCamelCase or SnakeCase.
sb.Append(prop.NameSnakeCase);
}
File.WriteAllText(table.TableName + ".csv", sb.ToString(), new UTF8Encoding(false));
}
```
If creates console-app, our [ConsoleAppFramework](https://github.com/Cysharp/ConsoleAppFramework/) can easy to make helper applications.
Here is sample of reading and creating dynamic from csv. `builder.AppendDynamic` and `System.Runtime.Serialization.FormatterServices.GetUninitializedObject` will help it.
```csharp
var csv = @"monster_id,name,max_hp
1,foo,100
2,bar,200";
var fileName = "monster";
var builder = new DatabaseBuilder();
var meta = MemoryDatabase.GetMetaDatabase();
var table = meta.GetTableInfo(fileName);
var tableData = new List<object>();
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(csv)))
using (var sr = new StreamReader(ms, Encoding.UTF8))
using (var reader = new TinyCsvReader(sr))
{
while ((reader.ReadValuesWithHeader() is Dictionary<string, string> values))
{
// create data without call constructor
// use System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject instead on .NET 8
var data = System.Runtime.Serialization.FormatterServices.GetUninitializedObject(table.DataType);
foreach (var prop in table.Properties)
{
if (values.TryGetValue(prop.NameSnakeCase, out var rawValue))
{
var value = ParseValue(prop.PropertyInfo.PropertyType, rawValue);
if (prop.PropertyInfo.SetMethod == null)
{
throw new Exception("Target property does not exists set method. If you use {get;}, please change to { get; private set; }, Type:" + prop.PropertyInfo.DeclaringType + " Prop:" + prop.PropertyInfo.Name);
}
prop.PropertyInfo.SetValue(data, value);
}
else
{
throw new KeyNotFoundException($"Not found \"{prop.NameSnakeCase}\" in \"{fileName}.csv\" header.");
}
}
tableData.Add(data);
}
}
// add dynamic collection.
builder.AppendDynamic(table.DataType, tableData);
var bin = builder.Build();
var database = new MemoryDatabase(bin);
static object ParseValue(Type type, string rawValue)
{
if (type == typeof(string)) return rawValue;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
if (string.IsNullOrWhiteSpace(rawValue)) return null;
return ParseValue(type.GenericTypeArguments[0], rawValue);
}
if (type.IsEnum)
{
var value = Enum.Parse(type, rawValue);
return value;
}
switch (Type.GetTypeCode(type))
{
case TypeCode.Boolean:
// True/False or 0,1
if (int.TryParse(rawValue, out var intBool))
{
return Convert.ToBoolean(intBool);
}
return Boolean.Parse(rawValue);
case TypeCode.Char:
return Char.Parse(rawValue);
case TypeCode.SByte:
return SByte.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Byte:
return Byte.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Int16:
return Int16.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.UInt16:
return UInt16.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Int32:
return Int32.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.UInt32:
return UInt32.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Int64:
return Int64.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.UInt64:
return UInt64.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Single:
return Single.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Double:
return Double.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Decimal:
return Decimal.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.DateTime:
return DateTime.Parse(rawValue, CultureInfo.InvariantCulture);
default:
if (type == typeof(DateTimeOffset))
{
return DateTimeOffset.Parse(rawValue, CultureInfo.InvariantCulture);
}
else if (type == typeof(TimeSpan))
{
return TimeSpan.Parse(rawValue, CultureInfo.InvariantCulture);
}
else if (type == typeof(Guid))
{
return Guid.Parse(rawValue);
}
// or other your custom parsing.
throw new NotSupportedException();
}
}
// Non string escape, tiny reader with header.
public class TinyCsvReader : IDisposable
{
static char[] trim = new[] { ' ', '\t' };
readonly StreamReader reader;
public IReadOnlyList<string> Header { get; private set; }
public TinyCsvReader(StreamReader reader)
{
this.reader = reader;
{
var line = reader.ReadLine();
if (line == null) throw new InvalidOperationException("Header is null.");
var index = 0;
var header = new List<string>();
while (index < line.Length)
{
var s = GetValue(line, ref index);
if (s.Length == 0) break;
header.Add(s);
}
this.Header = header;
}
}
string GetValue(string line, ref int i)
{
var temp = new char[line.Length - i];
var j = 0;
for (; i < line.Length; i++)
{
if (line[i] == ',')
{
i += 1;
break;
}
temp[j++] = line[i];
}
return new string(temp, 0, j).Trim(trim);
}
public string[] ReadValues()
{
var line = reader.ReadLine();
if (line == null) return null;
if (string.IsNullOrWhiteSpace(line)) return null;
var values = new string[Header.Count];
var lineIndex = 0;
for (int i = 0; i < values.Length; i++)
{
var s = GetValue(line, ref lineIndex);
values[i] = s;
}
return values;
}
public Dictionary<string, string> ReadValuesWithHeader()
{
var values = ReadValues();
if (values == null) return null;
var dict = new Dictionary<string, string>();
for (int i = 0; i < values.Length; i++)
{
dict.Add(Header[i], values[i]);
}
return dict;
}
public void Dispose()
{
reader.Dispose();
}
}
}
```
Inheritance
---
Currently MasterMemory does not support inheritance. Recommend way to create common method, use interface and extension method. But if you want to create common method with common cached field(made by `OnAfterConstruct`), for workaround, create abstract class and all data properties to abstract.
```csharp
public abstract class FooAndBarBase
{
// all data properties to virtual
public virtual int Prop1 { get; protected set; }
public virtual int Prop2 { get; protected set; }
[IgnoreMember]
public int Prop3 => Prop1 + Prop2;
public IEnumerable<FooAndBarBase> CommonMethod()
{
throw new NotImplementedException();
}
}
[MemoryTable("foo_table"), MessagePackObject(true)]
public class FooTable : FooAndBarBase
{
[PrimaryKey]
public override int Prop1 { get; protected set; }
public override int Prop2 { get; protected set; }
}
[MemoryTable("bar_table"), MessagePackObject(true)]
public class BarTable : FooAndBarBase
{
[PrimaryKey]
public override int Prop1 { get; protected set; }
public override int Prop2 { get; protected set; }
}
```
Optimization
---
When invoking `new MemoryDatabase(byte[] databaseBinary...)`, read and construct database from binary. If binary size is large then construct performance will slow down. `MemoryDatabase` has `ctor(..., int maxDegreeOfParallelism = 1)` option in constructor to construct in parallel.
```csharp
var database = new MemoryDatabase(bin, maxDegreeOfParallelism: Environment.ProcessorCount);
```
The use of Parallel can greatly improve the construct performance. Recommend to use `Environment.ProcessorCount`.
If you want to reduce code size of generated code, Validator and MetaDatabase info can omit in runtime. Generated code has two symbols `DISABLE_MASTERMEMORY_VALIDATOR` and `DISABLE_MASTERMEMORY_METADATABASE`. By defining them, can be erased from the build code.
The database generation/loading speed and size are affected by MessagePack's serialization format. Using `[MessagePackObject]` with `[Key]` attributes instead of `[MessagePackObject(true)]` can improve loading speed and reduce size. However, regarding size, since LZ4 compression is used by default, the difference may not be significant.
MasterMemoryGeneratorOptions
---
The Source Generator settings are configured using the assembly attribute `[MasterMemoryGeneratorOptions]`. By placing it in any file, you can configure the following settings.
```csharp
[assembly: MasterMemoryGeneratorOptions(
Namespace = "MyConsoleApp",
IsReturnNullIfKeyNotFound = true,
PrefixClassName = "Foo"
)]
```
* `Namespace`: Changes the namespace of generated files. If not specified, it tries to get the `RootNamespace` set in the csproj file; if that's not available, it defaults to `MasterMemory`
* `IsReturnNullIfKeyNotFound`: By default, the `Find` method throws a `KeyNotFoundException` when a key is not found. If set to true, the return type becomes `T?` and returns null instead
* `PrefixClassName`: Adds a prefix to the class names of generated files. For example, `DatabaseBuilder` becomes `FooDatabaseBuilder`. This allows you to distinguish between multiple MasterMemory projects by name.
v2 -> v3 migration
---
Since there are no changes to the API, binary format, or behavior, you can migrate simply by changing the command-line tool settings to the assembly attribute `[MasterMemoryGeneratorOptions]`.
* The code generator (MSBuild Task, .NET Core Global/Local Tools) has been removed and replaced with Source Generator
* Tool options are now available through `MasterMemoryGeneratorOptions` (e.g. `-usingNamespace`)
* The `-addImmutableConstructor` option has been completely removed; please use C#'s record or init keyword instead
* The library is now only available through NuGet for Unity. Please use NuGetForUnity
License
---
This library is under the MIT License.
================================================
FILE: sandbox/Benchmark/Benchmark.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<NoWarn>1701;1702;NU1904</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" />
<PackageReference Include="EnyimMemcachedCore" Version="2.2.4" />
<PackageReference Include="FASTER" Version="2019.4.24.4" />
<PackageReference Include="LiteDB" Version="4.1.4" />
<PackageReference Include="RocksDbNative" Version="5.17.2" />
<PackageReference Include="RocksDbSharp" Version="5.17.2" />
<PackageReference Include="System.Data.SQLite" Version="1.0.111" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\MasterMemory.Annotations\MasterMemory.Annotations.csproj" />
<ProjectReference Include="..\..\src\MasterMemory\MasterMemory.csproj" />
<ProjectReference Include="..\..\src\MasterMemory.SourceGenerator\MasterMemory.SourceGenerator.csproj">
<OutputItemType>Analyzer</OutputItemType>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
</Project>
================================================
FILE: sandbox/Benchmark/Program.cs
================================================
#pragma warning disable
using BenchmarkDotNet.Attributes;
using System.Linq;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Exporters.Csv;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using LiteDB;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.IO;
using TestPerfLiteDB;
using Enyim.Caching;
using Enyim.Caching.Configuration;
using Enyim.Caching.Memcached;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
using Enyim.Caching.Memcached.Transcoders;
using RocksDbSharp;
using MessagePack;
using System.Text;
namespace Benchmark
{
class Program
{
static void Main(string[] args)
{
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
}
}
public class BenchmarkConfig : ManualConfig
{
public BenchmarkConfig()
{
// run quickly:)
var baseConfig = Job.ShortRun.WithIterationCount(1).WithWarmupCount(1);
// Add(baseConfig.With(Runtime.Clr).With(Jit.RyuJit).With(Platform.X64));
Add(baseConfig.With(Runtime.Core).With(Jit.RyuJit).With(Platform.X64));
// Add(baseConfig.With(InProcessEmitToolchain.Instance));
Add(MarkdownExporter.GitHub);
Add(CsvExporter.Default);
Add(MemoryDiagnoser.Default);
}
}
[Config(typeof(BenchmarkConfig))]
public class SimpleRun
{
MemoryDatabase db;
SQLite_Test sqliteMemory;
SQLite_Test sqliteFile;
LiteDB_Test defaultLiteDb;
LiteDB_Test inmemoryLiteDb;
LiteDB_Test2 liteDb2;
MemcachedClient localMemcached;
Dictionary<int, TestDoc> dictionary;
RocksDb rocksDb;
const int QueryId = 741;
public SimpleRun()
{
var bin = new DatabaseBuilder().Append(MakeDoc(5000)).Build();
db = new MemoryDatabase(bin);
sqliteMemory = new SQLite_Test(5000, null, false, true);
sqliteMemory.Prepare(); sqliteMemory.Insert(); sqliteMemory.CreateIndex();
sqliteFile = new SQLite_Test(5000, null, false, false);
sqliteFile.Prepare(); sqliteFile.Insert(); sqliteFile.CreateIndex();
defaultLiteDb = new LiteDB_Test(5000, null, new LiteDB.FileOptions { Journal = true, FileMode = LiteDB.FileMode.Shared });
defaultLiteDb.Prepare(); defaultLiteDb.Insert(); defaultLiteDb.CreateIndex();
inmemoryLiteDb = new LiteDB_Test(5000);
inmemoryLiteDb.Prepare(); inmemoryLiteDb.Insert(); inmemoryLiteDb.CreateIndex();
liteDb2 = new LiteDB_Test2(5000);
liteDb2.Prepare(); liteDb2.Insert(); liteDb2.CreateIndex();
dictionary = new Dictionary<int, TestDoc>();
foreach (var item in MakeDoc(5000))
{
dictionary.Add(item.id, item);
}
{
var options = new DbOptions().SetCreateIfMissing(true);
var tempPath = Guid.NewGuid() + ".bin";
rocksDb = RocksDb.Open(options, tempPath);
foreach (var item in MakeDoc(5000))
{
rocksDb.Put(Encoding.UTF8.GetBytes("testdata." + item.id), MessagePackSerializer.Serialize(item));
}
}
var config = new MemcachedClientConfiguration(new LoggerDummy(), new Dummy());
localMemcached = new MemcachedClient(new LoggerDummy(), config);
foreach (var item in MakeDoc(5000))
{
localMemcached.Add("testdoc2." + item.id, item, 9999);
}
}
public IEnumerable<TestDoc> MakeDoc(int count)
{
foreach (var doc in Helper.GetDocs(count))
{
var v = new TestDoc
{
id = (int)doc["_id"],
name = (string)doc["name"],
lorem = (string)doc["lorem"]
};
yield return v;
}
}
[Benchmark(Baseline = true)]
public TestDoc MasterMemoryQuery()
{
return db.TestDocTable.FindByid(QueryId);
}
[Benchmark]
public TestDoc SQLiteInMemoryQuery()
{
using (var cmd = new SQLiteCommand("SELECT * FROM col WHERE id = @id", sqliteMemory._db))
{
cmd.Parameters.Add(new SQLiteParameter("id", DbType.Int32));
cmd.Parameters["id"].Value = QueryId;
using (var r = cmd.ExecuteReader())
{
r.Read();
var id = r.GetInt32(0);
var name = r.GetString(1);
var lorem = r.GetString(2);
return new TestDoc { id = 1, name = name, lorem = lorem };
}
}
}
[Benchmark]
public TestDoc SQLiteFileQuery()
{
using (var cmd = new SQLiteCommand("SELECT * FROM col WHERE id = @id", sqliteFile._db))
{
cmd.Parameters.Add(new SQLiteParameter("id", DbType.Int32));
cmd.Parameters["id"].Value = QueryId;
using (var r = cmd.ExecuteReader())
{
r.Read();
var id = r.GetInt32(0);
var name = r.GetString(1);
var lorem = r.GetString(2);
return new TestDoc { id = 1, name = name, lorem = lorem };
}
}
}
[Benchmark]
public BsonDocument LiteDbDefaultQuery()
{
return defaultLiteDb._db.FindOne("col", LiteDB.Query.EQ("_id", QueryId));
}
[Benchmark]
public BsonDocument LiteDbInMemoryQuery()
{
return inmemoryLiteDb._db.FindOne("col", LiteDB.Query.EQ("_id", QueryId));
}
[Benchmark]
public object LocalMemcachedQuery()
{
return localMemcached.Get("testdoc2." + QueryId);
}
//[Benchmark]
//public TestDoc DictionaryQuery()
//{
// return dictionary.TryGetValue(QueryId, out var r) ? r : null;
//}
[Benchmark]
public TestDoc RocksDbQuery()
{
return MessagePackSerializer.Deserialize<TestDoc>(rocksDb.Get(Encoding.UTF8.GetBytes("testdata." + QueryId)));
}
}
public class SQLite_Test
{
private string _filename;
public SQLiteConnection _db;
private int _count;
public int Count { get { return _count; } }
public SQLite_Test(int count, string password, bool journal, bool memory = false)
{
_count = count;
_filename = "sqlite-" + Guid.NewGuid().ToString("n") + ".db";
if (memory)
{
var cs = "Data Source=:memory:;New=True;";
_db = new SQLiteConnection(cs);
}
else
{
var cs = "Data Source=" + _filename;
if (password != null) cs += "; Password=" + password;
if (journal == false) cs += "; Journal Mode=Off";
_db = new SQLiteConnection(cs);
}
}
public void Prepare()
{
_db.Open();
var table = new SQLiteCommand("CREATE TABLE col (id INTEGER NOT NULL PRIMARY KEY, name TEXT, lorem TEXT)", _db);
table.ExecuteNonQuery();
var table2 = new SQLiteCommand("CREATE TABLE col_bulk (id INTEGER NOT NULL PRIMARY KEY, name TEXT, lorem TEXT)", _db);
table2.ExecuteNonQuery();
}
public void Insert()
{
// standard insert is slow, mod same as Bulk
using (var trans = _db.BeginTransaction())
{
var cmd = new SQLiteCommand("INSERT INTO col (id, name, lorem) VALUES (@id, @name, @lorem)", _db);
cmd.Parameters.Add(new SQLiteParameter("id", DbType.Int32));
cmd.Parameters.Add(new SQLiteParameter("name", DbType.String));
cmd.Parameters.Add(new SQLiteParameter("lorem", DbType.String));
foreach (var doc in Helper.GetDocs(_count))
{
cmd.Parameters["id"].Value = (int)doc["_id"];
cmd.Parameters["name"].Value = (string)doc["name"];
cmd.Parameters["lorem"].Value = (string)doc["lorem"];
cmd.ExecuteNonQuery();
}
trans.Commit();
}
}
public void CreateIndex()
{
var cmd = new SQLiteCommand("CREATE INDEX idx1 ON col (name)", _db);
cmd.ExecuteNonQuery();
}
public void Query()
{
var cmd = new SQLiteCommand("SELECT * FROM col WHERE id = @id", _db);
cmd.Parameters.Add(new SQLiteParameter("id", DbType.Int32));
for (var i = 0; i < _count; i++)
{
cmd.Parameters["id"].Value = i;
var r = cmd.ExecuteReader();
r.Read();
var name = r.GetString(1);
var lorem = r.GetString(2);
r.Close();
}
}
public void Dispose()
{
_db.Dispose();
}
}
public class LiteDB_Test
{
private string _filename;
public LiteEngine _db;
private int _count;
public int Count { get { return _count; } }
public LiteDB_Test(int count, string password, LiteDB.FileOptions options)
{
_count = count;
_filename = "dblite-" + Guid.NewGuid().ToString("n") + ".db";
var disk = new FileDiskService(_filename, options);
_db = new LiteEngine(disk, password);
}
public LiteDB_Test(int count)
{
_count = count;
_filename = "dblite-" + Guid.NewGuid().ToString("n") + ".db";
var ms = new MemoryStream();
var disk = new LiteDB.StreamDiskService(ms);
//var disk = new FileDiskService(_filename, options);
_db = new LiteEngine(disk);
}
public void Prepare()
{
}
public void Insert()
{
foreach (var doc in Helper.GetDocs(_count))
{
_db.Insert("col", doc);
}
}
public void Bulk()
{
_db.Insert("col_bulk", Helper.GetDocs(_count));
}
public void Update()
{
foreach (var doc in Helper.GetDocs(_count))
{
_db.Update("col", doc);
}
}
public void CreateIndex()
{
_db.EnsureIndex("col", "name", false);
}
public void Query()
{
for (var i = 0; i < _count; i++)
{
_db.Find("col", LiteDB.Query.EQ("_id", i)).Single();
}
}
public void Delete()
{
_db.Delete("col", LiteDB.Query.All());
}
public void Drop()
{
_db.DropCollection("col_bulk");
}
public void Dispose()
{
_db.Dispose();
File.Delete(_filename);
}
}
public class LiteDB_Test2
{
private string _filename;
public LiteDatabase _db;
private int _count;
public LiteCollection<TestDoc> _collection;
public int Count { get { return _count; } }
public LiteDB_Test2(int count, string password, LiteDB.FileOptions options)
{
_count = count;
_filename = "dblite-" + Guid.NewGuid().ToString("n") + ".db";
var disk = new FileDiskService(_filename, options);
_db = new LiteDatabase(disk);
_collection = _db.GetCollection<TestDoc>();
}
public LiteDB_Test2(int count)
{
_count = count;
_filename = "dblite-" + Guid.NewGuid().ToString("n") + ".db";
var ms = new MemoryStream();
var disk = new LiteDB.StreamDiskService(ms);
//var disk = new FileDiskService(_filename, options);
_db = new LiteDatabase(disk);
_collection = _db.GetCollection<TestDoc>();
}
public void Prepare()
{
}
public void Insert()
{
foreach (var doc in Helper.GetDocs(_count))
{
_collection.Insert(new TestDoc
{
// id = (int)doc["_id"],
name = (string)doc["name"],
lorem = (string)doc["lorem"]
});
}
}
public void CreateIndex()
{
//_collection.EnsureIndex(x => x.id, true);
}
}
class Dummy : IOptions<MemcachedClientOptions>
{
public MemcachedClientOptions Value => new MemcachedClientOptions
{
Servers = new List<Server> { new Server { Address = "127.0.0.1", Port = 11211 } },
Protocol = MemcachedProtocol.Binary,
// Transcoder = new BinaryFormatterTranscoder()
};
}
class LoggerDummy : ILoggerFactory
{
public void AddProvider(ILoggerProvider provider)
{
}
public ILogger CreateLogger(string categoryName)
{
return new NullLogger();
}
public void Dispose()
{
}
class NullLogger : ILogger
{
public IDisposable BeginScope<TState>(TState state)
{
return new EmptyDisposable();
}
public bool IsEnabled(LogLevel logLevel)
{
return false;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
}
class EmptyDisposable : IDisposable
{
public void Dispose()
{
}
}
}
}
}
================================================
FILE: sandbox/Benchmark/Utils/Helper.cs
================================================
#pragma warning disable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MessagePack;
using LiteDB;
using MasterMemory;
namespace TestPerfLiteDB
{
[MemoryTable("TestDoc"), MessagePackObject(true)]
public class TestDoc
{
[PrimaryKey]
public int id { get; set; }
public string name { get; set; }
public string lorem { get; set; }
public TestDoc()
{
}
public TestDoc(int id, string name, string lorem)
{
this.id = id;
this.name = name;
this.lorem = lorem;
}
}
public static class Helper
{
public static IEnumerable<BsonDocument> GetDocs(int count)
{
for (var i = 0; i < count; i++)
{
yield return new BsonDocument
{
{ "_id", i },
{ "name", Guid.NewGuid().ToString() },
{ "lorem", LoremIpsum(3, 5, 2, 3, 3) }
};
}
}
public static string LoremIpsum(int minWords, int maxWords,
int minSentences, int maxSentences,
int numParagraphs)
{
var words = new[] { "lorem", "ipsum", "dolor", "sit", "amet", "consectetuer",
"adipiscing", "elit", "sed", "diam", "nonummy", "nibh", "euismod",
"tincidunt", "ut", "laoreet", "dolore", "magna", "aliquam", "erat" };
var rand = new Random(DateTime.Now.Millisecond);
var numSentences = rand.Next(maxSentences - minSentences) + minSentences + 1;
var numWords = rand.Next(maxWords - minWords) + minWords + 1;
var result = new StringBuilder();
for (int p = 0; p < numParagraphs; p++)
{
for (int s = 0; s < numSentences; s++)
{
for (int w = 0; w < numWords; w++)
{
if (w > 0) { result.Append(" "); }
result.Append(words[rand.Next(words.Length)]);
}
result.Append(". ");
}
result.AppendLine();
}
return result.ToString();
}
}
}
================================================
FILE: sandbox/ConsoleApp/ConsoleApp.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>$(DefineConstants)TRACE;</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>$(DefineConstants)TRACE;</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\MasterMemory.Annotations\MasterMemory.Annotations.csproj" />
<ProjectReference Include="..\..\src\MasterMemory\MasterMemory.csproj" />
<ProjectReference Include="..\..\src\MasterMemory.SourceGenerator\MasterMemory.SourceGenerator.csproj">
<OutputItemType>Analyzer</OutputItemType>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
</Project>
================================================
FILE: sandbox/ConsoleApp/Program.cs
================================================
#pragma warning disable CS8618
#pragma warning disable CS8602
#pragma warning disable CS8603
using MasterMemory;
using MessagePack;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
[assembly: MasterMemoryGeneratorOptions(
Namespace = "ConsoleApp" // ,
// IsReturnNullIfKeyNotFound = true,
// PrefixClassName = "Foo"
)]
public class FooItem
{
public bool TryFindByItemId(int key, out Item result)
{
result = default!;
return true;
}
}
[MemoryTable("quest_master"), MessagePackObject(true)]
public class Quest : IValidatable<Quest>
{
[PrimaryKey]
public int Id { get; set; }
public string Name { get; set; }
public int RewardId { get; set; }
public int Cost { get; set; }
public MyEnum MyProperty { get; set; }
void IValidatable<Quest>.Validate(IValidator<Quest> validator)
{
var items = validator.GetReferenceSet<Item>();
if (this.RewardId > 0)
{
items.Exists(x => x.RewardId, x => x.ItemId);
}
validator.Validate(x => x.Cost >= 10);
validator.Validate(x => x.Cost <= 20);
if (validator.CallOnce())
{
var quests = validator.GetTableSet();
quests.Where(x => x.RewardId != 0).Unique(x => x.RewardId);
}
}
public enum MyEnum
{
A, B, C
}
}
[MemoryTable("item"), MessagePackObject(true)]
public class Item
{
[PrimaryKey]
public int ItemId { get; set; }
}
namespace ConsoleApp.Tables
{
public sealed partial class MonsterTable
{
/* readonly */
int maxHp;
partial void OnAfterConstruct()
{
maxHp = All.Select(x => x.MaxHp).Max();
}
}
}
namespace ConsoleApp
{
[MemoryTable("monster"), MessagePackObject(true)]
public partial class Monster
{
[PrimaryKey]
public int MonsterId { get; private set; }
public string Name { get; private set; }
public int MaxHp { get; private set; }
public Monster(int MonsterId, string Name, int MaxHp)
{
this.MonsterId = MonsterId;
this.Name = Name;
this.MaxHp = MaxHp;
}
}
[MemoryTable("enumkeytable"), MessagePackObject(true)]
public class EnumKeyTable
{
[PrimaryKey]
public Gender Gender { get; set; }
}
public enum Gender
{
Male, Female
}
[MemoryTable("person"), MessagePackObject(true)]
public class Person
{
[PrimaryKey(keyOrder: 1)]
public int PersonId { get; set; }
[SecondaryKey(0), NonUnique]
[SecondaryKey(2, keyOrder: 1), NonUnique]
public int Age { get; set; }
[SecondaryKey(1), NonUnique]
[SecondaryKey(2, keyOrder: 0), NonUnique]
public Gender Gender { get; set; }
public string Name { get; set; }
public Person()
{
}
public Person(int PersonId, int Age, Gender Gender, string Name)
{
this.PersonId = PersonId;
this.Age = Age;
this.Gender = Gender;
this.Name = Name;
}
public override string ToString()
{
return $"{PersonId} {Age} {Gender} {Name}";
}
}
class ByteBufferWriter : IBufferWriter<byte>
{
byte[] buffer;
int index;
public int CurrentOffset => index;
public ReadOnlySpan<byte> WrittenSpan => buffer.AsSpan(0, index);
public ReadOnlyMemory<byte> WrittenMemory => new ReadOnlyMemory<byte>(buffer, 0, index);
public ByteBufferWriter()
{
buffer = new byte[1024];
index = 0;
}
public void Advance(int count)
{
index += count;
}
public Memory<byte> GetMemory(int sizeHint = 0)
{
AGAIN:
var nextSize = index + sizeHint;
if (buffer.Length < nextSize)
{
Array.Resize(ref buffer, Math.Max(buffer.Length * 2, nextSize));
}
if (sizeHint == 0)
{
var result = new Memory<byte>(buffer, index, buffer.Length - index);
if (result.Length == 0)
{
sizeHint = 1024;
goto AGAIN;
}
return result;
}
else
{
return new Memory<byte>(buffer, index, sizeHint);
}
}
public Span<byte> GetSpan(int sizeHint = 0)
{
return GetMemory(sizeHint).Span;
}
}
[MemoryTable(nameof(Test1))]
public class Test1
{
[PrimaryKey]
public int Id { get; set; }
}
[MessagePackObject(false)]
[MemoryTable(nameof(Test2))]
public class Test2
{
[PrimaryKey]
[Key(0)]
public int Id { get; set; }
}
class Program
{
static void Main(string[] args)
{
var csv = @"monster_id,name,max_hp
1,foo,100
2,bar,200";
var fileName = "monster";
var builder = new DatabaseBuilder();
var meta = MemoryDatabase.GetMetaDatabase();
var table = meta.GetTableInfo(fileName);
var tableData = new List<object>();
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(csv)))
using (var sr = new StreamReader(ms, Encoding.UTF8))
using (var reader = new TinyCsvReader(sr))
{
while ((reader.ReadValuesWithHeader() is Dictionary<string, string> values))
{
// create data without call constructor
var data = RuntimeHelpers.GetUninitializedObject(table.DataType);
foreach (var prop in table.Properties)
{
if (values.TryGetValue(prop.NameSnakeCase, out var rawValue))
{
var value = ParseValue(prop.PropertyInfo.PropertyType, rawValue);
if (prop.PropertyInfo.SetMethod == null)
{
throw new Exception("Target property does not exists set method. If you use {get;}, please change to { get; private set; }, Type:" + prop.PropertyInfo.DeclaringType + " Prop:" + prop.PropertyInfo.Name);
}
prop.PropertyInfo.SetValue(data, value);
}
else
{
throw new KeyNotFoundException($"Not found \"{prop.NameSnakeCase}\" in \"{fileName}.csv\" header.");
}
}
tableData.Add(data);
}
}
// add dynamic collection.
builder.AppendDynamic(table.DataType, tableData);
var bin = builder.Build();
var database = new MemoryDatabase(bin, maxDegreeOfParallelism: Environment.ProcessorCount);
}
static object ParseValue(Type type, string rawValue)
{
if (type == typeof(string)) return rawValue;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
if (string.IsNullOrWhiteSpace(rawValue)) return null;
return ParseValue(type.GenericTypeArguments[0], rawValue);
}
if (type.IsEnum)
{
var value = Enum.Parse(type, rawValue);
return value;
}
switch (Type.GetTypeCode(type))
{
case TypeCode.Boolean:
// True/False or 0,1
if (int.TryParse(rawValue, out var intBool))
{
return Convert.ToBoolean(intBool);
}
return Boolean.Parse(rawValue);
case TypeCode.Char:
return Char.Parse(rawValue);
case TypeCode.SByte:
return SByte.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Byte:
return Byte.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Int16:
return Int16.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.UInt16:
return UInt16.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Int32:
return Int32.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.UInt32:
return UInt32.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Int64:
return Int64.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.UInt64:
return UInt64.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Single:
return Single.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Double:
return Double.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.Decimal:
return Decimal.Parse(rawValue, CultureInfo.InvariantCulture);
case TypeCode.DateTime:
return DateTime.Parse(rawValue, CultureInfo.InvariantCulture);
default:
if (type == typeof(DateTimeOffset))
{
return DateTimeOffset.Parse(rawValue, CultureInfo.InvariantCulture);
}
else if (type == typeof(TimeSpan))
{
return TimeSpan.Parse(rawValue, CultureInfo.InvariantCulture);
}
else if (type == typeof(Guid))
{
return Guid.Parse(rawValue);
}
// or other your custom parsing.
throw new NotSupportedException();
}
}
// Non string escape, tiny reader with header.
public class TinyCsvReader : IDisposable
{
static char[] trim = new[] { ' ', '\t' };
readonly StreamReader reader;
public IReadOnlyList<string> Header { get; private set; }
public TinyCsvReader(StreamReader reader)
{
this.reader = reader;
{
var line = reader.ReadLine();
if (line == null) throw new InvalidOperationException("Header is null.");
var index = 0;
var header = new List<string>();
while (index < line.Length)
{
var s = GetValue(line, ref index);
if (s.Length == 0) break;
header.Add(s);
}
this.Header = header;
}
}
string GetValue(string line, ref int i)
{
var temp = new char[line.Length - i];
var j = 0;
for (; i < line.Length; i++)
{
if (line[i] == ',')
{
i += 1;
break;
}
temp[j++] = line[i];
}
return new string(temp, 0, j).Trim(trim);
}
public string[] ReadValues()
{
var line = reader.ReadLine();
if (line == null) return null;
if (string.IsNullOrWhiteSpace(line)) return null;
var values = new string[Header.Count];
var lineIndex = 0;
for (int i = 0; i < values.Length; i++)
{
var s = GetValue(line, ref lineIndex);
values[i] = s;
}
return values;
}
public Dictionary<string, string> ReadValuesWithHeader()
{
var values = ReadValues();
if (values == null) return null;
var dict = new Dictionary<string, string>();
for (int i = 0; i < values.Length; i++)
{
dict.Add(Header[i], values[i]);
}
return dict;
}
public void Dispose()
{
reader.Dispose();
}
}
}
}
================================================
FILE: sandbox/GeneratorSandbox/GeneratorSandbox.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MessagePack" Version="3.1.3" />
</ItemGroup>
<!-- for testing... -->
<!--<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(ProjectDir).\Generated</CompilerGeneratedFilesOutputPath>
</PropertyGroup>-->
<ItemGroup>
<ProjectReference Include="..\..\src\MasterMemory\MasterMemory.csproj" />
<ProjectReference Include="..\..\src\MasterMemory.Annotations\MasterMemory.Annotations.csproj" />
<ProjectReference Include="..\..\src\MasterMemory.SourceGenerator\MasterMemory.SourceGenerator.csproj">
<OutputItemType>Analyzer</OutputItemType>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
</Project>
================================================
FILE: sandbox/GeneratorSandbox/Program.cs
================================================
using MasterMemory;
using MessagePack;
using GeneratorSandbox;
using System.Runtime.CompilerServices;
//[assembly: MasterMemoryGeneratorOptions(
// Namespace = "Z",
// IsReturnNullIfKeyNotFound = true,
// PrefixClassName = "")]
// to create database, use DatabaseBuilder and Append method.
var builder = new DatabaseBuilder();
builder.Append(new Person[]
{
new (){ PersonId = 0, Age = 13, Gender = Gender.Male, Name = "Dana Terry" },
new (){ PersonId = 1, Age = 17, Gender = Gender.Male, Name = "Kirk Obrien" },
new (){ PersonId = 2, Age = 31, Gender = Gender.Male, Name = "Wm Banks" },
new (){ PersonId = 3, Age = 44, Gender = Gender.Male, Name = "Karl Benson" },
new (){ PersonId = 4, Age = 23, Gender = Gender.Male, Name = "Jared Holland" },
new (){ PersonId = 5, Age = 27, Gender = Gender.Female, Name = "Jeanne Phelps" },
new (){ PersonId = 6, Age = 25, Gender = Gender.Female, Name = "Willie Rose" },
new (){ PersonId = 7, Age = 11, Gender = Gender.Female, Name = "Shari Gutierrez" },
new (){ PersonId = 8, Age = 63, Gender = Gender.Female, Name = "Lori Wilson" },
new (){ PersonId = 9, Age = 34, Gender = Gender.Female, Name = "Lena Ramsey" },
});
// build database binary(you can also use `WriteToStream` for save to file).
byte[] data = builder.Build();
var db = new MemoryDatabase(data);
// .PersonTable.FindByPersonId is fully typed by code-generation.
Person person = db.PersonTable.FindByPersonId(5);
// Multiple key is also typed(***And * **), Return value is multiple if key is marked with `NonUnique`.
RangeView<Person> result = db.PersonTable.FindByGenderAndAge((Gender.Female, 23));
// Get nearest value(choose lower(default) or higher).
RangeView<Person> age1 = db.PersonTable.FindClosestByAge(31);
// Get range(min-max inclusive).
RangeView<Person> age2 = db.PersonTable.FindRangeByAge(20, 29);
public enum Gender
{
Male, Female, Unknown
}
// table definition marked by MemoryTableAttribute.
// database-table must be serializable by MessagePack-CSsharp
[MemoryTable("person"), MessagePackObject(true)]
public record Person
{
// index definition by attributes.
[PrimaryKey]
public required int PersonId { get; init; }
// secondary index can add multiple(discriminated by index-number).
[SecondaryKey(0), NonUnique]
[SecondaryKey(1, keyOrder: 1), NonUnique]
public required int Age { get; init; }
[SecondaryKey(2), NonUnique]
[SecondaryKey(1, keyOrder: 0), NonUnique]
public required Gender Gender { get; init; }
public required string Name { get; init; }
}
================================================
FILE: sandbox/PerfTest2/Engines/Dictionary_Test.cs
================================================
#pragma warning disable
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TestPerfLiteDB;
namespace TestPerfLiteDB
{
public class Dictionary_Test : ITest
{
private string _filename;
private int _count;
Dictionary<int, TestDoc> dict;
public int Count { get { return _count; } }
public int FileLength { get { return (int)new FileInfo(_filename).Length; } }
public Dictionary_Test(int count)
{
_count = count;
_filename = "dict-" + Guid.NewGuid().ToString("n") + ".db";
dict = new Dictionary<int, TestPerfLiteDB.TestDoc>();
}
public void Insert()
{
foreach (var doc in Helper.GetDocs(_count))
{
var v = new TestDoc
{
id = doc["_id"].AsInt32,
name = doc["name"].AsString,
lorem = doc["lorem"].AsString
};
dict.Add(v.id, v);
}
}
public void Bulk()
{
}
public void CreateIndex()
{
}
public void Dispose()
{
}
public void Prepare()
{
}
public void Query()
{
for (var i = 0; i < _count; i++)
{
TestDoc d;
dict.TryGetValue(i, out d);
}
}
public void Update()
{
}
}
public class ConcurrentDictionary_Test : ITest
{
private string _filename;
private int _count;
ConcurrentDictionary<int, TestDoc> dict;
public int Count { get { return _count; } }
public int FileLength { get { return (int)new FileInfo(_filename).Length; } }
public ConcurrentDictionary_Test(int count)
{
_count = count;
_filename = "concurrentdict-" + Guid.NewGuid().ToString("n") + ".db";
dict = new ConcurrentDictionary<int, TestPerfLiteDB.TestDoc>();
}
public void Insert()
{
foreach (var doc in Helper.GetDocs(_count))
{
var v = new TestDoc
{
id = doc["_id"].AsInt32,
name = doc["name"].AsString,
lorem = doc["lorem"].AsString
};
dict.TryAdd(v.id, v);
}
}
public void Bulk()
{
}
public void CreateIndex()
{
}
public void Dispose()
{
}
public void Prepare()
{
}
public void Query()
{
for (var i = 0; i < _count; i++)
{
TestDoc d;
dict.TryGetValue(i, out d);
}
}
public void Update()
{
}
}
public class ImmutableDictionary_Test : ITest
{
private string _filename;
private int _count;
ImmutableDictionary<int, TestDoc> dict;
public int Count { get { return _count; } }
public int FileLength { get { return (int)new FileInfo(_filename).Length; } }
public ImmutableDictionary_Test(int count)
{
_count = count;
_filename = "immutabledict-" + Guid.NewGuid().ToString("n") + ".db";
//dict = new ImmutableDictionary<int, TestPerfLiteDB.TestDoc>();
}
public void Insert()
{
var builder = ImmutableDictionary.CreateBuilder<int, TestDoc>();
foreach (var doc in Helper.GetDocs(_count))
{
var v = new TestDoc
{
id = doc["_id"].AsInt32,
name = doc["name"].AsString,
lorem = doc["lorem"].AsString
};
builder.Add(v.id, v);
}
dict = builder.ToImmutableDictionary();
}
public void Bulk()
{
}
public void CreateIndex()
{
}
public void Dispose()
{
}
public void Prepare()
{
}
public void Query()
{
for (var i = 0; i < _count; i++)
{
TestDoc d;
dict.TryGetValue(i, out d);
}
}
public void Update()
{
}
}
}
================================================
FILE: sandbox/PerfTest2/Engines/ITest.cs
================================================
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LiteDB;
namespace TestPerfLiteDB
{
public interface ITest : IDisposable
{
int Count { get; }
int FileLength { get; }
void Prepare();
void Insert();
void Bulk();
void Update();
void CreateIndex();
void Query();
//void Delete();
//void Drop();
}
}
================================================
FILE: sandbox/PerfTest2/Engines/LiteDB_Test.cs
================================================
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LiteDB;
namespace TestPerfLiteDB
{
public class LiteDB_Test : ITest
{
private string _filename;
private LiteEngine _db;
private int _count;
public int Count { get { return _count; } }
public int FileLength { get { return (int)new FileInfo(_filename).Length; } }
public LiteDB_Test(int count, string password, LiteDB.FileOptions options)
{
_count = count;
_filename = "dblite-" + Guid.NewGuid().ToString("n") + ".db";
var disk = new FileDiskService(_filename, options);
_db = new LiteEngine(disk, password);
}
public LiteDB_Test(int count)
{
_count = count;
_filename = "dblite-" + Guid.NewGuid().ToString("n") + ".db";
var ms = new MemoryStream();
var disk = new LiteDB.StreamDiskService(ms);
//var disk = new FileDiskService(_filename, options);
_db = new LiteEngine(disk);
}
public void Prepare()
{
}
public void Insert()
{
foreach (var doc in Helper.GetDocs(_count))
{
_db.Insert("col", doc);
}
}
public void Bulk()
{
_db.Insert("col_bulk", Helper.GetDocs(_count));
}
public void Update()
{
foreach (var doc in Helper.GetDocs(_count))
{
_db.Update("col", doc);
}
}
public void CreateIndex()
{
_db.EnsureIndex("col", "name", false);
}
public void Query()
{
for (var i = 0; i < _count; i++)
{
_db.Find("col", LiteDB.Query.EQ("_id", i)).Single();
}
}
public void Delete()
{
_db.Delete("col", LiteDB.Query.All());
}
public void Drop()
{
_db.DropCollection("col_bulk");
}
public void Dispose()
{
_db.Dispose();
File.Delete(_filename);
}
}
}
================================================
FILE: sandbox/PerfTest2/Engines/MasterMemory_Test.cs
================================================
#pragma warning disable
using MasterMemory;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestPerfLiteDB
{
public class MasterMemory_Test : ITest
{
private string _filename;
private int _count;
MemoryDatabase database;
public int Count { get { return _count; } }
public int FileLength { get { return (int)new FileInfo(_filename).Length; } }
public MasterMemory_Test(int count)
{
_count = count;
_filename = "mastermemorydatabase-" + Guid.NewGuid().ToString("n") + ".db";
}
public IEnumerable<TestDoc> MakeDoc()
{
foreach (var doc in Helper.GetDocs(_count))
{
var v = new TestDoc
{
id = doc["_id"].AsInt32,
name = doc["name"].AsString,
lorem = doc["lorem"].AsString
};
yield return v;
}
}
public void Insert()
{
var builder = new DatabaseBuilder();
builder.Append(MakeDoc());
var saved = builder.Build();
File.WriteAllBytes(_filename, saved);
database = new MemoryDatabase(saved);
}
public void Bulk()
{
}
public void CreateIndex()
{
}
public void Dispose()
{
}
public void Prepare()
{
}
public void Query()
{
for (var i = 0; i < _count; i++)
{
//TestDoc d;
database.TestDocTable.FindByid(i);
}
}
public void Update()
{
}
}
}
================================================
FILE: sandbox/PerfTest2/Engines/RavenDB_Test.cs
================================================
//using Raven.Client;
//using Raven.Client.Embedded;
//using Raven.Client.Indexes;
//using System;
//using System.Collections.Generic;
//using System.IO;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;
//namespace TestPerfLiteDB
//{
// public class TestDocCreation : AbstractIndexCreationTask<TestDoc>
// {
// public TestDocCreation()
// {
// Map = xs => xs.Select(x => new { x.id });
// }
// }
// public class RavenDB_Test : ITest
// {
// private string _filename;
// private int _count;
// private bool isinmemory;
// IDocumentStore store;
// public int Count { get { return _count; } }
// public int FileLength { get { return (int)new FileInfo(_filename).Length; } }
// public RavenDB_Test(int count, bool isinmemory)
// {
// _count = count;
// _filename = "ravendb-" + Guid.NewGuid().ToString("n") + ".db";
// this.isinmemory = isinmemory;
// }
// public void Bulk()
// {
// if (isinmemory)
// {
// }
// //using (var store = new EmbeddableDocumentStore { RunInMemory = true }.Initialize())
// //{
// // using (var bulk = store.BulkInsert())
// // {
// // bulk.Store(new MyClass { Id = 9999, MyProperty = 1000 });
// // }
// // var session = store.OpenSession();
// // store.ExecuteIndex(new MyClassIndex());
// // var huga = session.Load<MyClass>("MyClasses/9999");
// //}
// }
// public void CreateIndex()
// {
// store.ExecuteIndex(new TestDocCreation());
// }
// public void Dispose()
// {
// store.Dispose();
// }
// IEnumerable<TestDoc> MakeDoc()
// {
// foreach (var doc in Helper.GetDocs(_count))
// {
// var v = new TestDoc
// {
// id = doc["_id"].AsInt32,
// name = doc["name"].AsString,
// lorem = doc["lorem"].AsString
// };
// yield return v;
// }
// }
// public void Insert()
// {
// using (var bulk = store.BulkInsert())
// {
// foreach (var item in MakeDoc())
// {
// bulk.Store(item);
// }
// }
// }
// public void Prepare()
// {
// if (isinmemory)
// {
// store = new EmbeddableDocumentStore { RunInMemory = true }.Initialize();
// }
// else
// {
// // store = new EmbeddableDocumentStore { RunInMemory = true }.Initialize();
// }
// }
// public void Query()
// {
// for (var i = 0; i < _count; i++)
// {
// using (var session = store.OpenSession())
// {
// session.Load<TestDoc>("TestDoc/" + i);
// }
// }
// }
// public void Update()
// {
// }
// }
//}
================================================
FILE: sandbox/PerfTest2/Engines/SQLite_Test.cs
================================================
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestPerfLiteDB
{
public class SQLite_Test : ITest
{
private string _filename;
private SQLiteConnection _db;
private int _count;
public int Count { get { return _count; } }
public int FileLength { get { return (int)new FileInfo(_filename).Length; } }
public SQLite_Test(int count, string password, bool journal, bool memory = false)
{
_count = count;
_filename = "sqlite-" + Guid.NewGuid().ToString("n") + ".db";
if (memory)
{
var cs = "Data Source=:memory:;New=True;";
_db = new SQLiteConnection(cs);
}
else
{
var cs = "Data Source=" + _filename;
if (password != null) cs += "; Password=" + password;
if (journal == false) cs += "; Journal Mode=Off";
_db = new SQLiteConnection(cs);
}
}
public void Prepare()
{
_db.Open();
var table = new SQLiteCommand("CREATE TABLE col (id INTEGER NOT NULL PRIMARY KEY, name TEXT, lorem TEXT)", _db);
table.ExecuteNonQuery();
var table2 = new SQLiteCommand("CREATE TABLE col_bulk (id INTEGER NOT NULL PRIMARY KEY, name TEXT, lorem TEXT)", _db);
table2.ExecuteNonQuery();
}
public void Insert()
{
// standard insert is slow, mod same as Bulk
using (var trans = _db.BeginTransaction())
{
var cmd = new SQLiteCommand("INSERT INTO col (id, name, lorem) VALUES (@id, @name, @lorem)", _db);
cmd.Parameters.Add(new SQLiteParameter("id", DbType.Int32));
cmd.Parameters.Add(new SQLiteParameter("name", DbType.String));
cmd.Parameters.Add(new SQLiteParameter("lorem", DbType.String));
foreach (var doc in Helper.GetDocs(_count))
{
cmd.Parameters["id"].Value = doc["_id"].AsInt32;
cmd.Parameters["name"].Value = doc["name"].AsString;
cmd.Parameters["lorem"].Value = doc["lorem"].AsString;
cmd.ExecuteNonQuery();
}
trans.Commit();
}
}
public void Bulk()
{
using (var trans = _db.BeginTransaction())
{
var cmd = new SQLiteCommand("INSERT INTO col_bulk (id, name, lorem) VALUES (@id, @name, @lorem)", _db);
cmd.Parameters.Add(new SQLiteParameter("id", DbType.Int32));
cmd.Parameters.Add(new SQLiteParameter("name", DbType.String));
cmd.Parameters.Add(new SQLiteParameter("lorem", DbType.String));
foreach (var doc in Helper.GetDocs(_count))
{
cmd.Parameters["id"].Value = doc["_id"].AsInt32;
cmd.Parameters["name"].Value = doc["name"].AsString;
cmd.Parameters["lorem"].Value = doc["lorem"].AsString;
cmd.ExecuteNonQuery();
}
trans.Commit();
}
}
public void Update()
{
var cmd = new SQLiteCommand("UPDATE col SET name = @name, lorem = @lorem WHERE id = @id", _db);
cmd.Parameters.Add(new SQLiteParameter("id", DbType.Int32));
cmd.Parameters.Add(new SQLiteParameter("name", DbType.String));
cmd.Parameters.Add(new SQLiteParameter("lorem", DbType.String));
foreach (var doc in Helper.GetDocs(_count))
{
cmd.Parameters["id"].Value = doc["_id"].AsInt32;
cmd.Parameters["name"].Value = doc["name"].AsString;
cmd.Parameters["lorem"].Value = doc["lorem"].AsString;
cmd.ExecuteNonQuery();
}
}
public void CreateIndex()
{
var cmd = new SQLiteCommand("CREATE INDEX idx1 ON col (name)", _db);
cmd.ExecuteNonQuery();
}
public void Query()
{
var cmd = new SQLiteCommand("SELECT * FROM col WHERE id = @id", _db);
cmd.Parameters.Add(new SQLiteParameter("id", DbType.Int32));
for (var i = 0; i < _count; i++)
{
cmd.Parameters["id"].Value = i;
var r = cmd.ExecuteReader();
r.Read();
var name = r.GetString(1);
var lorem = r.GetString(2);
r.Close();
}
}
public void Delete()
{
var cmd = new SQLiteCommand("DELETE FROM col", _db);
cmd.ExecuteNonQuery();
}
public void Drop()
{
var cmd = new SQLiteCommand("DROP TABLE col_bulk", _db);
cmd.ExecuteNonQuery();
}
public void Dispose()
{
_db.Dispose();
}
}
}
================================================
FILE: sandbox/PerfTest2/Generated/DatabaseBuilder.cs
================================================
// <auto-generated />
using LiteDB;
using MasterMemory;
using MessagePack;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using TestPerfLiteDB;
using TestPerfLiteDB.Tables;
namespace TestPerfLiteDB
{
public sealed class DatabaseBuilder : DatabaseBuilderBase
{
public DatabaseBuilder() : this(null) { }
public DatabaseBuilder(MessagePack.IFormatterResolver resolver) : base(resolver) { }
public DatabaseBuilder Append(System.Collections.Generic.IEnumerable<TestDoc> dataSource)
{
AppendCore(dataSource, x => x.id, System.Collections.Generic.Comparer<int>.Default);
return this;
}
}
}
================================================
FILE: sandbox/PerfTest2/Generated/ImmutableBuilder.cs
================================================
// <auto-generated />
using LiteDB;
using MasterMemory;
using MessagePack;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using TestPerfLiteDB;
using TestPerfLiteDB.Tables;
namespace TestPerfLiteDB
{
public sealed class ImmutableBuilder : ImmutableBuilderBase
{
MemoryDatabase memory;
public ImmutableBuilder(MemoryDatabase memory)
{
this.memory = memory;
}
public MemoryDatabase Build()
{
return memory;
}
public void ReplaceAll(System.Collections.Generic.IList<TestDoc> data)
{
var newData = CloneAndSortBy(data, x => x.id, System.Collections.Generic.Comparer<int>.Default);
var table = new TestDocTable(newData);
memory = new MemoryDatabase(
table
);
}
public void RemoveTestDoc(int[] keys)
{
var data = RemoveCore(memory.TestDocTable.GetRawDataUnsafe(), keys, x => x.id, System.Collections.Generic.Comparer<int>.Default);
var newData = CloneAndSortBy(data, x => x.id, System.Collections.Generic.Comparer<int>.Default);
var table = new TestDocTable(newData);
memory = new MemoryDatabase(
table
);
}
public void Diff(TestDoc[] addOrReplaceData)
{
var data = DiffCore(memory.TestDocTable.GetRawDataUnsafe(), addOrReplaceData, x => x.id, System.Collections.Generic.Comparer<int>.Default);
var newData = CloneAndSortBy(data, x => x.id, System.Collections.Generic.Comparer<int>.Default);
var table = new TestDocTable(newData);
memory = new MemoryDatabase(
table
);
}
}
}
================================================
FILE: sandbox/PerfTest2/Generated/MasterMemoryResolver.cs
================================================
// <auto-generated />
using LiteDB;
using MasterMemory;
using MessagePack;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using TestPerfLiteDB;
using TestPerfLiteDB.Tables;
namespace TestPerfLiteDB
{
public class MasterMemoryResolver : global::MessagePack.IFormatterResolver
{
public static readonly global::MessagePack.IFormatterResolver Instance = new MasterMemoryResolver();
MasterMemoryResolver()
{
}
public global::MessagePack.Formatters.IMessagePackFormatter<T> GetFormatter<T>()
{
return FormatterCache<T>.formatter;
}
static class FormatterCache<T>
{
public static readonly global::MessagePack.Formatters.IMessagePackFormatter<T> formatter;
static FormatterCache()
{
var f = MasterMemoryResolverGetFormatterHelper.GetFormatter(typeof(T));
if (f != null)
{
formatter = (global::MessagePack.Formatters.IMessagePackFormatter<T>)f;
}
}
}
}
internal static class MasterMemoryResolverGetFormatterHelper
{
static readonly global::System.Collections.Generic.Dictionary<Type, int> lookup;
static MasterMemoryResolverGetFormatterHelper()
{
lookup = new global::System.Collections.Generic.Dictionary<Type, int>(1)
{
{typeof(TestDoc[]), 0 },
};
}
internal static object GetFormatter(Type t)
{
int key;
if (!lookup.TryGetValue(t, out key)) return null;
switch (key)
{
case 0: return new MessagePack.Formatters.ArrayFormatter<TestDoc>();
default: return null;
}
}
}
}
================================================
FILE: sandbox/PerfTest2/Generated/MemoryDatabase.cs
================================================
// <auto-generated />
using LiteDB;
using MasterMemory;
using MessagePack;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using TestPerfLiteDB;
using TestPerfLiteDB.Tables;
namespace TestPerfLiteDB
{
public sealed class MemoryDatabase : MemoryDatabaseBase
{
public TestDocTable TestDocTable { get; private set; }
public MemoryDatabase(
TestDocTable TestDocTable
)
{
this.TestDocTable = TestDocTable;
}
public MemoryDatabase(byte[] databaseBinary, bool internString = true, MessagePack.IFormatterResolver formatterResolver = null, int maxDegreeOfParallelism = 1)
: base(databaseBinary, internString, formatterResolver, maxDegreeOfParallelism)
{
}
protected override void Init(Dictionary<string, (int offset, int count)> header, System.ReadOnlyMemory<byte> databaseBinary, MessagePack.MessagePackSerializerOptions options, int maxDegreeOfParallelism)
{
this.TestDocTable = ExtractTableData<TestDoc, TestDocTable>(header, databaseBinary, options, xs => new TestDocTable(xs));
}
public ImmutableBuilder ToImmutableBuilder()
{
return new ImmutableBuilder(this);
}
public DatabaseBuilder ToDatabaseBuilder()
{
var builder = new DatabaseBuilder();
builder.Append(this.TestDocTable.GetRawDataUnsafe());
return builder;
}
}
}
================================================
FILE: sandbox/PerfTest2/Generated/Tables/TestDocTable.cs
================================================
// <auto-generated />
using LiteDB;
using MasterMemory;
using MessagePack;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using TestPerfLiteDB;
namespace TestPerfLiteDB.Tables
{
public sealed partial class TestDocTable : TableBase<TestDoc>
{
readonly Func<TestDoc, int> primaryIndexSelector;
public TestDocTable(TestDoc[] sortedData)
: base(sortedData)
{
this.primaryIndexSelector = x => x.id;
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public TestDoc FindByid(int key)
{
var lo = 0;
var hi = data.Length - 1;
while (lo <= hi)
{
var mid = (int)(((uint)hi + (uint)lo) >> 1);
var selected = data[mid].id;
var found = (selected < key) ? -1 : (selected > key) ? 1 : 0;
if (found == 0) { return data[mid]; }
if (found < 0) { lo = mid + 1; }
else { hi = mid - 1; }
}
return default;
}
public TestDoc FindClosestByid(int key, bool selectLower = true)
{
return FindUniqueClosestCore(data, primaryIndexSelector, System.Collections.Generic.Comparer<int>.Default, key, selectLower);
}
public RangeView<TestDoc> FindRangeByid(int min, int max, bool ascendant = true)
{
return FindUniqueRangeCore(data, primaryIndexSelector, System.Collections.Generic.Comparer<int>.Default, min, max, ascendant);
}
}
}
================================================
FILE: sandbox/PerfTest2/PerfTest2.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<NoWarn>1701;1702;NU1904</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LiteDB" Version="4.1.4" />
<PackageReference Include="System.Data.SQLite" Version="1.0.111" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\MasterMemory\MasterMemory.csproj" />
<ProjectReference Include="..\..\src\MasterMemory.SourceGenerator\MasterMemory.SourceGenerator.csproj">
<OutputItemType>Analyzer</OutputItemType>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
</Project>
================================================
FILE: sandbox/PerfTest2/Program.cs
================================================
#pragma warning disable
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LiteDB;
using System.IO;
// based test code -> https://github.com/mbdavid/LiteDB-Perf
namespace TestPerfLiteDB
{
class Program
{
static void Main(string[] args)
{
RunTest("LiteDB: default", new LiteDB_Test(5000, null, new LiteDB.FileOptions { Journal = true, FileMode = LiteDB.FileMode.Shared }));
RunTest("LiteDB: encrypted", new LiteDB_Test(5000, "mypass", new LiteDB.FileOptions { Journal = true, FileMode = LiteDB.FileMode.Shared }));
RunTest("LiteDB: exclusive no journal", new LiteDB_Test(5000, null, new LiteDB.FileOptions { Journal = false, FileMode = LiteDB.FileMode.Exclusive }));
RunTest("LiteDB: in-memory", new LiteDB_Test(5000));
RunTest("SQLite: default", new SQLite_Test(5000, null, true));
//RunTest("SQLite: encrypted", new SQLite_Test(5000, "mypass", true));
//RunTest("SQLite: no journal", new SQLite_Test(5000, null, false));
RunTest("SQLite: in-memory", new SQLite_Test(5000, null, false, true));
RunTest("Dictionary", new Dictionary_Test(5000));
RunTest("ConcurrentDictionary", new ConcurrentDictionary_Test(5000));
RunTest("ImmutableDictionary", new ImmutableDictionary_Test(5000));
RunTest("MasterMemory", new MasterMemory_Test(5000));
Console.ReadKey();
// RunTest("RavenDB: in-memory", new RavenDB_Test(5000, true));
}
static void RunTest(string name, ITest test)
{
var title = name + " - " + test.Count + " records";
Console.WriteLine(title);
Console.WriteLine("=".PadLeft(title.Length, '='));
test.Prepare();
test.Run("Insert", test.Insert, true);
test.Run("Bulk", test.Bulk, true);
test.Run("CreateIndex", test.CreateIndex, true);
test.Run("Query", test.Query, false);
test.Run("Query", test.Query, false);
test.Run("Query", test.Query, false);
test.Run("Query", test.Query, false);
try
{
Console.WriteLine("FileLength : " + Math.Round((double)test.FileLength / (double)1024, 2).ToString().PadLeft(5, ' ') + " kb");
}
catch (System.IO.FileNotFoundException)
{
}
test.Dispose();
Console.WriteLine();
}
}
}
================================================
FILE: sandbox/PerfTest2/Utils/Helper.cs
================================================
#pragma warning disable
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LiteDB;
using MasterMemory;
using MessagePack;
namespace TestPerfLiteDB
{
[MemoryTable("TestDoc"), MessagePackObject(true)]
public class TestDoc
{
[PrimaryKey]
public int id { get; set; }
public string name { get; set; }
public string lorem { get; set; }
}
static class Helper
{
public static void Run(this ITest test, string name, Action action, bool dryrun)
{
var sw = new Stopwatch();
System.GC.Collect(2, GCCollectionMode.Forced, blocking: true);
sw.Start();
action();
sw.Stop();
var time = sw.ElapsedMilliseconds.ToString().PadLeft(5, ' ');
var seg = Math.Round(test.Count / sw.Elapsed.TotalSeconds).ToString().PadLeft(8, ' ');
if (!dryrun)
{
Console.WriteLine(name.PadRight(15, ' ') + ": " +
time + " ms - " +
seg + " records/second");
}
}
public static IEnumerable<BsonDocument> GetDocs(int count)
{
for (var i = 0; i < count; i++)
{
yield return new BsonDocument
{
{ "_id", i },
{ "name", Guid.NewGuid().ToString() },
{ "lorem", LoremIpsum(3, 5, 2, 3, 3) }
};
}
}
public static string LoremIpsum(int minWords, int maxWords,
int minSentences, int maxSentences,
int numParagraphs)
{
var words = new[] { "lorem", "ipsum", "dolor", "sit", "amet", "consectetuer",
"adipiscing", "elit", "sed", "diam", "nonummy", "nibh", "euismod",
"tincidunt", "ut", "laoreet", "dolore", "magna", "aliquam", "erat" };
var rand = new Random(DateTime.Now.Millisecond);
var numSentences = rand.Next(maxSentences - minSentences) + minSentences + 1;
var numWords = rand.Next(maxWords - minWords) + minWords + 1;
var result = new StringBuilder();
for (int p = 0; p < numParagraphs; p++)
{
for (int s = 0; s < numSentences; s++)
{
for (int w = 0; w < numWords; w++)
{
if (w > 0) { result.Append(" "); }
result.Append(words[rand.Next(words.Length)]);
}
result.Append(". ");
}
result.AppendLine();
}
return result.ToString();
}
}
}
================================================
FILE: src/MasterMemory/DatabaseBuilderBase.cs
================================================
using MasterMemory.Internal;
using MessagePack;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace MasterMemory
{
public abstract class DatabaseBuilderBase
{
readonly ByteBufferWriter bufferWriter = new ByteBufferWriter();
// TableName, (Offset, Count)
readonly Dictionary<string, (int offset, int count)> header = new Dictionary<string, (int offset, int count)>();
readonly MessagePackSerializerOptions? options;
public DatabaseBuilderBase(MessagePackSerializerOptions? options)
{
// options keep null to lazily use default options
if (options != null)
{
options = options.WithCompression(MessagePackCompression.Lz4Block);
}
}
public DatabaseBuilderBase(IFormatterResolver? resolver)
{
if (resolver != null)
{
this.options = MessagePackSerializer.DefaultOptions
.WithCompression(MessagePackCompression.Lz4Block)
.WithResolver(resolver);
}
}
protected void AppendCore<T, TKey>(IEnumerable<T> datasource, Func<T, TKey> indexSelector, IComparer<TKey> comparer)
{
var tableName = typeof(T).GetCustomAttribute<MemoryTableAttribute>();
if (tableName == null) throw new InvalidOperationException("Type is not annotated MemoryTableAttribute. Type:" + typeof(T).FullName);
if (header.ContainsKey(tableName.TableName))
{
throw new InvalidOperationException("TableName is already appended in builder. TableName: " + tableName.TableName + " Type:" + typeof(T).FullName);
}
if (datasource == null) return;
// sort(as indexed data-table)
var source = FastSort(datasource, indexSelector, comparer);
// write data and store header-data.
var useOption = options ?? MessagePackSerializer.DefaultOptions.WithCompression(MessagePackCompression.Lz4Block);
var offset = bufferWriter.CurrentOffset;
MessagePackSerializer.Serialize(bufferWriter, source, useOption);
header.Add(tableName.TableName, (offset, bufferWriter.CurrentOffset - offset));
}
static TElement[] FastSort<TElement, TKey>(IEnumerable<TElement> datasource, Func<TElement, TKey> indexSelector, IComparer<TKey> comparer)
{
var collection = datasource as ICollection<TElement>;
if (collection != null)
{
var array = new TElement[collection.Count];
var sortSource = new TKey[collection.Count];
var i = 0;
foreach (var item in collection)
{
array[i] = item;
sortSource[i] = indexSelector(item);
i++;
}
Array.Sort(sortSource, array, 0, collection.Count, comparer);
return array;
}
else
{
var array = new ExpandableArray<TElement>(null!);
var sortSource = new ExpandableArray<TKey>(null!);
foreach (var item in datasource)
{
array.Add(item);
sortSource.Add(indexSelector(item));
}
Array.Sort(sortSource.items, array.items, 0, array.count, comparer);
Array.Resize(ref array.items, array.count);
return array.items;
}
}
public byte[] Build()
{
using (var ms = new MemoryStream())
{
WriteToStream(ms);
return ms.ToArray();
}
}
public void WriteToStream(Stream stream)
{
MessagePackSerializer.Serialize(stream, header, HeaderFormatterResolver.StandardOptions);
MemoryMarshal.TryGetArray(bufferWriter.WrittenMemory, out var segment);
stream.Write(segment.Array, segment.Offset, segment.Count);
}
}
}
================================================
FILE: src/MasterMemory/DatabaseBuilderBaseExtensions.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
namespace MasterMemory
{
public static class DatabaseBuilderExtensions
{
public static void AppendDynamic(this DatabaseBuilderBase builder, Type dataType, IList<object> tableData)
{
var appendMethod = builder.GetType().GetMethods()
.Where(x => x.Name == "Append")
.Where(x => x.GetParameters()[0].ParameterType.GetGenericArguments()[0] == dataType)
.FirstOrDefault();
if (appendMethod == null)
{
throw new InvalidOperationException("Append(IEnumerable<DataType>) can not found. DataType:" + dataType);
}
var dynamicArray = Array.CreateInstance(dataType, tableData.Count);
for (int i = 0; i < tableData.Count; i++)
{
dynamicArray.SetValue(Convert.ChangeType(tableData[i], dataType), i);
}
appendMethod.Invoke(builder, new object[] { dynamicArray });
}
}
}
================================================
FILE: src/MasterMemory/IValidatable.cs
================================================
using MasterMemory.Validation;
using System;
using System.Linq.Expressions;
namespace MasterMemory
{
public interface IValidatable<TSelf>
{
void Validate(IValidator<TSelf> validator);
}
public interface IValidator<T>
{
ValidatableSet<T> GetTableSet();
ReferenceSet<T, TRef> GetReferenceSet<TRef>();
void Validate(Expression<Func<T, bool>> predicate);
void Validate(Func<T, bool> predicate, string message);
void ValidateAction(Expression<Func<bool>> predicate);
void ValidateAction(Func<bool> predicate, string message);
void Fail(string message);
bool CallOnce();
}
}
================================================
FILE: src/MasterMemory/ImmutableBuilderBase.cs
================================================
using MasterMemory.Internal;
using System;
using System.Collections.Generic;
namespace MasterMemory
{
public abstract class ImmutableBuilderBase
{
static protected TElement[] CloneAndSortBy<TElement, TKey>(IList<TElement> elementData, Func<TElement, TKey> indexSelector, IComparer<TKey> comparer)
{
var array = new TElement[elementData.Count];
var sortSource = new TKey[elementData.Count];
for (int i = 0; i < elementData.Count; i++)
{
array[i] = elementData[i];
sortSource[i] = indexSelector(elementData[i]);
}
Array.Sort(sortSource, array, 0, array.Length, comparer);
return array;
}
static protected List<TElement> RemoveCore<TElement, TKey>(TElement[] array, TKey[] keys, Func<TElement, TKey> keySelector, IComparer<TKey> comparer)
{
var removeIndexes = new HashSet<int>();
foreach (var key in keys)
{
var index = BinarySearch.FindFirst(array, key, keySelector, comparer);
if (index != -1)
{
removeIndexes.Add(index);
}
}
var newList = new List<TElement>(array.Length - removeIndexes.Count);
for (int i = 0; i < array.Length; i++)
{
if (!removeIndexes.Contains(i))
{
newList.Add(array[i]);
}
}
return newList;
}
static protected List<TElement> DiffCore<TElement, TKey>(TElement[] array, TElement[] addOrReplaceData, Func<TElement, TKey> keySelector, IComparer<TKey> comparer)
{
var newList = new List<TElement>(array.Length);
var replaceIndexes = new Dictionary<int, TElement>();
foreach (var data in addOrReplaceData)
{
var index = BinarySearch.FindFirst(array, keySelector(data), keySelector, comparer);
if (index != -1)
{
replaceIndexes.Add(index, data);
}
else
{
newList.Add(data);
}
}
for (int i = 0; i < array.Length; i++)
{
if (replaceIndexes.TryGetValue(i, out var data))
{
newList.Add(data);
}
else
{
newList.Add(array[i]);
}
}
return newList;
}
}
}
================================================
FILE: src/MasterMemory/Internal/BinarySearch.cs
================================================
using System;
using System.Collections.Generic;
namespace MasterMemory.Internal
{
internal static class BinarySearch
{
public static int FindFirst<T, TKey>(T[] array, TKey key, Func<T, TKey> selector, IComparer<TKey> comparer)
{
var lo = 0;
var hi = array.Length - 1;
while (lo <= hi)
{
var mid = (int)(((uint)hi + (uint)lo) >> 1);
var found = comparer.Compare(selector(array[mid]), key);
if (found == 0) return mid;
if (found < 0)
{
lo = mid + 1;
}
else
{
hi = mid - 1;
}
}
return -1;
}
public static int FindFirstIntKey<T>(T[] array, int key, Func<T, int> selector)
{
var lo = 0;
var hi = array.Length - 1;
while (lo <= hi)
{
var mid = (int)(((uint)hi + (uint)lo) >> 1);
// compare inlining
var selectedValue = selector(array[mid]);
var found = (selectedValue < key) ? -1 : (selectedValue > key) ? 1 : 0;
if (found == 0) return mid;
if (found < 0)
{
lo = mid + 1;
}
else
{
hi = mid - 1;
}
}
return -1;
}
// lo = 0, hi = Count.
public static int FindClosest<T, TKey>(T[] array, int lo, int hi, TKey key, Func<T, TKey> selector, IComparer<TKey> comparer, bool selectLower)
{
if (array.Length == 0) return -1;
lo = lo - 1;
while (hi - lo > 1)
{
var mid = lo + ((hi - lo) >> 1);
var found = comparer.Compare(selector(array[mid]), key);
if (found == 0)
{
lo = hi = mid;
break;
}
if (found >= 1)
{
hi = mid;
}
else
{
lo = mid;
}
}
return selectLower ? lo : hi;
}
// default lo = 0, hi = array.Count
public static int LowerBound<T, TKey>(T[] array, int lo, int hi, TKey key, Func<T, TKey> selector, IComparer<TKey> comparer)
{
while (lo < hi)
{
var mid = lo + ((hi - lo) >> 1);
var found = comparer.Compare(key, selector(array[mid]));
if (found <= 0)
{
hi = mid;
}
else
{
lo = mid + 1;
}
}
var index = lo;
if (index == -1 || array.Length <= index)
{
return -1;
}
// check final
return (comparer.Compare(key, selector(array[index])) == 0)
? index
: -1;
}
public static int UpperBound<T, TKey>(T[] array, int lo, int hi, TKey key, Func<T, TKey> selector, IComparer<TKey> comparer)
{
while (lo < hi)
{
var mid = lo + ((hi - lo) >> 1);
var found = comparer.Compare(key, selector(array[mid]));
if (found >= 0)
{
lo = mid + 1;
}
else
{
hi = mid;
}
}
var index = (lo == 0) ? 0 : lo - 1;
if (index == -1 || array.Length <= index)
{
return -1;
}
// check final
return (comparer.Compare(key, selector(array[index])) == 0)
? index
: -1;
}
//... want the lowest index of Key <= Value
//... returns 0 if key is <= all values in array
//... returns array.Length if key is > all values in array
public static int LowerBoundClosest<T, TKey>(T[] array, int lo, int hi, TKey key, Func<T, TKey> selector, IComparer<TKey> comparer)
{
while (lo < hi)
{
var mid = lo + ((hi - lo) >> 1);
var found = comparer.Compare(key, selector(array[mid]));
if (found <= 0) //... Key is <= value at mid
{
hi = mid;
}
else
{
lo = mid + 1; //... Notice that lo starts at zero and can only increase
}
}
var index = lo; //... index will always be zero or greater
if ( array.Length <= index)
{
return array.Length;
}
// check final
return (comparer.Compare(key, selector(array[index])) <= 0)
? index
: -1;
}
//... want the highest index of Key >= Value
//... returns -1 if key is < than all values in array
//... returns array.Length - 1 if key is >= than all values in array
public static int UpperBoundClosest<T, TKey>(T[] array, int lo, int hi, TKey key, Func<T, TKey> selector, IComparer<TKey> comparer)
{
while (lo < hi)
{
var mid = lo + ((hi - lo) >> 1);
var found = comparer.Compare(key, selector(array[mid]));
if (found >= 0) //... Key >= value at mid
{
lo = mid + 1; //... Note lo starts at zero and can only increase
}
else
{
hi = mid;
}
}
var index = (lo == 0) ? 0 : lo - 1; //... index will always be zero or greater
if ( index >= array.Length )
{
return array.Length;
}
// check final
return (comparer.Compare(key, selector(array[index])) >= 0)
? index
: -1;
}
}
}
================================================
FILE: src/MasterMemory/Internal/ByteBufferWriter.cs
================================================
using System;
using System.Buffers;
namespace MasterMemory
{
internal class ByteBufferWriter : IBufferWriter<byte>
{
byte[] buffer;
int index;
public int CurrentOffset => index;
public ReadOnlySpan<byte> WrittenSpan => buffer.AsSpan(0, index);
public ReadOnlyMemory<byte> WrittenMemory => new ReadOnlyMemory<byte>(buffer, 0, index);
public ByteBufferWriter()
{
buffer = new byte[1024];
index = 0;
}
public void Advance(int count)
{
index += count;
}
public Memory<byte> GetMemory(int sizeHint = 0)
{
AGAIN:
var nextSize = index + sizeHint;
if (buffer.Length < nextSize)
{
Array.Resize(ref buffer, Math.Max(buffer.Length * 2, nextSize));
}
if (sizeHint == 0)
{
var result = new Memory<byte>(buffer, index, buffer.Length - index);
if (result.Length == 0)
{
sizeHint = 1024;
goto AGAIN;
}
return result;
}
else
{
return new Memory<byte>(buffer, index, sizeHint);
}
}
public Span<byte> GetSpan(int sizeHint = 0)
{
return GetMemory(sizeHint).Span;
}
}
}
================================================
FILE: src/MasterMemory/Internal/ExpandableArray.cs
================================================
using System;
namespace MasterMemory.Internal
{
internal struct ExpandableArray<TElement>
{
internal TElement[] items;
internal int count;
public ExpandableArray(object dummy)
{
items = Array.Empty<TElement>();
count = 0;
}
internal void Add(TElement item)
{
if (items == null || items.Length == 0)
{
items = new TElement[4];
}
else if (items.Length == (count + 1))
{
Array.Resize(ref items, checked(count * 2));
}
items[count++] = item;
}
}
}
================================================
FILE: src/MasterMemory/Internal/HeaderFormatterResolver.cs
================================================
using MessagePack;
using MessagePack.Formatters;
using System;
using System.Collections.Generic;
namespace MasterMemory.Internal
{
// for AOT(IL2CPP) concrete generic formatter.
internal class HeaderFormatterResolver : IFormatterResolver
{
public static readonly IFormatterResolver Instance = new HeaderFormatterResolver();
public static readonly MessagePackSerializerOptions StandardOptions = MessagePackSerializerOptions.Standard.WithResolver(Instance);
public IMessagePackFormatter<T>? GetFormatter<T>()
{
if (typeof(T) == typeof(Dictionary<string, (int, int)>))
{
return (IMessagePackFormatter<T>)(object)new DictionaryFormatter<string, (int, int)>();
}
else if (typeof(T) == typeof(string))
{
return (IMessagePackFormatter<T>)(object)NullableStringFormatter.Instance;
}
else if (typeof(T) == typeof((int, int)))
{
return (IMessagePackFormatter<T>)(object)new IntIntValueTupleFormatter();
}
else if (typeof(T) == typeof(int))
{
return (IMessagePackFormatter<T>)(object)Int32Formatter.Instance;
}
return null;
}
}
internal sealed class IntIntValueTupleFormatter : IMessagePackFormatter<ValueTuple<int, int>>
{
public void Serialize(ref MessagePackWriter writer, (int, int) value, MessagePackSerializerOptions options)
{
writer.WriteArrayHeader(2);
writer.WriteInt32(value.Item1);
writer.WriteInt32(value.Item2);
}
public (int, int) Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.IsNil)
{
throw new InvalidOperationException("Data is Nil, ValueTuple can not be null.");
}
var count = reader.ReadArrayHeader();
if (count != 2) throw new InvalidOperationException("Invalid ValueTuple count");
var item1 = reader.ReadInt32();
var item2 = reader.ReadInt32();
return new ValueTuple<int, int>(item1, item2);
}
}
}
================================================
FILE: src/MasterMemory/Internal/InternStringResolver.cs
================================================
using MessagePack;
using MessagePack.Formatters;
using System;
namespace MasterMemory.Internal
{
#pragma warning disable MsgPack013 // Inaccessible formatter
internal class InternStringResolver : IFormatterResolver, IMessagePackFormatter<string?>
{
readonly IFormatterResolver innerResolver;
public InternStringResolver(IFormatterResolver innerResolver)
{
this.innerResolver = innerResolver;
}
public IMessagePackFormatter<T>? GetFormatter<T>()
{
if (typeof(T) == typeof(string))
{
return (IMessagePackFormatter<T>)this;
}
return innerResolver.GetFormatter<T>();
}
string? IMessagePackFormatter<string?>.Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
var str = reader.ReadString();
if (str == null)
{
return null;
}
return string.Intern(str);
}
void IMessagePackFormatter<string?>.Serialize(ref MessagePackWriter writer, string? value, MessagePackSerializerOptions options)
{
throw new NotImplementedException();
}
}
}
================================================
FILE: src/MasterMemory/MasterMemory.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>MasterMemory</RootNamespace>
<AssemblyName>MasterMemory</AssemblyName>
<LangVersion>13</LangVersion>
<Nullable>enable</Nullable>
<OutputType>Library</OutputType>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<Company>Cysharp</Company>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>1701;1702;1705;1591</NoWarn>
<!-- NuGet -->
<PackageId>MasterMemory</PackageId>
<Description>Embedded Typed Readonly In-Memory Document Database for .NET Core and Unity.</Description>
<IsPackable>true</IsPackable>
<!-- SourceGenerator Packaging configs... -->
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);PackBuildOutputs</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>
<!-- for nuget publish -->
<Target Name="PackBuildOutputs" DependsOnTargets="SatelliteDllsProjectOutputGroup;DebugSymbolsProjectOutputGroup">
<ItemGroup>
<TfmSpecificPackageFile Include="$(TargetDir)\MasterMemory.SourceGenerator.dll" PackagePath="analyzers\dotnet\cs" />
<TfmSpecificPackageFile Include="@(SatelliteDllsProjectOutputGroupOutput->'%(FinalOutputPath)')" PackagePath="analyzers\dotnet\cs\%(SatelliteDllsProjectOutputGroupOutput.Culture)\" />
</ItemGroup>
</Target>
<ItemGroup>
<PackageReference Include="MessagePack" Version="3.1.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MasterMemory.Annotations\MasterMemory.Annotations.csproj" />
<!-- We don't consume the analyzers in this library itself,
but we reference the project to add a package dependency so users of this library will automatically get the analyzers. -->
<ProjectReference Include="..\MasterMemory.SourceGenerator\MasterMemory.SourceGenerator.csproj" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<None Update="Validation\ValidatableSet.Sequential.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>ValidatableSet.Sequential.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
<ItemGroup>
<Compile Update="Validation\ValidatableSet.Sequential.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>ValidatableSet.Sequential.tt</DependentUpon>
</Compile>
</ItemGroup>
</Project>
================================================
FILE: src/MasterMemory/MemoryDatabaseBase.cs
================================================
using MasterMemory.Internal;
using MessagePack;
using MessagePack.Formatters;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Buffers;
using MasterMemory.Validation;
namespace MasterMemory
{
public abstract class MemoryDatabaseBase
{
protected MemoryDatabaseBase()
{
}
public MemoryDatabaseBase(byte[] databaseBinary, bool internString = true, IFormatterResolver? formatterResolver = null, int maxDegreeOfParallelism = 1)
{
var reader = new MessagePackReader(databaseBinary);
var formatter = new DictionaryFormatter<string, (int, int)>();
var header = formatter.Deserialize(ref reader, HeaderFormatterResolver.StandardOptions);
var resolver = formatterResolver ?? MessagePackSerializer.DefaultOptions.Resolver;
if (internString)
{
resolver = new InternStringResolver(resolver);
}
if (maxDegreeOfParallelism < 1)
{
maxDegreeOfParallelism = 1;
}
Init(header!, databaseBinary.AsMemory((int)reader.Consumed), MessagePackSerializer.DefaultOptions.WithResolver(resolver).WithCompression(MessagePackCompression.Lz4Block), maxDegreeOfParallelism);
}
protected static TView ExtractTableData<T, TView>(Dictionary<string, (int offset, int count)> header, ReadOnlyMemory<byte> databaseBinary, MessagePackSerializerOptions options, Func<T[], TView> createView)
{
var tableName = typeof(T).GetCustomAttribute<MemoryTableAttribute>();
if (tableName == null) throw new InvalidOperationException("Type is not annotated MemoryTableAttribute. Type:" + typeof(T).FullName);
if (header.TryGetValue(tableName.TableName, out var segment))
{
var data = MessagePackSerializer.Deserialize<T[]>(databaseBinary.Slice(segment.offset, segment.count), options);
return createView(data);
}
else
{
// return empty
var data = Array.Empty<T>();
return createView(data);
}
}
protected abstract void Init(Dictionary<string, (int offset, int count)> header, ReadOnlyMemory<byte> databaseBinary, MessagePackSerializerOptions options, int maxDegreeOfParallelism);
public static TableInfo[] GetTableInfo(byte[] databaseBinary, bool storeTableData = true)
{
var formatter = new DictionaryFormatter<string, (int, int)>();
var reader = new MessagePackReader(databaseBinary);
var header = formatter.Deserialize(ref reader, HeaderFormatterResolver.StandardOptions);
return header.Select(x => new TableInfo(x.Key, x.Value.Item2, storeTableData ? databaseBinary : null, x.Value.Item1)).ToArray();
}
protected void ValidateTable<TElement>(IReadOnlyList<TElement> table, ValidationDatabase database, string pkName, Delegate pkSelector, ValidateResult result)
{
var onceCalled = new System.Runtime.CompilerServices.StrongBox<bool>(false);
foreach (var item in table)
{
if (item is IValidatable<TElement> validatable)
{
var validator = new Validator<TElement>(database, item, result, onceCalled, pkName, pkSelector);
validatable.Validate(validator);
}
}
}
}
/// <summary>
/// Diagnostic info of MasterMemory's table.
/// </summary>
public class TableInfo
{
public string TableName { get; }
public int Size { get; }
byte[]? binaryData;
public TableInfo(string tableName, int size, byte[]? rawBinary, int offset)
{
TableName = tableName;
Size = size;
if (rawBinary != null)
{
this.binaryData = new byte[size];
Array.Copy(rawBinary, offset, binaryData, 0, size);
}
}
public string DumpAsJson()
{
return DumpAsJson(MessagePackSerializer.DefaultOptions);
}
public string DumpAsJson(MessagePackSerializerOptions options)
{
if (binaryData == null)
{
throw new InvalidOperationException("DumpAsJson can only call from GetTableInfo(storeTableData = true).");
}
return MessagePackSerializer.ConvertToJson(binaryData, options.WithCompression(MessagePackCompression.Lz4Block));
}
}
}
================================================
FILE: src/MasterMemory/Meta/Meta.cs
================================================
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace MasterMemory.Meta
{
public class MetaDatabase
{
IDictionary<string, MetaTable> tableInfos;
public MetaDatabase(IDictionary<string, MetaTable> tableInfos)
{
this.tableInfos = tableInfos;
}
public int Count => tableInfos.Count;
public IEnumerable<MetaTable> GetTableInfos()
{
foreach (var item in tableInfos.Values)
{
yield return item;
}
}
public MetaTable? GetTableInfo(string tableName)
{
return tableInfos.TryGetValue(tableName, out var table)
? table
: null;
}
}
public class MetaTable
{
public Type DataType { get; }
public Type TableType { get; }
public string TableName { get; }
public IReadOnlyList<MetaProperty> Properties { get; }
public IReadOnlyList<MetaIndex> Indexes { get; }
public MetaTable(Type dataType, Type tableType, string tableName, IReadOnlyList<MetaProperty> properties, IReadOnlyList<MetaIndex> Indexes)
{
this.DataType = dataType;
this.TableType = tableType;
this.TableName = tableName;
this.Properties = properties;
this.Indexes = Indexes;
}
public override string ToString()
{
return TableName;
}
}
public class MetaProperty
{
public PropertyInfo PropertyInfo { get; }
public string Name => PropertyInfo.Name;
public string NameLowerCamel => ToCamelCase(PropertyInfo.Name);
public string NameSnakeCase => ToSnakeCase(PropertyInfo.Name);
public MetaProperty(PropertyInfo? propertyInfo)
{
PropertyInfo = propertyInfo!;
}
public override string ToString()
{
return Name;
}
/// <summary>
/// MyProperty -> myProperty
/// </summary>
static string ToCamelCase(string s)
{
if (string.IsNullOrEmpty(s) || char.IsLower(s, 0))
{
return s;
}
var array = s.ToCharArray();
array[0] = char.ToLowerInvariant(array[0]);
return new string(array);
}
/// <summary>
/// MyProperty -> my_property
/// </summary>
static string ToSnakeCase(string s)
{
if (string.IsNullOrEmpty(s)) return s;
var sb = new StringBuilder();
for (int i = 0; i < s.Length; i++)
{
var c = s[i];
if (Char.IsUpper(c))
{
// first
if (i == 0)
{
sb.Append(char.ToLowerInvariant(c));
}
else if (char.IsUpper(s[i - 1])) // WriteIO => write_io
{
sb.Append(char.ToLowerInvariant(c));
}
else
{
sb.Append("_");
sb.Append(char.ToLowerInvariant(c));
}
}
else
{
sb.Append(c);
}
}
return sb.ToString();
}
}
public class MetaIndex
{
public IReadOnlyList<PropertyInfo> IndexProperties { get; }
public bool IsPrimaryIndex { get; }
public bool IsUnique { get; }
public System.Collections.IComparer Comparer { get; }
public bool IsReturnRangeValue => IndexProperties.Count != 1;
public MetaIndex(IReadOnlyList<PropertyInfo> indexProperties, bool isPrimaryIndex, bool isUnique, System.Collections.IComparer comparer)
{
IndexProperties = indexProperties;
IsPrimaryIndex = isPrimaryIndex;
IsUnique = isUnique;
Comparer = comparer;
}
public override string ToString()
{
return string.Join(", ", IndexProperties.Select(x => x.Name));
}
}
}
================================================
FILE: src/MasterMemory/RangeView.cs
================================================
using System;
using System.Collections;
using System.Collections.Generic;
namespace MasterMemory
{
public readonly struct RangeView<T> : IEnumerable<T>, IReadOnlyList<T>, IList<T>
{
public static RangeView<T> Empty => new RangeView<T>(null, -1, -1, false);
readonly T[]? orderedData;
readonly int left;
readonly int right;
readonly bool ascendant;
readonly bool hasValue;
public int Count => (!hasValue) ? 0 : (right - left) + 1;
public T First => this[0];
public T Last => this[Count - 1];
public RangeView<T> Reverse => new RangeView<T>(orderedData, left, right, !ascendant);
internal int FirstIndex => ascendant ? left : right;
internal int LastIndex => ascendant ? right : left;
bool ICollection<T>.IsReadOnly => true;
public T this[int index]
{
get
{
if (!hasValue) throw new ArgumentOutOfRangeException("view is empty");
if (index < 0) throw new ArgumentOutOfRangeException("index < 0");
if (Count <= index) throw new ArgumentOutOfRangeException("count <= index");
if (ascendant)
{
return orderedData![left + index];
}
else
{
return orderedData![right - index];
}
}
}
public RangeView(T[]? orderedData, int left, int right, bool ascendant)
{
this.hasValue = (orderedData != null) && (orderedData.Length != 0) && (left <= right); // same index is length = 1 this.orderedData = orderedData;
this.orderedData = orderedData;
this.left = left;
this.right = right;
this.ascendant = ascendant;
}
public IEnumerator<T> GetEnumerator()
{
var count = Count;
for (int i = 0; i < count; i++)
{
yield return this[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public bool Any()
{
return Count != 0;
}
public int IndexOf(T item)
{
var i = 0;
foreach (var v in this)
{
if (EqualityComparer<T>.Default.Equals(v, item))
{
return i;
}
i++;
}
return -1;
}
public bool Contains(T item)
{
var count = Count;
for (int i = 0; i < count; i++)
{
var v = this[i];
if (EqualityComparer<T>.Default.Equals(v, item))
{
return true;
}
}
return false;
}
public void CopyTo(T[] array, int arrayIndex)
{
var count = Count;
Array.Copy(orderedData, left, array, arrayIndex, count);
if (!ascendant)
{
Array.Reverse(array, arrayIndex, count);
}
}
T IList<T>.this[int index]
{
get
{
return this[index];
}
set
{
throw new NotImplementedException();
}
}
void IList<T>.Insert(int index, T item)
{
throw new NotSupportedException();
}
void IList<T>.RemoveAt(int index)
{
throw new NotSupportedException();
}
void ICollection<T>.Add(T item)
{
throw new NotSupportedException();
}
void ICollection<T>.Clear()
{
throw new NotSupportedException();
}
bool ICollection<T>.Remove(T item)
{
throw new NotSupportedException();
}
}
}
================================================
FILE: src/MasterMemory/TableBase.cs
================================================
using MasterMemory.Internal;
using MasterMemory.Validation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace MasterMemory
{
public abstract class TableBase<TElement>
{
protected readonly TElement[] data;
// Common Properties
public int Count => data.Length;
public RangeView<TElement> All => new RangeView<TElement>(data, 0, data.Length - 1, true);
public RangeView<TElement> AllReverse => new RangeView<TElement>(data, 0, data.Length - 1, false);
public TElement[] GetRawDataUnsafe() => data;
public TableBase(TElement[] sortedData)
{
this.data = sortedData;
}
// Validate
static protected void ValidateUniqueCore<TKey>(TElement[] indexArray, Func<TElement, TKey> keySelector, string message, ValidateResult resultSet)
{
var set = new HashSet<TKey>();
foreach (var item in indexArray)
{
var v = keySelector(item);
if (!set.Add(v))
{
resultSet.AddFail(typeof(TElement), "Unique failed: " + message + ", value = " + v, item!);
}
}
}
// Util
protected TElement[] CloneAndSortBy<TKey>(Func<TElement, TKey> indexSelector, IComparer<TKey> comparer)
{
var array = new TElement[data.Length];
var sortSource = new TKey[data.Length];
for (int i = 0; i < data.Length; i++)
{
array[i] = data[i];
sortSource[i] = indexSelector(data[i]);
}
Array.Sort(sortSource, array, 0, array.Length, comparer);
return array;
}
static protected TElement ThrowKeyNotFound<TKey>(TKey key)
{
throw new KeyNotFoundException("DataType: " + typeof(TElement).FullName + ", Key: " + key?.ToString());
}
// Unique
static protected TElement FindUniqueCore<TKey>(TElement[] indexArray, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, TKey key, bool throwIfNotFound = true)
{
var index = BinarySearch.FindFirst(indexArray, key, keySelector, comparer);
if (index != -1)
{
return indexArray[index];
}
else
{
if (throwIfNotFound)
{
ThrowKeyNotFound(key);
}
return default!;
}
}
// Optimize for IntKey
static protected TElement FindUniqueCoreInt(TElement[] indexArray, Func<TElement, int> keySelector, IComparer<int> _, int key, bool throwIfNotFound = true)
{
var index = BinarySearch.FindFirstIntKey(indexArray, key, keySelector);
if (index != -1)
{
return indexArray[index];
}
else
{
if (throwIfNotFound)
{
ThrowKeyNotFound(key);
}
return default!;
}
}
static protected bool TryFindUniqueCore<TKey>(TElement[] indexArray, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, TKey key, out TElement result)
{
var index = BinarySearch.FindFirst(indexArray, key, keySelector, comparer);
if (index != -1)
{
result = indexArray[index];
return true;
}
else
{
result = default!;
return false;
}
}
static protected bool TryFindUniqueCoreInt(TElement[] indexArray, Func<TElement, int> keySelector, IComparer<int> _, int key, out TElement result)
{
var index = BinarySearch.FindFirstIntKey(indexArray, key, keySelector);
if (index != -1)
{
result = indexArray[index];
return true;
}
else
{
result = default!;
return false;
}
}
static protected TElement? FindUniqueClosestCore<TKey>(TElement[] indexArray, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, TKey key, bool selectLower)
{
var index = BinarySearch.FindClosest(indexArray, 0, indexArray.Length, key, keySelector, comparer, selectLower);
return (index != -1) ? indexArray[index] : default(TElement);
}
static protected RangeView<TElement> FindUniqueRangeCore<TKey>(TElement[] indexArray, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, TKey min, TKey max, bool ascendant)
{
var lo = BinarySearch.FindClosest(indexArray, 0, indexArray.Length, min, keySelector, comparer, false);
var hi = BinarySearch.FindClosest(indexArray, 0, indexArray.Length, max, keySelector, comparer, true);
if ( lo == -1 ) lo = 0;
if ( hi == indexArray.Length ) hi -= 1;
return new RangeView<TElement>(indexArray, lo, hi, ascendant);
}
// Many
static protected RangeView<TElement> FindManyCore<TKey>(TElement[] indexKeys, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, TKey key)
{
var lo = BinarySearch.LowerBound(indexKeys, 0, indexKeys.Length, key, keySelector, comparer);
if (lo == -1) return RangeView<TElement>.Empty;
var hi = BinarySearch.UpperBound(indexKeys, 0, indexKeys.Length, key, keySelector, comparer);
if (hi == -1) return RangeView<TElement>.Empty;
return new RangeView<TElement>(indexKeys, lo, hi, true);
}
static protected RangeView<TElement> FindManyClosestCore<TKey>(TElement[] indexArray, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, TKey key, bool selectLower)
{
var closest = BinarySearch.FindClosest(indexArray, 0, indexArray.Length, key, keySelector, comparer, selectLower);
if ((closest == -1) || ( closest >= indexArray.Length ))
return RangeView<TElement>.Empty;
return FindManyCore(indexArray, keySelector, comparer, keySelector(indexArray[closest]));
}
static protected RangeView<TElement> FindManyRangeCore<TKey>(TElement[] indexArray, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, TKey min, TKey max, bool ascendant)
{
//... Empty set when min > max
//... Alternatively, could treat this as between and swap min and max.
if ( Comparer<TKey>.Default.Compare( min, max ) > 0 )
return RangeView<TElement>.Empty;
//... want lo to be the lowest index of the values >= than min.
//... lo should be in the range [0,arraylength]
var lo = BinarySearch.LowerBoundClosest(indexArray, 0, indexArray.Length, min, keySelector, comparer );
//... want hi to be the highest index of the values <= than max
//... hi should be in the range [-1,arraylength-1]
var hi = BinarySearch.UpperBoundClosest(indexArray, 0, indexArray.Length, max, keySelector, comparer );
Debug.Assert( lo >= 0 );
Debug.Assert( hi < indexArray.Length );
if ( hi < lo )
return RangeView<TElement>.Empty;
return new RangeView<TElement>(indexArray, lo, hi, ascendant);
}
}
}
================================================
FILE: src/MasterMemory/Validation/ExpressionDumper.cs
================================================
using System;
using System.Linq;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
namespace MasterMemory.Validation
{
internal class ExpressionDumper<T> : ExpressionVisitor
{
ParameterExpression param;
T target;
public Dictionary<string, object> Members { get; private set; }
public ExpressionDumper(T target, ParameterExpression param)
{
this.target = target;
this.param = param;
this.Members = new Dictionary<string, object>();
}
protected override System.Linq.Expressions.Expression VisitMember(MemberExpression node)
{
if (node.Expression == param && !Members.ContainsKey(node.Member.Name))
{
var accessor = new ReflectAccessor(target, node.Member.Name);
Members.Add(node.Member.Name, accessor.GetValue());
}
return base.VisitMember(node);
}
public static string DumpMemberValues(T item, Expression<Func<T, bool>> predicate)
{
var dumper = new ExpressionDumper<T>(item, predicate.Parameters.Single());
return dumper.VisitAndFormat(predicate);
}
public string VisitAndFormat(Expression expression)
{
Visit(expression);
return string.Join(", ", Members.Select(kvp => kvp.Key + " = " + kvp.Value));
}
private class ReflectAccessor
{
public Func<object> GetValue { get; private set; }
public Action<object> SetValue { get; private set; }
public ReflectAccessor(T target, string name)
{
var field = typeof(T).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
{
GetValue = () => field.GetValue(target);
SetValue = value => field.SetValue(target, value);
return;
}
var prop = typeof(T).GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (prop != null)
{
GetValue = () => prop.GetValue(target, null);
SetValue = value => prop.SetValue(target, value, null);
return;
}
throw new ArgumentException(string.Format("\"{0}\" not found : Type <{1}>", name, typeof(T).Name));
}
}
}
}
================================================
FILE: src/MasterMemory/Validation/ExpressionParameterNameModifier.cs
================================================
using System;
using System.Linq.Expressions;
namespace MasterMemory.Validation
{
public class ExpressionParameterNameModifier : ExpressionVisitor
{
readonly ParameterExpression modifyTarget;
readonly ParameterExpression replaceExpression;
public ExpressionParameterNameModifier(ParameterExpression modifyTarget, ParameterExpression replaceExpression)
{
this.modifyTarget = modifyTarget;
this.replaceExpression = replaceExpression;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node == modifyTarget)
{
return replaceExpression;
}
return base.VisitParameter(node);
}
}
public static class ExpressionParameterNameModifyExtensions
{
public static string ToThisBodyString<T>(this Expression<Func<T, bool>> predicate)
{
var newNameParameter = Expression.Parameter(typeof(T), "this");
var newExpression = new ExpressionParameterNameModifier(predicate.Parameters[0], newNameParameter).Visit(predicate);
return (newExpression as Expression<Func<T, bool>>)!.Body.ToString();
}
public static string ToSpaceBodyString<T, TProperty>(this Expression<Func<T, TProperty>> selector)
{
var newNameParameter = Expression.Parameter(typeof(T), " ");
var newExpression = new ExpressionParameterNameModifier(selector.Parameters[0], newNameParameter).Visit(selector);
return (newExpression as Expression<Func<T, TProperty>>)!.Body.ToString();
}
public static string ToNameBodyString<T, TProperty>(this Expression<Func<T, TProperty>> selector, string newName)
{
var newNameParameter = Expression.Parameter(typeof(T), newName);
var newExpression = new ExpressionParameterNameModifier(selector.Parameters[0], newNameParameter).Visit(selector);
return (newExpression as Expression<Func<T, TProperty>>)!.Body.ToString();
}
}
}
================================================
FILE: src/MasterMemory/Validation/ITableUniqueValidate.cs
================================================
namespace MasterMemory.Validation
{
public interface ITableUniqueValidate
{
void ValidateUnique(ValidateResult resultSet);
}
}
================================================
FILE: src/MasterMemory/Validation/ReferenceSet.cs
================================================
using System;
using System.Linq;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace MasterMemory.Validation
{
public class ReferenceSet<TElement, TReference>
{
readonly TElement item;
readonly IReadOnlyList<TReference> referenceTable;
readonly ValidateResult resultSet;
readonly string pkName;
readonly Delegate pkSelector;
public IReadOnlyList<TReference> TableData => referenceTable;
public ReferenceSet(TElement item, IReadOnlyList<TReference> referenceTable, ValidateResult resultSet, string pkName, Delegate pkSelector)
{
this.item = item;
this.referenceTable = referenceTable;
this.resultSet = resultSet;
this.pkName = pkName;
this.pkSelector = pkSelector;
}
public void Exists<TProperty>(Expression<Func<TElement, TProperty>> elementSelector, Expression<Func<TReference, TProperty>> referenceElementSelector)
{
Exists(elementSelector, referenceElementSelector, EqualityComparer<TProperty>.Default);
}
public void Exists<TProperty>(Expression<Func<TElement, TProperty>> elementSelector, Expression<Func<TReference, TProperty>> referenceElementSelector, EqualityComparer<TProperty> equalityComparer)
{
var f1 = elementSelector.Compile(true);
var f2 = referenceElementSelector.Compile(true);
var compareBase = f1(item);
foreach (var refItem in referenceTable)
{
if (equalityComparer.Equals(compareBase, f2(refItem)))
{
return;
}
}
// not found, assert.
var from = elementSelector.ToNameBodyString(typeof(TElement).Name);
var to = referenceElementSelector.ToNameBodyString(typeof(TReference).Name);
resultSet.AddFail(typeof(TElement), "Exists failed: " + from + " -> " + to + ", value = " + compareBase + ", " + BuildPkMessage(), item!);
}
string BuildPkMessage()
{
var pk = pkSelector.DynamicInvoke(item).ToString();
return $"PK({pkName}) = {pk}";
}
}
}
================================================
FILE: src/MasterMemory/Validation/ValidatableSet.Sequential.cs
================================================
using System;
using System.Linq;
using System.Linq.Expressions;
namespace MasterMemory.Validation
{
public partial class ValidatableSet<TElement>
{
public void Sequential(Expression<Func<TElement, SByte>> selector, bool distinct = false)
{
var f = selector.Compile(true);
SequentialCore(f, () => selector.ToSpaceBodyString(), distinct);
}
public void Sequential(Func<TElement, SByte> selector, string message, bool distinct = false)
{
SequentialCore(selector, () => " " + message, distinct);
}
void SequentialCore(Func<TElement, SByte> selector, Func<string> message, bool distinct)
{
if (tableData.Count == 0) return;
var data = tableData.OrderBy(selector).ToArray();
var prev = selector(data[0]);
for (int i = 1; i < data.Length; i++)
{
var curr = selector(data[i]);
if (distinct)
{
if (prev == curr) continue;
}
if ((prev + 1) != curr)
{
resultSet.AddFail(typeof(TElement), "Sequential failed:" + message() + ", value = " + (prev, curr) + ", " + BuildPkMessage(data[i]), data[i]!);
}
prev = curr;
}
}
public void Sequential(Expression<Func<TElement, Int16>> selector, bool distinct = false)
{
var f = selector.Compile(true);
SequentialCore(f, () => selector.ToSpaceBodyString(), distinct);
}
public void Sequential(Func<TElement, Int16> selector, string message, bool distinct = false)
{
SequentialCore(selector, () => " " + message, distinct);
}
void SequentialCore(Func<TElement, Int16> selector, Func<string> message, bool distinct)
{
if (tableData.Count == 0) return;
var data = tableData.OrderBy(selector).ToArray();
var prev = selector(data[0]);
for (int i = 1; i < data.Length; i++)
{
var curr = selector(data[i]);
if (distinct)
{
if (prev == curr) continue;
}
if ((prev + 1) != curr)
{
resultSet.AddFail(typeof(TElement), "Sequential failed:" + message() + ", value = " + (prev, curr) + ", " + BuildPkMessage(data[i]), data[i]!);
}
prev = curr;
}
}
public void Sequential(Expression<Func<TElement, Int32>> selector, bool distinct = false)
{
var f = selector.Compile(true);
SequentialCore(f, () => selector.ToSpaceBodyString(), distinct);
}
public void Sequential(Func<TElement, Int32> selector, string message, bool distinct = false)
{
SequentialCore(selector, () => " " + message, distinct);
}
void SequentialCore(Func<TElement, Int32> selector, Func<string> message, bool distinct)
{
if (tableData.Count == 0) return;
var data = tableData.OrderBy(selector).ToArray();
var prev = selector(data[0]);
for (int i = 1; i < data.Length; i++)
{
var curr = selector(data[i]);
if (distinct)
{
if (prev == curr) continue;
}
if ((prev + 1) != curr)
{
resultSet.AddFail(typeof(TElement), "Sequential failed:" + message() + ", value = " + (prev, curr) + ", " + BuildPkMessage(data[i]), data[i]!);
}
prev = curr;
}
}
public void Sequential(Expression<Func<TElement, Int64>> selector, bool distinct = false)
{
var f = selector.Compile(true);
SequentialCore(f, () => selector.ToSpaceBodyString(), distinct);
}
public void Sequential(Func<TElement, Int64> selector, string message, bool distinct = false)
{
SequentialCore(selector, () => " " + message, distinct);
}
void SequentialCore(Func<TElement, Int64> selector, Func<string> message, bool distinct)
{
if (tableData.Count == 0) return;
var data = tableData.OrderBy(selector).ToArray();
var prev = selector(data[0]);
for (int i = 1; i < data.Length; i++)
{
var curr = selector(data[i]);
if (distinct)
{
if (prev == curr) continue;
}
if ((prev + 1) != curr)
{
resultSet.AddFail(typeof(TElement), "Sequential failed:" + message() + ", value = " + (prev, curr) + ", " + BuildPkMessage(data[i]), data[i]!);
}
prev = curr;
}
}
public void Sequential(Expression<Func<TElement, Byte>> selector, bool distinct = false)
{
var f = selector.Compile(true);
SequentialCore(f, () => selector.ToSpaceBodyString(), distinct);
}
public void Sequential(Func<TElement, Byte> selector, string message, bool distinct = false)
{
SequentialCore(selector, () => " " + message, distinct);
}
void SequentialCore(Func<TElement, Byte> selector, Func<string> message, bool distinct)
{
if (tableData.Count == 0) return;
var data = tableData.OrderBy(selector).ToArray();
var prev = selector(data[0]);
for (int i = 1; i < data.Length; i++)
{
var curr = selector(data[i]);
if (distinct)
{
if (prev == curr) continue;
}
if ((prev + 1) != curr)
{
resultSet.AddFail(typeof(TElement), "Sequential failed:" + message() + ", value = " + (prev, curr) + ", " + BuildPkMessage(data[i]), data[i]!);
}
prev = curr;
}
}
public void Sequential(Expression<Func<TElement, UInt16>> selector, bool distinct = false)
{
var f = selector.Compile(true);
SequentialCore(f, () => selector.ToSpaceBodyString(), distinct);
}
public void Sequential(Func<TElement, UInt16> selector, string message, bool distinct = false)
{
SequentialCore(selector, () => " " + message, distinct);
}
void SequentialCore(Func<TElement, UInt16> selector, Func<string> message, bool distinct)
{
if (tableData.Count == 0) return;
var data = tableData.OrderBy(selector).ToArray();
var prev = selector(data[0]);
for (int i = 1; i < data.Length; i++)
{
var curr = selector(data[i]);
if (distinct)
{
if (prev == curr) continue;
}
if ((prev + 1) != curr)
{
resultSet.AddFail(typeof(TElement), "Sequential failed:" + message() + ", value = " + (prev, curr) + ", " + BuildPkMessage(data[i]), data[i]!);
}
prev = curr;
}
}
public void Sequential(Expression<Func<TElement, UInt32>> selector, bool distinct = false)
{
var f = selector.Compile(true);
SequentialCore(f, () => selector.ToSpaceBodyString(), distinct);
}
public void Sequential(Func<TElement, UInt32> selector, string message, bool distinct = false)
{
SequentialCore(selector, () => " " + message, distinct);
}
void SequentialCore(Func<TElement, UInt32> selector, Func<string> message, bool distinct)
{
if (tableData.Count == 0) return;
var data = tableData.OrderBy(selector).ToArray();
var prev = selector(data[0]);
for (int i = 1; i < data.Length; i++)
{
var curr = selector(data[i]);
if (distinct)
{
if (prev == curr) continue;
}
if ((prev + 1) != curr)
{
resultSet.AddFail(typeof(TElement), "Sequential failed:" + message() + ", value = " + (prev, curr) + ", " + BuildPkMessage(data[i]), data[i]!);
}
prev = curr;
}
}
public void Sequential(Expression<Func<TElement, UInt64>> selector, bool distinct = false)
{
var f = selector.Compile(true);
SequentialCore(f, () => selector.ToSpaceBodyString(), distinct);
}
public void Sequential(Func<TElement, UInt64> selector, string message, bool distinct = false)
{
SequentialCore(selector, () => " " + message, distinct);
}
void SequentialCore(Func<TElement, UInt64> selector, Func<string> message, bool distinct)
{
if (tableData.Count == 0) return;
var data = tableData.OrderBy(selector).ToArray();
var prev = selector(data[0]);
for (int i = 1; i < data.Length; i++)
{
var curr = selector(data[i]);
if (distinct)
{
if (prev == curr) continue;
}
if ((prev + 1) != curr)
{
resultSet.AddFail(typeof(TElement), "Sequential failed:" + message() + ", value = " + (prev, curr) + ", " + BuildPkMessage(data[i]), data[i]!);
}
prev = curr;
}
}
}
}
================================================
FILE: src/MasterMemory/Validation/ValidatableSet.Sequential.tt
================================================
<#@ template debug="true" hostSpecific="false" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="System.Core" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#
var targetTypes = new[]
{
typeof(sbyte),
typeof(short),
typeof(int),
typeof(long),
typeof(byte),
typeof(ushort),
typeof(uint),
typeof(ulong),
};
#>
using System;
using System.Linq;
using System.Linq.Expressions;
namespace MasterMemory.Validation
{
public partial class ValidatableSet<TElement>
{
<# foreach(var t in targetTypes) { #>
public void Sequential(Expression<Func<TElement, <#= t.Name #>>> selector, bool distinct = false)
{
var f = selector.Compile(true);
SequentialCore(f, () => selector.ToSpaceBodyString(), distinct);
}
public void Sequential(Func<TElement, <#= t.Name #>> selector, string message, bool distinct = false)
{
SequentialCore(selector, () => " " + message, distinct);
}
void SequentialCore(Func<TElement, <#= t.Name #>> selector, Func<string> message, bool distinct)
{
if (tableData.Count == 0) return;
var data = tableData.OrderBy(selector).ToArray();
var prev = selector(data[0]);
for (int i = 1; i < data.Length; i++)
{
var curr = selector(data[i]);
if (distinct)
{
if (prev == curr) continue;
}
if ((prev + 1) != curr)
{
resultSet.AddFail(typeof(TElement), "Sequential failed:" + message() + ", value = " + (prev, curr) + ", " + BuildPkMessage(data[i]), data[i]);
}
prev = curr;
}
}
<# } #>
}
}
================================================
FILE: src/MasterMemory/Validation/ValidatableSet.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace MasterMemory.Validation
{
public partial class ValidatableSet<TElement>
{
readonly IReadOnlyList<TElement> tableData;
readonly ValidateResult resultSet;
readonly string pkName;
readonly Delegate pkSelector;
public ValidatableSet(IReadOnlyList<TElement> tableData, ValidateResult resultSet, string pkName, Delegate pkSelector)
{
this.tableData = tableData;
this.resultSet = resultSet;
this.pkName = pkName;
this.pkSelector = pkSelector;
}
public IReadOnlyList<TElement> TableData => tableData;
public void Unique<TProperty>(Expression<Func<TElement, TProperty>> selector)
{
Unique(selector, EqualityComparer<TProperty>.Default);
}
public void Unique<TProperty>(Expression<Func<TElement, TProperty>> selector, IEqualityComparer<TProperty> equalityComparer)
{
var f = selector.Compile(true);
var set = new HashSet<TProperty>(equalityComparer);
foreach (var item in tableData)
{
var v = f(item);
if (!set.Add(v))
{
resultSet.AddFail(typeof(TElement), "Unique failed:" + selector.ToSpaceBodyString() + ", value = " + v + ", " + BuildPkMessage(item), item!);
}
}
}
public void Unique<TProperty>(Func<TElement, TProperty> selector, string message)
{
Unique(selector, EqualityComparer<TProperty>.Default, message);
}
public void Unique<TProperty>(Func<TElement, TProperty> selector, IEqualityComparer<TProperty> equalityComparer, string message)
{
var set = new HashSet<TProperty>(equalityComparer);
foreach (var item in tableData)
{
var v = selector(item);
if (!set.Add(v))
{
resultSet.AddFail(typeof(TElement), "Unique failed: " + message + ", value = " + v + ", " + BuildPkMessage(item), item!);
}
}
}
public ValidatableSet<TElement> Where(Func<TElement, bool> predicate)
{
return new ValidatableSet<TElement>(tableData.Where(predicate).ToArray(), resultSet, pkName, pkSelector);
}
string BuildPkMessage(TElement item)
{
var pk = pkSelector.DynamicInvoke(item).ToString();
return $"PK({pkName}) = {pk}";
}
}
}
================================================
FILE: src/MasterMemory/Validation/ValidateResult.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
namespace MasterMemory.Validation
{
public class ValidateResult
{
List<FaildItem> result = new List<FaildItem>();
public bool IsValidationFailed => result.Count != 0;
public IReadOnlyList<FaildItem> FailedResults => result;
public string FormatFailedResults()
{
var sb = new StringBuilder();
foreach (var item in result)
{
sb.AppendLine(item.Type.FullName + " - " + item.Message);
}
return sb.ToString();
}
internal void AddFail(Type type, string message, object data)
{
result.Add(new FaildItem(type, message, data));
}
}
public readonly struct FaildItem
{
public FaildItem(Type type, string message, object data)
{
Type = type;
Message = message;
Data = data;
}
public Type Type { get; }
public string Message { get; }
public object Data { get; }
}
}
================================================
FILE: src/MasterMemory/Validation/ValidationDatabase.cs
================================================
using System;
using System.Collections.Generic;
namespace MasterMemory.Validation
{
public class ValidationDatabase
{
// {Type, IReadOnlyList<T> }
readonly Dictionary<Type, object> dataTables = new Dictionary<Type, object>();
public ValidationDatabase(IEnumerable<object> tables)
{
foreach (var table in tables)
{
// TableBase<T>
var baseType = table.GetType().BaseType;
// RangeView<T>
var rangeViewAll = baseType.GetProperty("All").GetGetMethod().Invoke(table, null);
var elementType = baseType.GetGenericArguments()[0];
dataTables.Add(elementType, rangeViewAll);
}
}
internal IReadOnlyList<T> GetTable<T>()
{
if (!dataTables.TryGetValue(typeof(T), out var table))
{
throw new InvalidOperationException("Can not create validator in " + typeof(T).FullName);
}
var data = table as IReadOnlyList<T>;
return data!;
}
}
}
================================================
FILE: src/MasterMemory/Validation/Validator.cs
================================================
using System;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
namespace MasterMemory.Validation
{
internal class Validator<T> : IValidator<T>
{
readonly ValidationDatabase database;
readonly T item;
readonly ValidateResult resultSet;
readonly StrongBox<bool> onceCalled;
readonly string pkName;
readonly Delegate pkSelector;
public Validator(ValidationDatabase database, T item, ValidateResult resultSet, StrongBox<bool> onceCalled, string pkName, Delegate pkSelector)
{
this.database = database;
this.item = item;
this.resultSet = resultSet;
this.onceCalled = onceCalled;
this.pkName = pkName;
this.pkSelector = pkSelector;
}
public bool CallOnce()
{
if (!onceCalled.Value)
{
onceCalled.Value = true;
return true;
}
return false;
}
public ValidatableSet<T> GetTableSet()
{
return new ValidatableSet<T>(database.GetTable<T>(), resultSet, pkName, pkSelector);
}
public ReferenceSet<T, TRef> GetReferenceSet<TRef>()
{
var table = database.GetTable<TRef>();
return new ReferenceSet<T, TRef>(item, table, resultSet, pkName, pkSelector);
}
public void Validate(Expression<Func<T, bool>> predicate)
{
if (!predicate.Compile(true).Invoke(item))
{
var memberValues = ExpressionDumper<T>.DumpMemberValues(item, predicate);
var message = string.Format($"{predicate.ToThisBodyString()}, {memberValues}, {BuildPkMessage()}");
resultSet.AddFail(typeof(T), "Validate failed: " + message, item!);
}
}
public void Validate(Func<T, bool> predicate, string message)
{
if (!predicate(item))
{
resultSet.AddFail(typeof(T), "Validate failed: " + message + ", " + BuildPkMessage(), item!);
}
}
public void ValidateAction(Expression<Func<bool>> predicate)
{
if (!predicate.Compile(true).Invoke())
{
var expr = predicate.Body.ToString();
resultSet.AddFail(typeof(T), "ValidateAction failed: " + expr + ", " + BuildPkMessage(), item!);
}
}
public void ValidateAction(Func<bool> predicate, string message)
{
if (!predicate())
{
resultSet.AddFail(typeof(T), "ValidateAction failed: " + message + ", " + BuildPkMessage(), item!);
}
}
public void Fail(string message)
{
resultSet.AddFail(typeof(T), message + ", " + BuildPkMessage(), item!);
}
string BuildPkMessage()
{
var pk = pkSelector.DynamicInvoke(item).ToString();
return $"PK({pkName}) = {pk}";
}
}
}
================================================
FILE: src/MasterMemory/_InternalVisibleTo.cs
================================================
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("MasterMemory.Tests")]
================================================
FILE: src/MasterMemory/_MessagePackResolver.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
namespace MasterMemory;
[MessagePack.GeneratedMessagePackResolver]
internal partial class _MessagePackResolver
{
}
================================================
FILE: src/MasterMemory.Annotations/Attributes.cs
================================================
using System;
namespace MasterMemory
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class MemoryTableAttribute : Attribute
{
public string TableName { get; }
public MemoryTableAttribute(string tableName)
{
this.TableName = tableName;
}
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class PrimaryKeyAttribute : Attribute
{
public int KeyOrder { get; }
public PrimaryKeyAttribute(int keyOrder = 0)
{
this.KeyOrder = keyOrder;
}
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class SecondaryKeyAttribute : Attribute
{
public int IndexNo { get; }
public int KeyOrder { get; }
public SecondaryKeyAttribute(int indexNo, int keyOrder = 0)
{
this.IndexNo = indexNo;
this.KeyOrder = keyOrder;
}
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class NonUniqueAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class StringComparisonOptionAttribute : Attribute
{
public StringComparison StringComparison { get; }
public StringComparisonOptionAttribute(StringComparison stringComparison)
{
this.StringComparison = stringComparison;
}
}
}
================================================
FILE: src/MasterMemory.Annotations/MasterMemory.Annotations.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>13</LangVersion>
<OutputType>Library</OutputType>
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<Company>Cysharp</Company>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>1701;1702;1705;1591</NoWarn>
<RootNamespace>MasterMemory</RootNamespace>
<!-- NuGet -->
<PackageId>MasterMemory.Annotations</PackageId>
<Description>Attributes of MasterMemory.</Description>
<IsPackable>true</IsPackable>
</PropertyGroup>
</Project>
================================================
FILE: src/MasterMemory.SourceGenerator/DiagnosticDescriptors.cs
================================================
using Microsoft.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.Text;
namespace MasterMemory;
internal sealed class DiagnosticReporter : IEquatable<DiagnosticReporter>
{
List<Diagnostic>? diagnostics;
public bool HasDiagnostics => diagnostics != null && diagnostics.Count != 0;
public void ReportDiagnostic(DiagnosticDescriptor diagnosticDescriptor, Location location, params object?[]? messageArgs)
{
var diagnostic = Diagnostic.Create(diagnosticDescriptor, location, messageArgs);
if (diagnostics == null)
{
diagnostics = new();
}
diagnostics.Add(diagnostic);
}
public void ReportToContext(SourceProductionContext context)
{
if (diagnostics != null)
{
foreach (var item in diagnostics)
{
context.ReportDiagnostic(item);
}
}
}
public bool Equals(DiagnosticReporter other)
{
// if error, always false and otherwise ignore
if (diagnostics == null && other.diagnostics == null)
{
return true;
}
return false;
}
}
internal static class DiagnosticDescriptors
{
const string Category = "GenerateMasterMemory";
public static void ReportDiagnostic(this SourceProductionContext context, DiagnosticDescriptor diagnosticDescriptor, Location location, params object?[]? messageArgs)
{
var diagnostic = Diagnostic.Create(diagnosticDescriptor, location, messageArgs);
context.ReportDiagnostic(diagnostic);
}
public static DiagnosticDescriptor Create(int id, string message)
{
return Create(id, message, message);
}
public static DiagnosticDescriptor Create(int id, string title, string messageFormat)
{
return new DiagnosticDescriptor(
id: "MAM" + id.ToString("000"),
title: title,
messageFormat: messageFormat,
category: Category,
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);
}
public static DiagnosticDescriptor RequirePrimaryKey { get; } = Create(
1,
"MemoryTable does not found PrimaryKey property, Type:{0}.");
public static DiagnosticDescriptor DuplicatePrimaryKey { get; } = Create(
2,
"Duplicate PrimaryKey:{0}.{1}");
public static DiagnosticDescriptor DuplicateSecondaryKey { get; } = Create(
3,
"Duplicate SecondaryKey, doesn't allow to add multiple attribute in same attribute list:{0}.{1}");
}
================================================
FILE: src/MasterMemory.SourceGenerator/GeneratorCore/CodeGenerator.cs
================================================
#nullable disable
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace MasterMemory.GeneratorCore
{
internal static class CodeGenerator
{
// return GenerationContext?
public static GenerationContext CreateGenerationContext(TypeDeclarationSyntax classDecl, AttributeData memoryTableAttribute, DiagnosticReporter reporter)
{
var context = new GenerationContext();
context.ClassName = classDecl.Identifier.ToFullString().Trim();
context.MemoryTableName = memoryTableAttribute.ConstructorArguments[0].Value as string ?? context.ClassName;
var hasError = false;
var members = classDecl.Members.OfType<PropertyDeclarationSyntax>()
.Select(x =>
{
var prop = ExtractPropertyAttribute(x, reporter);
if (prop == null)
{
hasError = true;
return default!;
}
return prop.Value;
})
.ToArray();
if (hasError) return null;
var primaryKey = AggregatePrimaryKey(members.Where(x => x.Item1 != null).Select(x => x.Item1));
if (primaryKey.Properties.Length == 0)
{
reporter.ReportDiagnostic(DiagnosticDescriptors.RequirePrimaryKey, classDecl.Identifier.GetLocation(), context.ClassName);
return null;
}
var secondaryKeys = members.SelectMany(x => x.Item2).GroupBy(x => x.IndexNo).Select(x => AggregateSecondaryKey(x)).ToArray();
var properties = members.Where(x => x.Item3 != null).Select(x => new Property
{
Type = x.Item3.Type.ToFullStringTrim(),
Name = x.Item3.Identifier.Text,
}).ToArray();
var root = classDecl.SyntaxTree.GetRoot();
var ns = root.DescendantNodes().OfType<NamespaceDeclarationSyntax>()
.Select(x => "using " + x.Name.ToFullStringTrim() + ";")
.ToArray();
var usingStrings = root.DescendantNodes()
.OfType<UsingDirectiveSyntax>()
.Select(x => x.ToFullString().Trim())
.Concat(new[] { "using MasterMemory", "using MasterMemory.Validation", "using System", "using System.Collections.Generic" })
.Concat(n
gitextract_t6q9u1cd/
├── .editorconfig
├── .github/
│ ├── dependabot.yaml
│ └── workflows/
│ ├── build-debug.yaml
│ ├── build-release.yaml
│ ├── prevent-github-change.yaml
│ ├── stale.yaml
│ └── toc.yaml
├── .gitignore
├── Directory.Build.props
├── LICENSE
├── MasterMemory.sln
├── README.md
├── sandbox/
│ ├── Benchmark/
│ │ ├── Benchmark.csproj
│ │ ├── Program.cs
│ │ └── Utils/
│ │ └── Helper.cs
│ ├── ConsoleApp/
│ │ ├── ConsoleApp.csproj
│ │ └── Program.cs
│ ├── GeneratorSandbox/
│ │ ├── GeneratorSandbox.csproj
│ │ └── Program.cs
│ └── PerfTest2/
│ ├── Engines/
│ │ ├── Dictionary_Test.cs
│ │ ├── ITest.cs
│ │ ├── LiteDB_Test.cs
│ │ ├── MasterMemory_Test.cs
│ │ ├── RavenDB_Test.cs
│ │ └── SQLite_Test.cs
│ ├── Generated/
│ │ ├── DatabaseBuilder.cs
│ │ ├── ImmutableBuilder.cs
│ │ ├── MasterMemoryResolver.cs
│ │ ├── MemoryDatabase.cs
│ │ └── Tables/
│ │ └── TestDocTable.cs
│ ├── PerfTest2.csproj
│ ├── Program.cs
│ └── Utils/
│ └── Helper.cs
├── src/
│ ├── MasterMemory/
│ │ ├── DatabaseBuilderBase.cs
│ │ ├── DatabaseBuilderBaseExtensions.cs
│ │ ├── IValidatable.cs
│ │ ├── ImmutableBuilderBase.cs
│ │ ├── Internal/
│ │ │ ├── BinarySearch.cs
│ │ │ ├── ByteBufferWriter.cs
│ │ │ ├── ExpandableArray.cs
│ │ │ ├── HeaderFormatterResolver.cs
│ │ │ └── InternStringResolver.cs
│ │ ├── MasterMemory.csproj
│ │ ├── MemoryDatabaseBase.cs
│ │ ├── Meta/
│ │ │ └── Meta.cs
│ │ ├── RangeView.cs
│ │ ├── TableBase.cs
│ │ ├── Validation/
│ │ │ ├── ExpressionDumper.cs
│ │ │ ├── ExpressionParameterNameModifier.cs
│ │ │ ├── ITableUniqueValidate.cs
│ │ │ ├── ReferenceSet.cs
│ │ │ ├── ValidatableSet.Sequential.cs
│ │ │ ├── ValidatableSet.Sequential.tt
│ │ │ ├── ValidatableSet.cs
│ │ │ ├── ValidateResult.cs
│ │ │ ├── ValidationDatabase.cs
│ │ │ └── Validator.cs
│ │ ├── _InternalVisibleTo.cs
│ │ └── _MessagePackResolver.cs
│ ├── MasterMemory.Annotations/
│ │ ├── Attributes.cs
│ │ └── MasterMemory.Annotations.csproj
│ ├── MasterMemory.SourceGenerator/
│ │ ├── DiagnosticDescriptors.cs
│ │ ├── GeneratorCore/
│ │ │ ├── CodeGenerator.cs
│ │ │ ├── DatabaseBuilderTemplate.cs
│ │ │ ├── DatabaseBuilderTemplate.tt
│ │ │ ├── GenerationContext.cs
│ │ │ ├── ImmutableBuilderTemplate.cs
│ │ │ ├── ImmutableBuilderTemplate.tt
│ │ │ ├── MemoryDatabaseTemplate.cs
│ │ │ ├── MemoryDatabaseTemplate.tt
│ │ │ ├── MessagePackResolverTemplate.cs
│ │ │ ├── MessagePackResolverTemplate.tt
│ │ │ ├── TableTemplate.cs
│ │ │ ├── TableTemplate.tt
│ │ │ └── Template.cs
│ │ ├── MasterMemory.SourceGenerator.csproj
│ │ ├── MasterMemoryGenerator.cs
│ │ ├── MasterMemoryGeneratorOptions.cs
│ │ ├── Polyfill/
│ │ │ └── System.CodeDom.cs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ └── Utility/
│ │ ├── EquatableArray.cs
│ │ └── IgnoreEquality.cs
│ └── MasterMemory.Unity/
│ ├── Assets/
│ │ ├── NuGet.config
│ │ ├── NuGet.config.meta
│ │ ├── Packages.meta
│ │ ├── Scenes/
│ │ │ ├── Main.unity
│ │ │ └── Main.unity.meta
│ │ ├── Scenes.meta
│ │ ├── Scripts/
│ │ │ ├── NewBehaviourScript.cs
│ │ │ └── NewBehaviourScript.cs.meta
│ │ ├── Scripts.meta
│ │ ├── packages.config
│ │ └── packages.config.meta
│ ├── Packages/
│ │ ├── manifest.json
│ │ └── packages-lock.json
│ └── ProjectSettings/
│ ├── AudioManager.asset
│ ├── ClusterInputManager.asset
│ ├── DynamicsManager.asset
│ ├── EditorBuildSettings.asset
│ ├── EditorSettings.asset
│ ├── GraphicsSettings.asset
│ ├── InputManager.asset
│ ├── MemorySettings.asset
│ ├── NavMeshAreas.asset
│ ├── NetworkManager.asset
│ ├── PackageManagerSettings.asset
│ ├── Physics2DSettings.asset
│ ├── PresetManager.asset
│ ├── ProjectSettings.asset
│ ├── ProjectVersion.txt
│ ├── QualitySettings.asset
│ ├── SceneTemplateSettings.json
│ ├── TagManager.asset
│ ├── TimeManager.asset
│ ├── UnityConnectSettings.asset
│ ├── VFXManager.asset
│ ├── VersionControlSettings.asset
│ └── XRSettings.asset
└── tests/
├── MasterMemory.SourceGenerator.Tests/
│ ├── AssemblyAtrributeTest.cs
│ ├── DiagnosticsTest.cs
│ ├── GenerateTest.cs
│ ├── IncrementalGeneratorTest.cs
│ ├── MasterMemory.SourceGenerator.Tests.csproj
│ ├── TestBase.cs
│ └── Utility/
│ ├── CSharpGeneratorRunner.cs
│ └── CodeGeneratorHelper.cs
└── MasterMemory.Tests/
├── BinarySearchTest.cs
├── DatabaseTest.cs
├── IssueTest.cs
├── MasterMemory.Tests.csproj
├── MemoryKeyTest.cs
├── MemoryTest.cs
├── MessagePackResolver.cs
├── MetaTest.cs
├── RangeViewTest.cs
├── TestStructures/
│ ├── PersonModel.cs
│ ├── QuestMaster.cs
│ ├── Sample.cs
│ ├── SkillMaster.cs
│ ├── TestMaster.cs
│ └── UserLevel.cs
└── ValidatorTest.cs
SYMBOL INDEX (614 symbols across 77 files)
FILE: sandbox/Benchmark/Program.cs
class Program (line 32) | class Program
method Main (line 34) | static void Main(string[] args)
class BenchmarkConfig (line 40) | public class BenchmarkConfig : ManualConfig
method BenchmarkConfig (line 42) | public BenchmarkConfig()
class SimpleRun (line 57) | [Config(typeof(BenchmarkConfig))]
method SimpleRun (line 76) | public SimpleRun()
method MakeDoc (line 122) | public IEnumerable<TestDoc> MakeDoc(int count)
method MasterMemoryQuery (line 137) | [Benchmark(Baseline = true)]
method SQLiteInMemoryQuery (line 143) | [Benchmark]
method SQLiteFileQuery (line 162) | [Benchmark]
method LiteDbDefaultQuery (line 183) | [Benchmark]
method LiteDbInMemoryQuery (line 189) | [Benchmark]
method LocalMemcachedQuery (line 195) | [Benchmark]
method RocksDbQuery (line 207) | [Benchmark]
class SQLite_Test (line 215) | public class SQLite_Test
method SQLite_Test (line 223) | public SQLite_Test(int count, string password, bool journal, bool memo...
method Prepare (line 242) | public void Prepare()
method Insert (line 253) | public void Insert()
method CreateIndex (line 277) | public void CreateIndex()
method Query (line 284) | public void Query()
method Dispose (line 306) | public void Dispose()
class LiteDB_Test (line 313) | public class LiteDB_Test
method LiteDB_Test (line 321) | public LiteDB_Test(int count, string password, LiteDB.FileOptions opti...
method LiteDB_Test (line 331) | public LiteDB_Test(int count)
method Prepare (line 343) | public void Prepare()
method Insert (line 347) | public void Insert()
method Bulk (line 355) | public void Bulk()
method Update (line 360) | public void Update()
method CreateIndex (line 368) | public void CreateIndex()
method Query (line 373) | public void Query()
method Delete (line 381) | public void Delete()
method Drop (line 386) | public void Drop()
method Dispose (line 391) | public void Dispose()
class LiteDB_Test2 (line 399) | public class LiteDB_Test2
method LiteDB_Test2 (line 408) | public LiteDB_Test2(int count, string password, LiteDB.FileOptions opt...
method LiteDB_Test2 (line 420) | public LiteDB_Test2(int count)
method Prepare (line 434) | public void Prepare()
method Insert (line 438) | public void Insert()
method CreateIndex (line 451) | public void CreateIndex()
class Dummy (line 458) | class Dummy : IOptions<MemcachedClientOptions>
class LoggerDummy (line 468) | class LoggerDummy : ILoggerFactory
method AddProvider (line 470) | public void AddProvider(ILoggerProvider provider)
method CreateLogger (line 474) | public ILogger CreateLogger(string categoryName)
method Dispose (line 479) | public void Dispose()
class NullLogger (line 483) | class NullLogger : ILogger
method BeginScope (line 485) | public IDisposable BeginScope<TState>(TState state)
method IsEnabled (line 490) | public bool IsEnabled(LogLevel logLevel)
method Log (line 495) | public void Log<TState>(LogLevel logLevel, EventId eventId, TState s...
class EmptyDisposable (line 499) | class EmptyDisposable : IDisposable
method Dispose (line 501) | public void Dispose()
FILE: sandbox/Benchmark/Utils/Helper.cs
class TestDoc (line 15) | [MemoryTable("TestDoc"), MessagePackObject(true)]
method TestDoc (line 23) | public TestDoc()
method TestDoc (line 28) | public TestDoc(int id, string name, string lorem)
class Helper (line 36) | public static class Helper
method GetDocs (line 38) | public static IEnumerable<BsonDocument> GetDocs(int count)
method LoremIpsum (line 51) | public static string LoremIpsum(int minWords, int maxWords,
FILE: sandbox/ConsoleApp/Program.cs
class FooItem (line 24) | public class FooItem
method TryFindByItemId (line 26) | public bool TryFindByItemId(int key, out Item result)
class Quest (line 33) | [MemoryTable("quest_master"), MessagePackObject(true)]
method Validate (line 43) | void IValidatable<Quest>.Validate(IValidator<Quest> validator)
type MyEnum (line 62) | public enum MyEnum
class Item (line 68) | [MemoryTable("item"), MessagePackObject(true)]
class MonsterTable (line 77) | public sealed partial class MonsterTable
method OnAfterConstruct (line 82) | partial void OnAfterConstruct()
class Monster (line 91) | [MemoryTable("monster"), MessagePackObject(true)]
method Monster (line 99) | public Monster(int MonsterId, string Name, int MaxHp)
class EnumKeyTable (line 107) | [MemoryTable("enumkeytable"), MessagePackObject(true)]
type Gender (line 114) | public enum Gender
class Person (line 119) | [MemoryTable("person"), MessagePackObject(true)]
method Person (line 132) | public Person()
method Person (line 136) | public Person(int PersonId, int Age, Gender Gender, string Name)
method ToString (line 144) | public override string ToString()
class ByteBufferWriter (line 154) | class ByteBufferWriter : IBufferWriter<byte>
method ByteBufferWriter (line 163) | public ByteBufferWriter()
method Advance (line 169) | public void Advance(int count)
method GetMemory (line 174) | public Memory<byte> GetMemory(int sizeHint = 0)
method GetSpan (line 199) | public Span<byte> GetSpan(int sizeHint = 0)
class Test1 (line 205) | [MemoryTable(nameof(Test1))]
class Test2 (line 212) | [MessagePackObject(false)]
class Program (line 223) | class Program
method Main (line 225) | static void Main(string[] args)
method ParseValue (line 276) | static object ParseValue(Type type, string rawValue)
class TinyCsvReader (line 347) | public class TinyCsvReader : IDisposable
method TinyCsvReader (line 354) | public TinyCsvReader(StreamReader reader)
method GetValue (line 373) | string GetValue(string line, ref int i)
method ReadValues (line 390) | public string[] ReadValues()
method ReadValuesWithHeader (line 406) | public Dictionary<string, string> ReadValuesWithHeader()
method Dispose (line 420) | public void Dispose()
FILE: sandbox/GeneratorSandbox/Program.cs
type Gender (line 46) | public enum Gender
type Person (line 55) | [MemoryTable("person"), MessagePackObject(true)]
FILE: sandbox/PerfTest2/Engines/Dictionary_Test.cs
class Dictionary_Test (line 14) | public class Dictionary_Test : ITest
method Dictionary_Test (line 24) | public Dictionary_Test(int count)
method Insert (line 31) | public void Insert()
method Bulk (line 46) | public void Bulk()
method CreateIndex (line 51) | public void CreateIndex()
method Dispose (line 56) | public void Dispose()
method Prepare (line 61) | public void Prepare()
method Query (line 66) | public void Query()
method Update (line 75) | public void Update()
class ConcurrentDictionary_Test (line 81) | public class ConcurrentDictionary_Test : ITest
method ConcurrentDictionary_Test (line 91) | public ConcurrentDictionary_Test(int count)
method Insert (line 98) | public void Insert()
method Bulk (line 113) | public void Bulk()
method CreateIndex (line 118) | public void CreateIndex()
method Dispose (line 123) | public void Dispose()
method Prepare (line 128) | public void Prepare()
method Query (line 133) | public void Query()
method Update (line 142) | public void Update()
class ImmutableDictionary_Test (line 148) | public class ImmutableDictionary_Test : ITest
method ImmutableDictionary_Test (line 158) | public ImmutableDictionary_Test(int count)
method Insert (line 165) | public void Insert()
method Bulk (line 183) | public void Bulk()
method CreateIndex (line 188) | public void CreateIndex()
method Dispose (line 193) | public void Dispose()
method Prepare (line 198) | public void Prepare()
method Query (line 203) | public void Query()
method Update (line 212) | public void Update()
FILE: sandbox/PerfTest2/Engines/ITest.cs
type ITest (line 14) | public interface ITest : IDisposable
method Prepare (line 19) | void Prepare();
method Insert (line 20) | void Insert();
method Bulk (line 21) | void Bulk();
method Update (line 22) | void Update();
method CreateIndex (line 23) | void CreateIndex();
method Query (line 24) | void Query();
FILE: sandbox/PerfTest2/Engines/LiteDB_Test.cs
class LiteDB_Test (line 14) | public class LiteDB_Test : ITest
method LiteDB_Test (line 23) | public LiteDB_Test(int count, string password, LiteDB.FileOptions opti...
method LiteDB_Test (line 33) | public LiteDB_Test(int count)
method Prepare (line 45) | public void Prepare()
method Insert (line 49) | public void Insert()
method Bulk (line 57) | public void Bulk()
method Update (line 62) | public void Update()
method CreateIndex (line 70) | public void CreateIndex()
method Query (line 75) | public void Query()
method Delete (line 83) | public void Delete()
method Drop (line 88) | public void Drop()
method Dispose (line 93) | public void Dispose()
FILE: sandbox/PerfTest2/Engines/MasterMemory_Test.cs
class MasterMemory_Test (line 12) | public class MasterMemory_Test : ITest
method MasterMemory_Test (line 22) | public MasterMemory_Test(int count)
method MakeDoc (line 29) | public IEnumerable<TestDoc> MakeDoc()
method Insert (line 44) | public void Insert()
method Bulk (line 53) | public void Bulk()
method CreateIndex (line 58) | public void CreateIndex()
method Dispose (line 63) | public void Dispose()
method Prepare (line 68) | public void Prepare()
method Query (line 73) | public void Query()
method Update (line 82) | public void Update()
FILE: sandbox/PerfTest2/Engines/SQLite_Test.cs
class SQLite_Test (line 13) | public class SQLite_Test : ITest
method SQLite_Test (line 22) | public SQLite_Test(int count, string password, bool journal, bool memo...
method Prepare (line 41) | public void Prepare()
method Insert (line 52) | public void Insert()
method Bulk (line 76) | public void Bulk()
method Update (line 99) | public void Update()
method CreateIndex (line 117) | public void CreateIndex()
method Query (line 124) | public void Query()
method Delete (line 145) | public void Delete()
method Drop (line 152) | public void Drop()
method Dispose (line 159) | public void Dispose()
FILE: sandbox/PerfTest2/Generated/DatabaseBuilder.cs
class DatabaseBuilder (line 17) | public sealed class DatabaseBuilder : DatabaseBuilderBase
method DatabaseBuilder (line 19) | public DatabaseBuilder() : this(null) { }
method DatabaseBuilder (line 20) | public DatabaseBuilder(MessagePack.IFormatterResolver resolver) : base...
method Append (line 22) | public DatabaseBuilder Append(System.Collections.Generic.IEnumerable<T...
FILE: sandbox/PerfTest2/Generated/ImmutableBuilder.cs
class ImmutableBuilder (line 17) | public sealed class ImmutableBuilder : ImmutableBuilderBase
method ImmutableBuilder (line 21) | public ImmutableBuilder(MemoryDatabase memory)
method Build (line 26) | public MemoryDatabase Build()
method ReplaceAll (line 31) | public void ReplaceAll(System.Collections.Generic.IList<TestDoc> data)
method RemoveTestDoc (line 41) | public void RemoveTestDoc(int[] keys)
method Diff (line 52) | public void Diff(TestDoc[] addOrReplaceData)
FILE: sandbox/PerfTest2/Generated/MasterMemoryResolver.cs
class MasterMemoryResolver (line 17) | public class MasterMemoryResolver : global::MessagePack.IFormatterResolver
method MasterMemoryResolver (line 21) | MasterMemoryResolver()
method GetFormatter (line 26) | public global::MessagePack.Formatters.IMessagePackFormatter<T> GetForm...
class FormatterCache (line 31) | static class FormatterCache<T>
method FormatterCache (line 35) | static FormatterCache()
class MasterMemoryResolverGetFormatterHelper (line 46) | internal static class MasterMemoryResolverGetFormatterHelper
method MasterMemoryResolverGetFormatterHelper (line 50) | static MasterMemoryResolverGetFormatterHelper()
method GetFormatter (line 58) | internal static object GetFormatter(Type t)
FILE: sandbox/PerfTest2/Generated/MemoryDatabase.cs
class MemoryDatabase (line 17) | public sealed class MemoryDatabase : MemoryDatabaseBase
method MemoryDatabase (line 21) | public MemoryDatabase(
method MemoryDatabase (line 28) | public MemoryDatabase(byte[] databaseBinary, bool internString = true,...
method Init (line 33) | protected override void Init(Dictionary<string, (int offset, int count...
method ToImmutableBuilder (line 38) | public ImmutableBuilder ToImmutableBuilder()
method ToDatabaseBuilder (line 43) | public DatabaseBuilder ToDatabaseBuilder()
FILE: sandbox/PerfTest2/Generated/Tables/TestDocTable.cs
class TestDocTable (line 16) | public sealed partial class TestDocTable : TableBase<TestDoc>
method TestDocTable (line 21) | public TestDocTable(TestDoc[] sortedData)
method FindByid (line 28) | [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerSer...
method FindClosestByid (line 45) | public TestDoc FindClosestByid(int key, bool selectLower = true)
method FindRangeByid (line 50) | public RangeView<TestDoc> FindRangeByid(int min, int max, bool ascenda...
FILE: sandbox/PerfTest2/Program.cs
class Program (line 16) | class Program
method Main (line 18) | static void Main(string[] args)
method RunTest (line 43) | static void RunTest(string name, ITest test)
FILE: sandbox/PerfTest2/Utils/Helper.cs
class TestDoc (line 15) | [MemoryTable("TestDoc"), MessagePackObject(true)]
class Helper (line 24) | static class Helper
method Run (line 26) | public static void Run(this ITest test, string name, Action action, bo...
method GetDocs (line 46) | public static IEnumerable<BsonDocument> GetDocs(int count)
method LoremIpsum (line 59) | public static string LoremIpsum(int minWords, int maxWords,
FILE: src/MasterMemory.Annotations/Attributes.cs
class MemoryTableAttribute (line 5) | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
method MemoryTableAttribute (line 10) | public MemoryTableAttribute(string tableName)
class PrimaryKeyAttribute (line 16) | [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
method PrimaryKeyAttribute (line 21) | public PrimaryKeyAttribute(int keyOrder = 0)
class SecondaryKeyAttribute (line 27) | [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
method SecondaryKeyAttribute (line 33) | public SecondaryKeyAttribute(int indexNo, int keyOrder = 0)
class NonUniqueAttribute (line 40) | [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
class StringComparisonOptionAttribute (line 46) | [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
method StringComparisonOptionAttribute (line 51) | public StringComparisonOptionAttribute(StringComparison stringComparison)
FILE: src/MasterMemory.SourceGenerator/DiagnosticDescriptors.cs
class DiagnosticReporter (line 8) | internal sealed class DiagnosticReporter : IEquatable<DiagnosticReporter>
method ReportDiagnostic (line 14) | public void ReportDiagnostic(DiagnosticDescriptor diagnosticDescriptor...
method ReportToContext (line 24) | public void ReportToContext(SourceProductionContext context)
method Equals (line 35) | public bool Equals(DiagnosticReporter other)
class DiagnosticDescriptors (line 47) | internal static class DiagnosticDescriptors
method ReportDiagnostic (line 51) | public static void ReportDiagnostic(this SourceProductionContext conte...
method Create (line 57) | public static DiagnosticDescriptor Create(int id, string message)
method Create (line 62) | public static DiagnosticDescriptor Create(int id, string title, string...
FILE: src/MasterMemory.SourceGenerator/GeneratorCore/CodeGenerator.cs
class CodeGenerator (line 9) | internal static class CodeGenerator
method CreateGenerationContext (line 12) | public static GenerationContext CreateGenerationContext(TypeDeclaratio...
method ExtractPropertyAttribute (line 73) | static (PrimaryKey, List<SecondaryKey>, PropertyDeclarationSyntax)? Ex...
method AggregatePrimaryKey (line 189) | static PrimaryKey AggregatePrimaryKey(IEnumerable<PrimaryKey> primaryK...
method AggregateSecondaryKey (line 208) | static SecondaryKey AggregateSecondaryKey(IGrouping<int, SecondaryKey>...
class Extensions (line 228) | internal static class Extensions
method ToFullStringTrim (line 230) | public static string ToFullStringTrim(this SyntaxNode node)
method ToFullStringTrim (line 235) | public static string ToFullStringTrim(this SyntaxToken token)
FILE: src/MasterMemory.SourceGenerator/GeneratorCore/DatabaseBuilderTemplate.cs
class DatabaseBuilderTemplate (line 20) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Visua...
method TransformText (line 26) | public virtual string TransformText()
class DatabaseBuilderTemplateBase (line 58) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Visua...
method Write (line 145) | public void Write(string textToAppend)
method WriteLine (line 187) | public void WriteLine(string textToAppend)
method Write (line 196) | public void Write(string format, params object[] args)
method WriteLine (line 203) | public void WriteLine(string format, params object[] args)
method Error (line 210) | public void Error(string message)
method Warning (line 219) | public void Warning(string message)
method PushIndent (line 229) | public void PushIndent(string indent)
method PopIndent (line 241) | public string PopIndent()
method ClearIndent (line 259) | public void ClearIndent()
class ToStringInstanceHelper (line 269) | public class ToStringInstanceHelper
method ToStringWithCulture (line 292) | public string ToStringWithCulture(object objectToConvert)
FILE: src/MasterMemory.SourceGenerator/GeneratorCore/GenerationContext.cs
type GenerationContext (line 9) | public record GenerationContext
type Property (line 24) | public record Property
type KeyBase (line 30) | public abstract record KeyBase
type PrimaryKey (line 205) | public record PrimaryKey : KeyBase
type SecondaryKey (line 212) | public record SecondaryKey : KeyBase
type KeyProperty (line 220) | public record KeyProperty
FILE: src/MasterMemory.SourceGenerator/GeneratorCore/ImmutableBuilderTemplate.cs
class ImmutableBuilderTemplate (line 20) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Visua...
method TransformText (line 26) | public virtual string TransformText()
class ImmutableBuilderTemplateBase (line 124) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Visua...
method Write (line 211) | public void Write(string textToAppend)
method WriteLine (line 253) | public void WriteLine(string textToAppend)
method Write (line 262) | public void Write(string format, params object[] args)
method WriteLine (line 269) | public void WriteLine(string format, params object[] args)
method Error (line 276) | public void Error(string message)
method Warning (line 285) | public void Warning(string message)
method PushIndent (line 295) | public void PushIndent(string indent)
method PopIndent (line 307) | public string PopIndent()
method ClearIndent (line 325) | public void ClearIndent()
class ToStringInstanceHelper (line 335) | public class ToStringInstanceHelper
method ToStringWithCulture (line 358) | public string ToStringWithCulture(object objectToConvert)
FILE: src/MasterMemory.SourceGenerator/GeneratorCore/MemoryDatabaseTemplate.cs
class MemoryDatabaseTemplate (line 20) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Visua...
method TransformText (line 26) | public virtual string TransformText()
class MemoryDatabaseTemplateBase (line 218) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Visua...
method Write (line 305) | public void Write(string textToAppend)
method WriteLine (line 347) | public void WriteLine(string textToAppend)
method Write (line 356) | public void Write(string format, params object[] args)
method WriteLine (line 363) | public void WriteLine(string format, params object[] args)
method Error (line 370) | public void Error(string message)
method Warning (line 379) | public void Warning(string message)
method PushIndent (line 389) | public void PushIndent(string indent)
method PopIndent (line 401) | public string PopIndent()
method ClearIndent (line 419) | public void ClearIndent()
class ToStringInstanceHelper (line 429) | public class ToStringInstanceHelper
method ToStringWithCulture (line 452) | public string ToStringWithCulture(object objectToConvert)
FILE: src/MasterMemory.SourceGenerator/GeneratorCore/MessagePackResolverTemplate.cs
class MessagePackResolverTemplate (line 20) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Visua...
method TransformText (line 26) | public virtual string TransformText()
class MessagePackResolverTemplateBase (line 100) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Visua...
method Write (line 187) | public void Write(string textToAppend)
method WriteLine (line 229) | public void WriteLine(string textToAppend)
method Write (line 238) | public void Write(string format, params object[] args)
method WriteLine (line 245) | public void WriteLine(string format, params object[] args)
method Error (line 252) | public void Error(string message)
method Warning (line 261) | public void Warning(string message)
method PushIndent (line 271) | public void PushIndent(string indent)
method PopIndent (line 283) | public string PopIndent()
method ClearIndent (line 301) | public void ClearIndent()
class ToStringInstanceHelper (line 311) | public class ToStringInstanceHelper
method ToStringWithCulture (line 334) | public string ToStringWithCulture(object objectToConvert)
FILE: src/MasterMemory.SourceGenerator/GeneratorCore/TableTemplate.cs
class TableTemplate (line 20) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Visua...
method TransformText (line 26) | public virtual string TransformText()
class TableTemplateBase (line 298) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Visua...
method Write (line 385) | public void Write(string textToAppend)
method WriteLine (line 427) | public void WriteLine(string textToAppend)
method Write (line 436) | public void Write(string format, params object[] args)
method WriteLine (line 443) | public void WriteLine(string format, params object[] args)
method Error (line 450) | public void Error(string message)
method Warning (line 459) | public void Warning(string message)
method PushIndent (line 469) | public void PushIndent(string indent)
method PopIndent (line 481) | public string PopIndent()
method ClearIndent (line 499) | public void ClearIndent()
class ToStringInstanceHelper (line 509) | public class ToStringInstanceHelper
method ToStringWithCulture (line 532) | public string ToStringWithCulture(object objectToConvert)
FILE: src/MasterMemory.SourceGenerator/GeneratorCore/Template.cs
class DatabaseBuilderTemplate (line 9) | public partial class DatabaseBuilderTemplate
class MemoryDatabaseTemplate (line 19) | public partial class MemoryDatabaseTemplate
class MetaMemoryDatabaseTemplate (line 28) | public partial class MetaMemoryDatabaseTemplate
class ImmutableBuilderTemplate (line 37) | public partial class ImmutableBuilderTemplate
class MessagePackResolverTemplate (line 46) | public partial class MessagePackResolverTemplate
class TableTemplate (line 55) | public partial class TableTemplate
FILE: src/MasterMemory.SourceGenerator/MasterMemoryGenerator.cs
class MasterMemoryGenerator (line 8) | [Generator(LanguageNames.CSharp)]
method Initialize (line 11) | public void Initialize(IncrementalGeneratorInitializationContext context)
method EmitMemoryTable (line 68) | void EmitMemoryTable(SourceProductionContext context, (((DiagnosticRep...
method Log (line 111) | static void Log(string msg) => Trace.WriteLine(msg);
method AddSource (line 113) | static string AddSource(SourceProductionContext context, string fileNa...
FILE: src/MasterMemory.SourceGenerator/MasterMemoryGeneratorOptions.cs
type MasterMemoryGeneratorOptions (line 6) | readonly record struct MasterMemoryGeneratorOptions(string? Namespace, s...
FILE: src/MasterMemory.SourceGenerator/Polyfill/System.CodeDom.cs
class CompilerError (line 9) | public class CompilerError
class CompilerErrorCollection (line 15) | public class CompilerErrorCollection
method Add (line 17) | public void Add(CompilerError error)
FILE: src/MasterMemory.SourceGenerator/Utility/EquatableArray.cs
type EquatableArray (line 6) | public readonly struct EquatableArray<T> : IEquatable<EquatableArray<T>>...
method EquatableArray (line 11) | public EquatableArray() // for collection literal []
method EquatableArray (line 16) | public EquatableArray(T[] array)
method AsSpan (line 34) | public ReadOnlySpan<T> AsSpan()
method GetEnumerator (line 39) | public ReadOnlySpan<T>.Enumerator GetEnumerator()
method GetEnumerator (line 44) | IEnumerator<T> IEnumerable<T>.GetEnumerator()
method GetEnumerator (line 49) | IEnumerator IEnumerable.GetEnumerator()
method Equals (line 54) | public bool Equals(EquatableArray<T> other)
FILE: src/MasterMemory.SourceGenerator/Utility/IgnoreEquality.cs
type IgnoreEquality (line 3) | public readonly struct IgnoreEquality<T>(T value) : IEquatable<IgnoreEqu...
method Equals (line 17) | public bool Equals(IgnoreEquality<T> other)
FILE: src/MasterMemory.Unity/Assets/Scripts/NewBehaviourScript.cs
class IsExternalInit (line 15) | internal sealed class IsExternalInit { }
class NewBehaviourScript (line 20) | public class NewBehaviourScript : MonoBehaviour
method Start (line 23) | void Start()
method Update (line 29) | void Update()
type Gender (line 35) | public enum Gender
type Person (line 42) | [MemoryTable("person"), MessagePackObject(true)]
class Initializer (line 61) | public static class Initializer
method SetupMessagePackResolver (line 63) | [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLo...
FILE: src/MasterMemory/DatabaseBuilderBase.cs
class DatabaseBuilderBase (line 11) | public abstract class DatabaseBuilderBase
method DatabaseBuilderBase (line 19) | public DatabaseBuilderBase(MessagePackSerializerOptions? options)
method DatabaseBuilderBase (line 28) | public DatabaseBuilderBase(IFormatterResolver? resolver)
method AppendCore (line 39) | protected void AppendCore<T, TKey>(IEnumerable<T> datasource, Func<T, ...
method FastSort (line 63) | static TElement[] FastSort<TElement, TKey>(IEnumerable<TElement> datas...
method Build (line 97) | public byte[] Build()
method WriteToStream (line 106) | public void WriteToStream(Stream stream)
FILE: src/MasterMemory/DatabaseBuilderBaseExtensions.cs
class DatabaseBuilderExtensions (line 7) | public static class DatabaseBuilderExtensions
method AppendDynamic (line 9) | public static void AppendDynamic(this DatabaseBuilderBase builder, Typ...
FILE: src/MasterMemory/IValidatable.cs
type IValidatable (line 7) | public interface IValidatable<TSelf>
method Validate (line 9) | void Validate(IValidator<TSelf> validator);
type IValidator (line 12) | public interface IValidator<T>
method GetTableSet (line 14) | ValidatableSet<T> GetTableSet();
method GetReferenceSet (line 15) | ReferenceSet<T, TRef> GetReferenceSet<TRef>();
method Validate (line 16) | void Validate(Expression<Func<T, bool>> predicate);
method Validate (line 17) | void Validate(Func<T, bool> predicate, string message);
method ValidateAction (line 18) | void ValidateAction(Expression<Func<bool>> predicate);
method ValidateAction (line 19) | void ValidateAction(Func<bool> predicate, string message);
method Fail (line 20) | void Fail(string message);
method CallOnce (line 21) | bool CallOnce();
FILE: src/MasterMemory/ImmutableBuilderBase.cs
class ImmutableBuilderBase (line 7) | public abstract class ImmutableBuilderBase
method CloneAndSortBy (line 9) | static protected TElement[] CloneAndSortBy<TElement, TKey>(IList<TElem...
method RemoveCore (line 23) | static protected List<TElement> RemoveCore<TElement, TKey>(TElement[] ...
method DiffCore (line 47) | static protected List<TElement> DiffCore<TElement, TKey>(TElement[] ar...
FILE: src/MasterMemory/Internal/BinarySearch.cs
class BinarySearch (line 6) | internal static class BinarySearch
method FindFirst (line 8) | public static int FindFirst<T, TKey>(T[] array, TKey key, Func<T, TKey...
method FindFirstIntKey (line 32) | public static int FindFirstIntKey<T>(T[] array, int key, Func<T, int> ...
method FindClosest (line 59) | public static int FindClosest<T, TKey>(T[] array, int lo, int hi, TKey...
method LowerBound (line 89) | public static int LowerBound<T, TKey>(T[] array, int lo, int hi, TKey ...
method UpperBound (line 118) | public static int UpperBound<T, TKey>(T[] array, int lo, int hi, TKey ...
method LowerBoundClosest (line 152) | public static int LowerBoundClosest<T, TKey>(T[] array, int lo, int hi...
method UpperBoundClosest (line 187) | public static int UpperBoundClosest<T, TKey>(T[] array, int lo, int hi...
FILE: src/MasterMemory/Internal/ByteBufferWriter.cs
class ByteBufferWriter (line 6) | internal class ByteBufferWriter : IBufferWriter<byte>
method ByteBufferWriter (line 15) | public ByteBufferWriter()
method Advance (line 21) | public void Advance(int count)
method GetMemory (line 26) | public Memory<byte> GetMemory(int sizeHint = 0)
method GetSpan (line 51) | public Span<byte> GetSpan(int sizeHint = 0)
FILE: src/MasterMemory/Internal/ExpandableArray.cs
type ExpandableArray (line 5) | internal struct ExpandableArray<TElement>
method ExpandableArray (line 10) | public ExpandableArray(object dummy)
method Add (line 16) | internal void Add(TElement item)
FILE: src/MasterMemory/Internal/HeaderFormatterResolver.cs
class HeaderFormatterResolver (line 9) | internal class HeaderFormatterResolver : IFormatterResolver
method GetFormatter (line 14) | public IMessagePackFormatter<T>? GetFormatter<T>()
class IntIntValueTupleFormatter (line 37) | internal sealed class IntIntValueTupleFormatter : IMessagePackFormatter<...
method Serialize (line 39) | public void Serialize(ref MessagePackWriter writer, (int, int) value, ...
method Deserialize (line 46) | public (int, int) Deserialize(ref MessagePackReader reader, MessagePac...
FILE: src/MasterMemory/Internal/InternStringResolver.cs
class InternStringResolver (line 8) | internal class InternStringResolver : IFormatterResolver, IMessagePackFo...
method InternStringResolver (line 12) | public InternStringResolver(IFormatterResolver innerResolver)
method GetFormatter (line 17) | public IMessagePackFormatter<T>? GetFormatter<T>()
method Deserialize (line 27) | string? IMessagePackFormatter<string?>.Deserialize(ref MessagePackRead...
method Serialize (line 38) | void IMessagePackFormatter<string?>.Serialize(ref MessagePackWriter wr...
FILE: src/MasterMemory/MemoryDatabaseBase.cs
class MemoryDatabaseBase (line 13) | public abstract class MemoryDatabaseBase
method MemoryDatabaseBase (line 15) | protected MemoryDatabaseBase()
method MemoryDatabaseBase (line 20) | public MemoryDatabaseBase(byte[] databaseBinary, bool internString = t...
method ExtractTableData (line 39) | protected static TView ExtractTableData<T, TView>(Dictionary<string, (...
method Init (line 57) | protected abstract void Init(Dictionary<string, (int offset, int count...
method GetTableInfo (line 59) | public static TableInfo[] GetTableInfo(byte[] databaseBinary, bool sto...
method ValidateTable (line 68) | protected void ValidateTable<TElement>(IReadOnlyList<TElement> table, ...
class TableInfo (line 85) | public class TableInfo
method TableInfo (line 91) | public TableInfo(string tableName, int size, byte[]? rawBinary, int of...
method DumpAsJson (line 102) | public string DumpAsJson()
method DumpAsJson (line 107) | public string DumpAsJson(MessagePackSerializerOptions options)
FILE: src/MasterMemory/Meta/Meta.cs
class MetaDatabase (line 9) | public class MetaDatabase
method MetaDatabase (line 13) | public MetaDatabase(IDictionary<string, MetaTable> tableInfos)
method GetTableInfos (line 20) | public IEnumerable<MetaTable> GetTableInfos()
method GetTableInfo (line 28) | public MetaTable? GetTableInfo(string tableName)
class MetaTable (line 36) | public class MetaTable
method MetaTable (line 44) | public MetaTable(Type dataType, Type tableType, string tableName, IRea...
method ToString (line 53) | public override string ToString()
class MetaProperty (line 59) | public class MetaProperty
method MetaProperty (line 67) | public MetaProperty(PropertyInfo? propertyInfo)
method ToString (line 72) | public override string ToString()
method ToCamelCase (line 80) | static string ToCamelCase(string s)
method ToSnakeCase (line 95) | static string ToSnakeCase(string s)
class MetaIndex (line 131) | public class MetaIndex
method MetaIndex (line 139) | public MetaIndex(IReadOnlyList<PropertyInfo> indexProperties, bool isP...
method ToString (line 147) | public override string ToString()
FILE: src/MasterMemory/RangeView.cs
type RangeView (line 7) | public readonly struct RangeView<T> : IEnumerable<T>, IReadOnlyList<T>, ...
method RangeView (line 47) | public RangeView(T[]? orderedData, int left, int right, bool ascendant)
method GetEnumerator (line 56) | public IEnumerator<T> GetEnumerator()
method GetEnumerator (line 65) | IEnumerator IEnumerable.GetEnumerator()
method Any (line 70) | public bool Any()
method IndexOf (line 75) | public int IndexOf(T item)
method Contains (line 89) | public bool Contains(T item)
method CopyTo (line 103) | public void CopyTo(T[] array, int arrayIndex)
method Insert (line 125) | void IList<T>.Insert(int index, T item)
method RemoveAt (line 130) | void IList<T>.RemoveAt(int index)
method Add (line 135) | void ICollection<T>.Add(T item)
method Clear (line 140) | void ICollection<T>.Clear()
method Remove (line 145) | bool ICollection<T>.Remove(T item)
FILE: src/MasterMemory/TableBase.cs
class TableBase (line 9) | public abstract class TableBase<TElement>
method GetRawDataUnsafe (line 17) | public TElement[] GetRawDataUnsafe() => data;
method TableBase (line 19) | public TableBase(TElement[] sortedData)
method ValidateUniqueCore (line 26) | static protected void ValidateUniqueCore<TKey>(TElement[] indexArray, ...
method CloneAndSortBy (line 41) | protected TElement[] CloneAndSortBy<TKey>(Func<TElement, TKey> indexSe...
method ThrowKeyNotFound (line 55) | static protected TElement ThrowKeyNotFound<TKey>(TKey key)
method FindUniqueCore (line 62) | static protected TElement FindUniqueCore<TKey>(TElement[] indexArray, ...
method FindUniqueCoreInt (line 80) | static protected TElement FindUniqueCoreInt(TElement[] indexArray, Fun...
method TryFindUniqueCore (line 97) | static protected bool TryFindUniqueCore<TKey>(TElement[] indexArray, F...
method TryFindUniqueCoreInt (line 112) | static protected bool TryFindUniqueCoreInt(TElement[] indexArray, Func...
method FindUniqueClosestCore (line 127) | static protected TElement? FindUniqueClosestCore<TKey>(TElement[] inde...
method FindUniqueRangeCore (line 133) | static protected RangeView<TElement> FindUniqueRangeCore<TKey>(TElemen...
method FindManyCore (line 146) | static protected RangeView<TElement> FindManyCore<TKey>(TElement[] ind...
method FindManyClosestCore (line 157) | static protected RangeView<TElement> FindManyClosestCore<TKey>(TElemen...
method FindManyRangeCore (line 167) | static protected RangeView<TElement> FindManyRangeCore<TKey>(TElement[...
FILE: src/MasterMemory/Validation/ExpressionDumper.cs
class ExpressionDumper (line 10) | internal class ExpressionDumper<T> : ExpressionVisitor
method ExpressionDumper (line 17) | public ExpressionDumper(T target, ParameterExpression param)
method VisitMember (line 24) | protected override System.Linq.Expressions.Expression VisitMember(Memb...
method DumpMemberValues (line 35) | public static string DumpMemberValues(T item, Expression<Func<T, bool>...
method VisitAndFormat (line 41) | public string VisitAndFormat(Expression expression)
class ReflectAccessor (line 47) | private class ReflectAccessor
method ReflectAccessor (line 52) | public ReflectAccessor(T target, string name)
FILE: src/MasterMemory/Validation/ExpressionParameterNameModifier.cs
class ExpressionParameterNameModifier (line 6) | public class ExpressionParameterNameModifier : ExpressionVisitor
method ExpressionParameterNameModifier (line 11) | public ExpressionParameterNameModifier(ParameterExpression modifyTarge...
method VisitParameter (line 17) | protected override Expression VisitParameter(ParameterExpression node)
class ExpressionParameterNameModifyExtensions (line 28) | public static class ExpressionParameterNameModifyExtensions
method ToThisBodyString (line 30) | public static string ToThisBodyString<T>(this Expression<Func<T, bool>...
method ToSpaceBodyString (line 37) | public static string ToSpaceBodyString<T, TProperty>(this Expression<F...
method ToNameBodyString (line 44) | public static string ToNameBodyString<T, TProperty>(this Expression<Fu...
FILE: src/MasterMemory/Validation/ITableUniqueValidate.cs
type ITableUniqueValidate (line 3) | public interface ITableUniqueValidate
method ValidateUnique (line 5) | void ValidateUnique(ValidateResult resultSet);
FILE: src/MasterMemory/Validation/ReferenceSet.cs
class ReferenceSet (line 8) | public class ReferenceSet<TElement, TReference>
method ReferenceSet (line 18) | public ReferenceSet(TElement item, IReadOnlyList<TReference> reference...
method Exists (line 27) | public void Exists<TProperty>(Expression<Func<TElement, TProperty>> el...
method Exists (line 32) | public void Exists<TProperty>(Expression<Func<TElement, TProperty>> el...
method BuildPkMessage (line 52) | string BuildPkMessage()
FILE: src/MasterMemory/Validation/ValidatableSet.Sequential.cs
class ValidatableSet (line 8) | public partial class ValidatableSet<TElement>
method Sequential (line 10) | public void Sequential(Expression<Func<TElement, SByte>> selector, boo...
method Sequential (line 16) | public void Sequential(Func<TElement, SByte> selector, string message,...
method SequentialCore (line 21) | void SequentialCore(Func<TElement, SByte> selector, Func<string> messa...
method Sequential (line 44) | public void Sequential(Expression<Func<TElement, Int16>> selector, boo...
method Sequential (line 50) | public void Sequential(Func<TElement, Int16> selector, string message,...
method SequentialCore (line 55) | void SequentialCore(Func<TElement, Int16> selector, Func<string> messa...
method Sequential (line 78) | public void Sequential(Expression<Func<TElement, Int32>> selector, boo...
method Sequential (line 84) | public void Sequential(Func<TElement, Int32> selector, string message,...
method SequentialCore (line 89) | void SequentialCore(Func<TElement, Int32> selector, Func<string> messa...
method Sequential (line 112) | public void Sequential(Expression<Func<TElement, Int64>> selector, boo...
method Sequential (line 118) | public void Sequential(Func<TElement, Int64> selector, string message,...
method SequentialCore (line 123) | void SequentialCore(Func<TElement, Int64> selector, Func<string> messa...
method Sequential (line 146) | public void Sequential(Expression<Func<TElement, Byte>> selector, bool...
method Sequential (line 152) | public void Sequential(Func<TElement, Byte> selector, string message, ...
method SequentialCore (line 157) | void SequentialCore(Func<TElement, Byte> selector, Func<string> messag...
method Sequential (line 180) | public void Sequential(Expression<Func<TElement, UInt16>> selector, bo...
method Sequential (line 186) | public void Sequential(Func<TElement, UInt16> selector, string message...
method SequentialCore (line 191) | void SequentialCore(Func<TElement, UInt16> selector, Func<string> mess...
method Sequential (line 214) | public void Sequential(Expression<Func<TElement, UInt32>> selector, bo...
method Sequential (line 220) | public void Sequential(Func<TElement, UInt32> selector, string message...
method SequentialCore (line 225) | void SequentialCore(Func<TElement, UInt32> selector, Func<string> mess...
method Sequential (line 248) | public void Sequential(Expression<Func<TElement, UInt64>> selector, bo...
method Sequential (line 254) | public void Sequential(Func<TElement, UInt64> selector, string message...
method SequentialCore (line 259) | void SequentialCore(Func<TElement, UInt64> selector, Func<string> mess...
FILE: src/MasterMemory/Validation/ValidatableSet.cs
class ValidatableSet (line 8) | public partial class ValidatableSet<TElement>
method ValidatableSet (line 15) | public ValidatableSet(IReadOnlyList<TElement> tableData, ValidateResul...
method Unique (line 25) | public void Unique<TProperty>(Expression<Func<TElement, TProperty>> se...
method Unique (line 30) | public void Unique<TProperty>(Expression<Func<TElement, TProperty>> se...
method Unique (line 45) | public void Unique<TProperty>(Func<TElement, TProperty> selector, stri...
method Unique (line 50) | public void Unique<TProperty>(Func<TElement, TProperty> selector, IEqu...
method Where (line 63) | public ValidatableSet<TElement> Where(Func<TElement, bool> predicate)
method BuildPkMessage (line 68) | string BuildPkMessage(TElement item)
FILE: src/MasterMemory/Validation/ValidateResult.cs
class ValidateResult (line 7) | public class ValidateResult
method FormatFailedResults (line 15) | public string FormatFailedResults()
method AddFail (line 25) | internal void AddFail(Type type, string message, object data)
type FaildItem (line 31) | public readonly struct FaildItem
method FaildItem (line 33) | public FaildItem(Type type, string message, object data)
FILE: src/MasterMemory/Validation/ValidationDatabase.cs
class ValidationDatabase (line 6) | public class ValidationDatabase
method ValidationDatabase (line 11) | public ValidationDatabase(IEnumerable<object> tables)
method GetTable (line 26) | internal IReadOnlyList<T> GetTable<T>()
FILE: src/MasterMemory/Validation/Validator.cs
class Validator (line 7) | internal class Validator<T> : IValidator<T>
method Validator (line 16) | public Validator(ValidationDatabase database, T item, ValidateResult r...
method CallOnce (line 26) | public bool CallOnce()
method GetTableSet (line 37) | public ValidatableSet<T> GetTableSet()
method GetReferenceSet (line 42) | public ReferenceSet<T, TRef> GetReferenceSet<TRef>()
method Validate (line 48) | public void Validate(Expression<Func<T, bool>> predicate)
method Validate (line 58) | public void Validate(Func<T, bool> predicate, string message)
method ValidateAction (line 66) | public void ValidateAction(Expression<Func<bool>> predicate)
method ValidateAction (line 75) | public void ValidateAction(Func<bool> predicate, string message)
method Fail (line 83) | public void Fail(string message)
method BuildPkMessage (line 88) | string BuildPkMessage()
FILE: src/MasterMemory/_MessagePackResolver.cs
class _MessagePackResolver (line 7) | [MessagePack.GeneratedMessagePackResolver]
FILE: tests/MasterMemory.SourceGenerator.Tests/AssemblyAtrributeTest.cs
class AssemblyAtrributeTest (line 3) | public class AssemblyAtrributeTest(ITestOutputHelper outputHelper) : Tes...
method NoGeneratorOptions (line 5) | [Fact]
method FullOptions (line 28) | [Fact]
FILE: tests/MasterMemory.SourceGenerator.Tests/DiagnosticsTest.cs
class DiagnosticsTest (line 9) | public class DiagnosticsTest(ITestOutputHelper outputHelper) : TestBase(...
method RequirePrimaryKey (line 11) | [Fact]
method DuplicateSecondaryKey (line 24) | [Fact]
FILE: tests/MasterMemory.SourceGenerator.Tests/GenerateTest.cs
class GenerateTest (line 10) | public class GenerateTest(ITestOutputHelper outputHelper) : TestBase(out...
method GenerateClass (line 12) | [Fact]
method GenerateRecord (line 25) | [Fact]
FILE: tests/MasterMemory.SourceGenerator.Tests/IncrementalGeneratorTest.cs
class IncrementalGeneratorTest (line 3) | public class IncrementalGeneratorTest
method VerifySourceOutputReasonIsCached (line 5) | void VerifySourceOutputReasonIsCached((string Key, string Reasons)[] r...
method VerifySourceOutputReasonIsNotCached (line 11) | void VerifySourceOutputReasonIsNotCached((string Key, string Reasons)[...
method CheckReasons (line 17) | [Fact]
FILE: tests/MasterMemory.SourceGenerator.Tests/TestBase.cs
class TestBase (line 3) | public abstract class TestBase(ITestOutputHelper testoutputHelper)
method WriteLine (line 7) | protected void WriteLine(string message)
FILE: tests/MasterMemory.SourceGenerator.Tests/Utility/CSharpGeneratorRunner.cs
class CSharpGeneratorRunner (line 10) | public static class CSharpGeneratorRunner
method InitializeCompilation (line 14) | [ModuleInitializer]
method RunGenerator (line 45) | public static (Compilation, ImmutableArray<Diagnostic>) RunGenerator([...
method CompileAndExecute (line 66) | public static (Compilation, ImmutableArray<Diagnostic>, string) Compil...
method GetIncrementalGeneratorTrackedStepsReasons (line 101) | public static (string Key, string Reasons)[][] GetIncrementalGenerator...
FILE: tests/MasterMemory.SourceGenerator.Tests/Utility/CodeGeneratorHelper.cs
class CodeGeneratorHelper (line 5) | public class CodeGeneratorHelper(ITestOutputHelper output, string idPrefix)
method Ok (line 9) | public void Ok([StringSyntax("C#-test")] string code, [CallerArgumentE...
method GenerateCode (line 23) | public Dictionary<string, string> GenerateCode([StringSyntax("C#-test"...
method Verify (line 45) | public void Verify(int id, [StringSyntax("C#-test")] string code, stri...
method Verify (line 63) | public (string, string)[] Verify([StringSyntax("C#-test")] string code...
method Execute (line 74) | public void Execute([StringSyntax("C#-test")] string code, string args...
method Error (line 88) | public string Error([StringSyntax("C#-test")] string code, string args...
method GetLocationText (line 102) | string GetLocationText(Diagnostic diagnostic, IEnumerable<SyntaxTree> ...
method OutputGeneratedCode (line 121) | void OutputGeneratedCode(Compilation compilation)
FILE: tests/MasterMemory.Tests/BinarySearchTest.cs
class BinarySearchTest (line 13) | public class BinarySearchTest
method BinarySearchTest (line 15) | public BinarySearchTest()
method Find (line 20) | [Fact]
method Closest (line 67) | [Fact]
FILE: tests/MasterMemory.Tests/DatabaseTest.cs
class DatabaseTest (line 13) | public class DatabaseTest
method DatabaseTest (line 15) | public DatabaseTest()
method CreateData (line 20) | Sample[] CreateData()
method SingleDb (line 40) | [Fact]
method All (line 54) | [Fact]
method Ranges (line 68) | [Fact]
method EmptyAll (line 83) | [Fact]
method WithNull (line 106) | [Fact]
FILE: tests/MasterMemory.Tests/IssueTest.cs
class IssueTest (line 10) | public class IssueTest
method CreateData (line 31) | Sample[] CreateData()
method Issue57 (line 51) | [Fact]
FILE: tests/MasterMemory.Tests/MemoryKeyTest.cs
class MemoryKeyMemoryTest (line 10) | public class MemoryKeyMemoryTest
method MemoryKeyMemoryTest (line 12) | public MemoryKeyMemoryTest()
method CreateData (line 17) | Sample[] CreateData()
method CreateTable (line 37) | SampleTable CreateTable()
method Unique (line 42) | [Fact]
method Range (line 59) | [Fact]
FILE: tests/MasterMemory.Tests/MemoryTest.cs
class MemoryTest (line 9) | public class MemoryTest
method MemoryTest (line 11) | public MemoryTest()
method CreateData (line 16) | Sample[] CreateData()
method CreateTable (line 36) | SampleTable CreateTable(Sample[] data)
method Count (line 41) | [Fact]
method Find (line 50) | [Fact]
method MultiKeyFind (line 66) | [Fact]
method FindClosest (line 84) | [Fact]
method FindClosestMultiKey (line 149) | [Fact]
method FindMany (line 169) | [Fact]
method FindManyMultiKey (line 178) | [Fact]
FILE: tests/MasterMemory.Tests/MessagePackResolver.cs
class MessagePackResolver (line 6) | [CompositeResolver(typeof(MasterMemoryResolver), typeof(StandardResolver))]
FILE: tests/MasterMemory.Tests/MetaTest.cs
class MetaTest (line 9) | public class MetaTest
method Meta (line 11) | [Fact]
FILE: tests/MasterMemory.Tests/RangeViewTest.cs
class RangeViewTest (line 9) | public class RangeViewTest
method Range (line 11) | [Fact]
FILE: tests/MasterMemory.Tests/TestStructures/PersonModel.cs
class PersonModel (line 10) | [MemoryTable("people"), MessagePackObject(true)]
FILE: tests/MasterMemory.Tests/TestStructures/QuestMaster.cs
class QuestMaster (line 9) | [MemoryTable("quest_master"), MessagePackObject(true)]
method Validate (line 18) | public void Validate(IValidator<QuestMaster> validator)
class ItemMaster (line 38) | [MemoryTable("item_master"), MessagePackObject(true)]
method Validate (line 44) | public void Validate(IValidator<ItemMaster> validator)
class QuestMasterEmptyValidate (line 49) | [MemoryTable("quest_master_empty"), MessagePackObject(true)]
class ItemMasterEmptyValidate (line 59) | [MemoryTable("item_master_empty"), MessagePackObject(true)]
class SequentialCheckMaster (line 66) | [MemoryTable("sequantial_master"), MessagePackObject(true)]
method Validate (line 73) | public void Validate(IValidator<SequentialCheckMaster> validator)
class SingleMaster (line 85) | [MemoryTable("single_master"), MessagePackObject(true)]
method Validate (line 94) | public void Validate(IValidator<SingleMaster> validator)
class Fail (line 104) | [MemoryTable("fail"), MessagePackObject(true)]
method Validate (line 110) | public void Validate(IValidator<Fail> validator)
FILE: tests/MasterMemory.Tests/TestStructures/Sample.cs
class Sample (line 6) | [MemoryTable("s_a_m_p_l_e"), MessagePackObject(true)]
method ToString (line 37) | public override string ToString()
method Sample (line 42) | public Sample()
method Sample (line 47) | public Sample(int Id, int Age, string FirstName, string LastName)
FILE: tests/MasterMemory.Tests/TestStructures/SkillMaster.cs
class SkillMaster (line 6) | [MemoryTable("skillmaster"), MessagePackObject(true)]
method SkillMaster (line 17) | public SkillMaster()
method SkillMaster (line 22) | public SkillMaster(int SkillId, int SkillLevel, int AttackPower, strin...
FILE: tests/MasterMemory.Tests/TestStructures/TestMaster.cs
class TestMaster (line 8) | [MessagePackObject(true)]
method TestMaster (line 16) | public TestMaster(int TestID, int Value)
FILE: tests/MasterMemory.Tests/TestStructures/UserLevel.cs
class UserLevel (line 5) | [MemoryTable("UserLevel"), MessagePackObject(true)]
method UserLevel (line 13) | public UserLevel()
method UserLevel (line 18) | public UserLevel(int Level, int Exp)
FILE: tests/MasterMemory.Tests/ValidatorTest.cs
class ValidatorTest (line 11) | public class ValidatorTest
method ValidatorTest (line 16) | public ValidatorTest()
method ValidatorTest (line 22) | public ValidatorTest(Xunit.Abstractions.ITestOutputHelper output)
method CreateDatabase (line 29) | MemoryDatabase CreateDatabase(Fail[] data1)
method CreateDatabase (line 39) | MemoryDatabase CreateDatabase(SingleMaster[] data1)
method CreateDatabase (line 49) | MemoryDatabase CreateDatabase(SequentialCheckMaster[] data1)
method CreateDatabase (line 59) | MemoryDatabase CreateDatabase(QuestMaster[] data1, ItemMaster[] data2)
method CreateDatabase (line 70) | MemoryDatabase CreateDatabase(QuestMasterEmptyValidate[] data1, ItemMa...
method Empty (line 81) | [Fact]
method PKUnique (line 94) | [Fact]
method Exists (line 141) | [Fact]
method Unique (line 164) | [Fact]
method Sequential (line 185) | [Fact]
method CallOnce (line 215) | [Fact]
method Validate (line 231) | [Fact]
method ValidateAction (line 254) | [Fact]
method Fail (line 279) | [Fact]
Condensed preview — 142 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (489K chars).
[
{
"path": ".editorconfig",
"chars": 1127,
"preview": "# top-most EditorConfig file\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_style = space\nindent_size = 2\nins"
},
{
"path": ".github/dependabot.yaml",
"chars": 726,
"preview": "# ref: https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-"
},
{
"path": ".github/workflows/build-debug.yaml",
"chars": 630,
"preview": "name: Build-Debug\n\non:\n push:\n branches:\n - \"master\"\n pull_request:\n branches:\n - \"master\"\n\njobs:\n bu"
},
{
"path": ".github/workflows/build-release.yaml",
"chars": 1315,
"preview": "name: Build-Release\n\non:\n workflow_dispatch:\n inputs:\n tag:\n description: \"tag: git tag you want create."
},
{
"path": ".github/workflows/prevent-github-change.yaml",
"chars": 245,
"preview": "name: Prevent github change\non:\n pull_request:\n paths:\n - \".github/**/*.yaml\"\n - \".github/**/*.yml\"\n\njobs:"
},
{
"path": ".github/workflows/stale.yaml",
"chars": 256,
"preview": "name: \"Close stale issues\"\n\non:\n workflow_dispatch:\n schedule:\n - cron: \"0 0 * * *\"\n\njobs:\n stale:\n permissions"
},
{
"path": ".github/workflows/toc.yaml",
"chars": 256,
"preview": "name: TOC Generator\n\non:\n push:\n paths:\n - 'README.md'\n\njobs:\n toc:\n permissions:\n contents: write\n "
},
{
"path": ".gitignore",
"chars": 2327,
"preview": "# Build Folders (you can keep bin if you'd like, to store dlls and pdbs)\n[Bb]in/\n[Oo]bj/\n\n# mstest test results\nTestResu"
},
{
"path": "Directory.Build.props",
"chars": 1116,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbui"
},
{
"path": "LICENSE",
"chars": 1088,
"preview": "MIT License\n\nCopyright (c) 2019 Yoshifumi Kawai / Cysharp, Inc.\n\nPermission is hereby granted, free of charge, to any pe"
},
{
"path": "MasterMemory.sln",
"chars": 6367,
"preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.12.355"
},
{
"path": "README.md",
"chars": 30653,
"preview": "[](https://github.com/Cysharp/"
},
{
"path": "sandbox/Benchmark/Benchmark.csproj",
"chars": 1108,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<OutputType>Exe</OutputType>\n\t\t<TargetFramework>net6.0</TargetFra"
},
{
"path": "sandbox/Benchmark/Program.cs",
"chars": 14406,
"preview": "#pragma warning disable\n\nusing BenchmarkDotNet.Attributes;\nusing System.Linq;\nusing BenchmarkDotNet.Configs;\nusing Benc"
},
{
"path": "sandbox/Benchmark/Utils/Helper.cs",
"chars": 2352,
"preview": "#pragma warning disable\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nu"
},
{
"path": "sandbox/ConsoleApp/ConsoleApp.csproj",
"chars": 910,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<OutputType>Exe</OutputType>\n\t\t<TargetFramework>net9.0</TargetFram"
},
{
"path": "sandbox/ConsoleApp/Program.cs",
"chars": 12907,
"preview": "#pragma warning disable CS8618\n#pragma warning disable CS8602\n#pragma warning disable CS8603\n\nusing MasterMemory;\nusing"
},
{
"path": "sandbox/GeneratorSandbox/GeneratorSandbox.csproj",
"chars": 984,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<OutputType>Exe</OutputType>\n\t\t<TargetFramework>net9.0</TargetFra"
},
{
"path": "sandbox/GeneratorSandbox/Program.cs",
"chars": 2601,
"preview": "using MasterMemory;\nusing MessagePack;\nusing GeneratorSandbox;\nusing System.Runtime.CompilerServices;\n\n//[assembly: Mas"
},
{
"path": "sandbox/PerfTest2/Engines/Dictionary_Test.cs",
"chars": 4607,
"preview": "#pragma warning disable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing Syst"
},
{
"path": "sandbox/PerfTest2/Engines/ITest.cs",
"chars": 551,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Data.SQLite;\nusing System.Diagnostics;\n"
},
{
"path": "sandbox/PerfTest2/Engines/LiteDB_Test.cs",
"chars": 2331,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Data.SQLite;\nusing System.Diagnostics;\n"
},
{
"path": "sandbox/PerfTest2/Engines/MasterMemory_Test.cs",
"chars": 1822,
"preview": "#pragma warning disable\nusing MasterMemory;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing Syst"
},
{
"path": "sandbox/PerfTest2/Engines/RavenDB_Test.cs",
"chars": 3269,
"preview": "//using Raven.Client;\n//using Raven.Client.Embedded;\n//using Raven.Client.Indexes;\n//using System;\n//using System.Colle"
},
{
"path": "sandbox/PerfTest2/Engines/SQLite_Test.cs",
"chars": 5199,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Data.SQLite;\nusing System.Diagnostics;\n"
},
{
"path": "sandbox/PerfTest2/Generated/DatabaseBuilder.cs",
"chars": 780,
"preview": "// <auto-generated />\nusing LiteDB;\nusing MasterMemory;\nusing MessagePack;\nusing System.Collections.Generic;\nusing Syste"
},
{
"path": "sandbox/PerfTest2/Generated/ImmutableBuilder.cs",
"chars": 1913,
"preview": "// <auto-generated />\nusing LiteDB;\nusing MasterMemory;\nusing MessagePack;\nusing System.Collections.Generic;\nusing Syste"
},
{
"path": "sandbox/PerfTest2/Generated/MasterMemoryResolver.cs",
"chars": 1940,
"preview": "// <auto-generated />\nusing LiteDB;\nusing MasterMemory;\nusing MessagePack;\nusing System.Collections.Generic;\nusing Syste"
},
{
"path": "sandbox/PerfTest2/Generated/MemoryDatabase.cs",
"chars": 1585,
"preview": "// <auto-generated />\nusing LiteDB;\nusing MasterMemory;\nusing MessagePack;\nusing System.Collections.Generic;\nusing Syste"
},
{
"path": "sandbox/PerfTest2/Generated/Tables/TestDocTable.cs",
"chars": 1730,
"preview": "// <auto-generated />\nusing LiteDB;\nusing MasterMemory;\nusing MessagePack;\nusing System.Collections.Generic;\nusing Syste"
},
{
"path": "sandbox/PerfTest2/PerfTest2.csproj",
"chars": 684,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<OutputType>Exe</OutputType>\n\t\t<TargetFramework>net9.0</TargetFram"
},
{
"path": "sandbox/PerfTest2/Program.cs",
"chars": 2626,
"preview": "#pragma warning disable\nusing System;\nusing System.Collections.Generic;\nusing System.Data.SQLite;\nusing System.Diagnost"
},
{
"path": "sandbox/PerfTest2/Utils/Helper.cs",
"chars": 2827,
"preview": "#pragma warning disable\nusing System;\nusing System.Collections.Generic;\nusing System.Data.SQLite;\nusing System.Diagnost"
},
{
"path": "src/MasterMemory/DatabaseBuilderBase.cs",
"chars": 4197,
"preview": "using MasterMemory.Internal;\nusing MessagePack;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing "
},
{
"path": "src/MasterMemory/DatabaseBuilderBaseExtensions.cs",
"chars": 1050,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace MasterMemory\n{\n public static class Da"
},
{
"path": "src/MasterMemory/IValidatable.cs",
"chars": 667,
"preview": "using MasterMemory.Validation;\nusing System;\nusing System.Linq.Expressions;\n\nnamespace MasterMemory\n{\n public interf"
},
{
"path": "src/MasterMemory/ImmutableBuilderBase.cs",
"chars": 2627,
"preview": "using MasterMemory.Internal;\nusing System;\nusing System.Collections.Generic;\n\nnamespace MasterMemory\n{\n public abstr"
},
{
"path": "src/MasterMemory/Internal/BinarySearch.cs",
"chars": 6305,
"preview": "using System;\nusing System.Collections.Generic;\n\nnamespace MasterMemory.Internal\n{\n internal static class BinarySear"
},
{
"path": "src/MasterMemory/Internal/ByteBufferWriter.cs",
"chars": 1436,
"preview": "using System;\nusing System.Buffers;\n\nnamespace MasterMemory\n{\n internal class ByteBufferWriter : IBufferWriter<byte>"
},
{
"path": "src/MasterMemory/Internal/ExpandableArray.cs",
"chars": 663,
"preview": "using System;\n\nnamespace MasterMemory.Internal\n{\n internal struct ExpandableArray<TElement>\n {\n internal T"
},
{
"path": "src/MasterMemory/Internal/HeaderFormatterResolver.cs",
"chars": 2248,
"preview": "using MessagePack;\nusing MessagePack.Formatters;\nusing System;\nusing System.Collections.Generic;\n\nnamespace MasterMemor"
},
{
"path": "src/MasterMemory/Internal/InternStringResolver.cs",
"chars": 1241,
"preview": "using MessagePack;\nusing MessagePack.Formatters;\nusing System;\n\nnamespace MasterMemory.Internal\n{\n#pragma warning disab"
},
{
"path": "src/MasterMemory/MasterMemory.csproj",
"chars": 2437,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>netstandard2.0</TargetFramework>\n\t\t<RootNamespac"
},
{
"path": "src/MasterMemory/MemoryDatabaseBase.cs",
"chars": 4645,
"preview": "using MasterMemory.Internal;\nusing MessagePack;\nusing MessagePack.Formatters;\nusing System;\nusing System.Collections.Ge"
},
{
"path": "src/MasterMemory/Meta/Meta.cs",
"chars": 4279,
"preview": "using System;\nusing System.Linq;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Text;\n\nnamespa"
},
{
"path": "src/MasterMemory/RangeView.cs",
"chars": 3996,
"preview": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\n\nnamespace MasterMemory\n{\n public readonly"
},
{
"path": "src/MasterMemory/TableBase.cs",
"chars": 7526,
"preview": "using MasterMemory.Internal;\nusing MasterMemory.Validation;\nusing System;\nusing System.Collections.Generic;\nusing Syste"
},
{
"path": "src/MasterMemory/Validation/ExpressionDumper.cs",
"chars": 2583,
"preview": "using System;\nusing System.Linq;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\nusing System.Reflecti"
},
{
"path": "src/MasterMemory/Validation/ExpressionParameterNameModifier.cs",
"chars": 2095,
"preview": "using System;\nusing System.Linq.Expressions;\n\nnamespace MasterMemory.Validation\n{\n public class ExpressionParameterN"
},
{
"path": "src/MasterMemory/Validation/ITableUniqueValidate.cs",
"chars": 148,
"preview": "namespace MasterMemory.Validation\n{\n public interface ITableUniqueValidate\n {\n void ValidateUnique(Validat"
},
{
"path": "src/MasterMemory/Validation/ReferenceSet.cs",
"chars": 2230,
"preview": "using System;\nusing System.Linq;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\n\nnamespace MasterMemo"
},
{
"path": "src/MasterMemory/Validation/ValidatableSet.Sequential.cs",
"chars": 9854,
"preview": " \nusing System;\nusing System.Linq;\nusing System.Linq.Expressions;\n\nnamespace MasterMemory.Validation\n{\n public parti"
},
{
"path": "src/MasterMemory/Validation/ValidatableSet.Sequential.tt",
"chars": 2038,
"preview": "<#@ template debug=\"true\" hostSpecific=\"false\" #>\n<#@ output extension=\".cs\" #>\n<#@ Assembly Name=\"System.Core\" #>\n<#@ "
},
{
"path": "src/MasterMemory/Validation/ValidatableSet.cs",
"chars": 2628,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\n\nnamespace MasterMemo"
},
{
"path": "src/MasterMemory/Validation/ValidateResult.cs",
"chars": 1096,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace MasterMemory.Validation\n{\n public clas"
},
{
"path": "src/MasterMemory/Validation/ValidationDatabase.cs",
"chars": 1109,
"preview": "using System;\nusing System.Collections.Generic;\n\nnamespace MasterMemory.Validation\n{\n public class ValidationDatabas"
},
{
"path": "src/MasterMemory/Validation/Validator.cs",
"chars": 3044,
"preview": "using System;\nusing System.Linq.Expressions;\nusing System.Runtime.CompilerServices;\n\nnamespace MasterMemory.Validation\n"
},
{
"path": "src/MasterMemory/_InternalVisibleTo.cs",
"chars": 93,
"preview": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"MasterMemory.Tests\")]"
},
{
"path": "src/MasterMemory/_MessagePackResolver.cs",
"chars": 184,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace MasterMemory;\n\n[MessagePack.GeneratedMess"
},
{
"path": "src/MasterMemory.Annotations/Attributes.cs",
"chars": 1472,
"preview": "using System;\n\nnamespace MasterMemory\n{\n [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n public "
},
{
"path": "src/MasterMemory.Annotations/MasterMemory.Annotations.csproj",
"chars": 622,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>netstandard2.0</TargetFramework>\n\t\t<LangVersion>"
},
{
"path": "src/MasterMemory.SourceGenerator/DiagnosticDescriptors.cs",
"chars": 2588,
"preview": "using Microsoft.CodeAnalysis;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace MasterMemor"
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/CodeGenerator.cs",
"chars": 10003,
"preview": "#nullable disable\n\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSha"
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/DatabaseBuilderTemplate.cs",
"chars": 13022,
"preview": "// ------------------------------------------------------------------------------\n// <auto-generated>\n// This code "
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/DatabaseBuilderTemplate.tt",
"chars": 920,
"preview": "<#@ template debug=\"false\" hostspecific=\"false\" linePragmas=\"false\" language=\"C#\" #>\n<#@ assembly name=\"System.Core\" #>"
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/GenerationContext.cs",
"chars": 6951,
"preview": "#nullable disable\n\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System.Linq;\n\nnamespace MasterMemory.GeneratorCore"
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/ImmutableBuilderTemplate.cs",
"chars": 17806,
"preview": "// ------------------------------------------------------------------------------\n// <auto-generated>\n// This code "
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/ImmutableBuilderTemplate.tt",
"chars": 3175,
"preview": "<#@ template debug=\"false\" hostspecific=\"false\" linePragmas=\"false\" language=\"C#\" #>\n<#@ assembly name=\"System.Core\" #>"
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/MemoryDatabaseTemplate.cs",
"chars": 21117,
"preview": "// ------------------------------------------------------------------------------\n// <auto-generated>\n// This code "
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/MemoryDatabaseTemplate.tt",
"chars": 5654,
"preview": "<#@ template debug=\"false\" hostspecific=\"false\" linePragmas=\"false\" language=\"C#\" #>\n<#@ assembly name=\"System.Core\" #>"
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/MessagePackResolverTemplate.cs",
"chars": 14918,
"preview": "// ------------------------------------------------------------------------------\n// <auto-generated>\n// This code "
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/MessagePackResolverTemplate.tt",
"chars": 2229,
"preview": "<#@ template debug=\"false\" hostspecific=\"false\" linePragmas=\"false\" language=\"C#\" #>\n<#@ assembly name=\"System.Core\" #>"
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/TableTemplate.cs",
"chars": 28563,
"preview": "// ------------------------------------------------------------------------------\n// <auto-generated>\n// This code "
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/TableTemplate.tt",
"chars": 7969,
"preview": "<#@ template debug=\"false\" hostspecific=\"false\" linePragmas=\"false\" language=\"C#\" #>\n<#@ assembly name=\"System.Core\" #>"
},
{
"path": "src/MasterMemory.SourceGenerator/GeneratorCore/Template.cs",
"chars": 2165,
"preview": "#nullable disable\n\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace MasterMemory.Generator"
},
{
"path": "src/MasterMemory.SourceGenerator/MasterMemory.SourceGenerator.csproj",
"chars": 2859,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>netstandard2.0</TargetFramework>\n\t\t<LangVersion>"
},
{
"path": "src/MasterMemory.SourceGenerator/MasterMemoryGenerator.cs",
"chars": 6231,
"preview": "using MasterMemory.GeneratorCore;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Syste"
},
{
"path": "src/MasterMemory.SourceGenerator/MasterMemoryGeneratorOptions.cs",
"chars": 1435,
"preview": "using Microsoft.CodeAnalysis;\n\n\nnamespace MasterMemory.SourceGenerator;\n\nreadonly record struct MasterMemoryGeneratorOp"
},
{
"path": "src/MasterMemory.SourceGenerator/Polyfill/System.CodeDom.cs",
"chars": 329,
"preview": "#nullable disable\n\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace System.CodeDom.Compile"
},
{
"path": "src/MasterMemory.SourceGenerator/Properties/launchSettings.json",
"chars": 177,
"preview": "{\n \"profiles\": {\n \"Profile 1\": {\n \"commandName\": \"DebugRoslynComponent\",\n \"targetProject\": \"..\\\\..\\\\sandbo"
},
{
"path": "src/MasterMemory.SourceGenerator/Utility/EquatableArray.cs",
"chars": 1248,
"preview": "using System.Collections;\nusing System.Runtime.CompilerServices;\n\nnamespace MasterMemory;\n\npublic readonly struct Equat"
},
{
"path": "src/MasterMemory.SourceGenerator/Utility/IgnoreEquality.cs",
"chars": 506,
"preview": "namespace MasterMemory;\n\npublic readonly struct IgnoreEquality<T>(T value) : IEquatable<IgnoreEquality<T>>\n{\n public"
},
{
"path": "src/MasterMemory.Unity/Assets/NuGet.config",
"chars": 630,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n <packageSources>\n <clear />\n <add key=\"nuget.org\" value=\""
},
{
"path": "src/MasterMemory.Unity/Assets/NuGet.config.meta",
"chars": 652,
"preview": "fileFormatVersion: 2\nguid: e5322b2ac44bca4478137f3076edc3bb\nlabels:\n- NuGetForUnity\nPluginImporter:\n externalObjects: {"
},
{
"path": "src/MasterMemory.Unity/Assets/Packages.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: 26358cf27391727439065c2117eb2e52\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "src/MasterMemory.Unity/Assets/Scenes/Main.unity",
"chars": 6254,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!29 &1\nOcclusionCullingSettings:\n m_ObjectHideFlags: 0\n serializedVersi"
},
{
"path": "src/MasterMemory.Unity/Assets/Scenes/Main.unity.meta",
"chars": 155,
"preview": "fileFormatVersion: 2\nguid: d5ed035d1a1185e43a6e9d45e3d68f1f\nDefaultImporter:\n externalObjects: {}\n userData: \n assetB"
},
{
"path": "src/MasterMemory.Unity/Assets/Scenes.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: 3e4672a57ce755a44805bc58b4ddea29\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "src/MasterMemory.Unity/Assets/Scripts/NewBehaviourScript.cs",
"chars": 1902,
"preview": "using MasterMemory;\nusing MessagePack;\nusing MessagePack.Resolvers;\nusing System;\nusing System.Collections;\nusing System"
},
{
"path": "src/MasterMemory.Unity/Assets/Scripts/NewBehaviourScript.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: a7e2d905f1c43ee42914ee6de131c41e\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "src/MasterMemory.Unity/Assets/Scripts.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: dfc2745c192a6764a8f038393ed2455c\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "src/MasterMemory.Unity/Assets/packages.config",
"chars": 449,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n <package id=\"MessagePack\" version=\"3.1.0\" manuallyInstalled=\"true\" "
},
{
"path": "src/MasterMemory.Unity/Assets/packages.config.meta",
"chars": 435,
"preview": "fileFormatVersion: 2\nguid: 44858e3667fc6e44c8fc19fd02574910\nlabels:\n- NuGetForUnity\nPluginImporter:\n externalObjects: {"
},
{
"path": "src/MasterMemory.Unity/Packages/manifest.json",
"chars": 656,
"preview": "{\n \"dependencies\": {\n \"com.cysharp.runtimeunittesttoolkit\": \"https://github.com/Cysharp/RuntimeUnitTestToolkit.git?p"
},
{
"path": "src/MasterMemory.Unity/Packages/packages-lock.json",
"chars": 3307,
"preview": "{\n \"dependencies\": {\n \"com.cysharp.runtimeunittesttoolkit\": {\n \"version\": \"https://github.com/Cysharp/RuntimeUn"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/AudioManager.asset",
"chars": 360,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!11 &1\nAudioManager:\n m_ObjectHideFlags: 0\n m_Volume: 1\n Rolloff Scale"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/ClusterInputManager.asset",
"chars": 114,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!236 &1\nClusterInputManager:\n m_ObjectHideFlags: 0\n m_Inputs: []\n"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/DynamicsManager.asset",
"chars": 1075,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!55 &1\nPhysicsManager:\n m_ObjectHideFlags: 0\n serializedVersion: 7\n m_"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/EditorBuildSettings.asset",
"chars": 257,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!1045 &1\nEditorBuildSettings:\n m_ObjectHideFlags: 0\n serializedVersion:"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/EditorSettings.asset",
"chars": 622,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!159 &1\nEditorSettings:\n m_ObjectHideFlags: 0\n serializedVersion: 7\n m"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/GraphicsSettings.asset",
"chars": 2087,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!30 &1\nGraphicsSettings:\n m_ObjectHideFlags: 0\n serializedVersion: 12\n "
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/InputManager.asset",
"chars": 5793,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!13 &1\nInputManager:\n m_ObjectHideFlags: 0\n serializedVersion: 2\n m_Ax"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/MemorySettings.asset",
"chars": 1192,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!387306366 &1\nMemorySettings:\n m_ObjectHideFlags: 0\n m_EditorMemorySett"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/NavMeshAreas.asset",
"chars": 1308,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!126 &1\nNavMeshProjectSettings:\n m_ObjectHideFlags: 0\n serializedVersio"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/NetworkManager.asset",
"chars": 151,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!149 &1\nNetworkManager:\n m_ObjectHideFlags: 0\n m_DebugLevel: 0\n m_Send"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/PackageManagerSettings.asset",
"chars": 952,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!114 &1\nMonoBehaviour:\n m_ObjectHideFlags: 53\n m_CorrespondingSourceObj"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/Physics2DSettings.asset",
"chars": 2028,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!19 &1\nPhysics2DSettings:\n m_ObjectHideFlags: 0\n serializedVersion: 4\n "
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/PresetManager.asset",
"chars": 120,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!1386491679 &1\nPresetManager:\n m_ObjectHideFlags: 0\n m_DefaultList: []\n"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/ProjectSettings.asset",
"chars": 21057,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!129 &1\nPlayerSettings:\n m_ObjectHideFlags: 0\n serializedVersion: 26\n "
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/ProjectVersion.txt",
"chars": 85,
"preview": "m_EditorVersion: 2022.3.12f1\nm_EditorVersionWithRevision: 2022.3.12f1 (4fe6e059c7ef)\n"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/QualitySettings.asset",
"chars": 4852,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!47 &1\nQualitySettings:\n m_ObjectHideFlags: 0\n serializedVersion: 5\n m"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/SceneTemplateSettings.json",
"chars": 3534,
"preview": "{\n \"templatePinStates\": [],\n \"dependencyTypeInfos\": [\n {\n \"userAdded\": false,\n \"type\""
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/TagManager.asset",
"chars": 378,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!78 &1\nTagManager:\n serializedVersion: 2\n tags: []\n layers:\n - Defaul"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/TimeManager.asset",
"chars": 195,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!5 &1\nTimeManager:\n m_ObjectHideFlags: 0\n Fixed Timestep: 0.02\n Maximu"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/UnityConnectSettings.asset",
"chars": 943,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!310 &1\nUnityConnectSettings:\n m_ObjectHideFlags: 0\n serializedVersion:"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/VFXManager.asset",
"chars": 157,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!937362698 &1\nVFXManager:\n m_ObjectHideFlags: 0\n m_IndirectShader: {fil"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/VersionControlSettings.asset",
"chars": 188,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!890905787 &1\nVersionControlSettings:\n m_ObjectHideFlags: 0\n m_Mode: Vi"
},
{
"path": "src/MasterMemory.Unity/ProjectSettings/XRSettings.asset",
"chars": 158,
"preview": "{\n \"m_SettingKeys\": [\n \"VR Device Disabled\",\n \"VR Device User Alert\"\n ],\n \"m_SettingValues\": [\n "
},
{
"path": "tests/MasterMemory.SourceGenerator.Tests/AssemblyAtrributeTest.cs",
"chars": 1475,
"preview": "namespace MasterMemory.SourceGenerator.Tests;\n\npublic class AssemblyAtrributeTest(ITestOutputHelper outputHelper) : Tes"
},
{
"path": "tests/MasterMemory.SourceGenerator.Tests/DiagnosticsTest.cs",
"chars": 758,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nna"
},
{
"path": "tests/MasterMemory.SourceGenerator.Tests/GenerateTest.cs",
"chars": 641,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusi"
},
{
"path": "tests/MasterMemory.SourceGenerator.Tests/IncrementalGeneratorTest.cs",
"chars": 1253,
"preview": "namespace MasterMemory.SourceGenerator.Tests;\n\npublic class IncrementalGeneratorTest\n{\n void VerifySourceOutputReaso"
},
{
"path": "tests/MasterMemory.SourceGenerator.Tests/MasterMemory.SourceGenerator.Tests.csproj",
"chars": 934,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net9.0</TargetFramework>\n\t\t<ImplicitUsings>enabl"
},
{
"path": "tests/MasterMemory.SourceGenerator.Tests/TestBase.cs",
"chars": 315,
"preview": "namespace MasterMemory.SourceGenerator.Tests;\n\npublic abstract class TestBase(ITestOutputHelper testoutputHelper)\n{\n "
},
{
"path": "tests/MasterMemory.SourceGenerator.Tests/Utility/CSharpGeneratorRunner.cs",
"chars": 5980,
"preview": "using MasterMemory.SourceGenerator;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft."
},
{
"path": "tests/MasterMemory.SourceGenerator.Tests/Utility/CodeGeneratorHelper.cs",
"chars": 4592,
"preview": "using Microsoft.CodeAnalysis;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.CompilerServices;\n\npublic cla"
},
{
"path": "tests/MasterMemory.Tests/BinarySearchTest.cs",
"chars": 4976,
"preview": "using MasterMemory.Internal;\nusing MessagePack.Resolvers;\nusing System;\nusing System.Collections.Generic;\nusing System."
},
{
"path": "tests/MasterMemory.Tests/DatabaseTest.cs",
"chars": 4444,
"preview": "#pragma warning disable\nusing MessagePack;\nusing MessagePack.Resolvers;\nusing System;\nusing System.Collections.Generic;"
},
{
"path": "tests/MasterMemory.Tests/IssueTest.cs",
"chars": 2537,
"preview": "using MasterMemory.Tests.TestStructures;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Syste"
},
{
"path": "tests/MasterMemory.Tests/MasterMemory.Tests.csproj",
"chars": 881,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net9.0</TargetFramework>\n\t</PropertyGroup>\n\n\t<It"
},
{
"path": "tests/MasterMemory.Tests/MemoryKeyTest.cs",
"chars": 2715,
"preview": "#pragma warning disable\nusing Xunit;\nusing System.Linq;\nusing MasterMemory.Tests.Tables;\nusing MessagePack;\nusing Syste"
},
{
"path": "tests/MasterMemory.Tests/MemoryTest.cs",
"chars": 7013,
"preview": "using MasterMemory.Tests.Tables;\nusing MessagePack;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Xunit;\n\n"
},
{
"path": "tests/MasterMemory.Tests/MessagePackResolver.cs",
"chars": 198,
"preview": "using MessagePack;\nusing MessagePack.Resolvers;\n\nnamespace MasterMemory.Tests;\n\n[CompositeResolver(typeof(MasterMemoryR"
},
{
"path": "tests/MasterMemory.Tests/MetaTest.cs",
"chars": 997,
"preview": "#pragma warning disable\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\nusing Xunit;\n\nnamespace Mast"
},
{
"path": "tests/MasterMemory.Tests/RangeViewTest.cs",
"chars": 2936,
"preview": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Xunit;\n\nnamespace Ma"
},
{
"path": "tests/MasterMemory.Tests/TestStructures/PersonModel.cs",
"chars": 580,
"preview": "#pragma warning disable\nusing MessagePack;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespac"
},
{
"path": "tests/MasterMemory.Tests/TestStructures/QuestMaster.cs",
"chars": 3220,
"preview": "#pragma warning disable\nusing MessagePack;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespac"
},
{
"path": "tests/MasterMemory.Tests/TestStructures/Sample.cs",
"chars": 1362,
"preview": "#pragma warning disable\nusing MessagePack;\n\nnamespace MasterMemory.Tests\n{\n [MemoryTable(\"s_a_m_p_l_e\"), MessagePack"
},
{
"path": "tests/MasterMemory.Tests/TestStructures/SkillMaster.cs",
"chars": 833,
"preview": "#pragma warning disable\nusing MessagePack;\n\nnamespace MasterMemory.Tests\n{\n [MemoryTable(\"skillmaster\"), MessagePack"
},
{
"path": "tests/MasterMemory.Tests/TestStructures/TestMaster.cs",
"chars": 490,
"preview": "using MessagePack;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace MasterMemory.Tests.Test"
},
{
"path": "tests/MasterMemory.Tests/TestStructures/UserLevel.cs",
"chars": 446,
"preview": "using MessagePack;\n\nnamespace MasterMemory.Tests\n{\n [MemoryTable(\"UserLevel\"), MessagePackObject(true)]\n public cl"
},
{
"path": "tests/MasterMemory.Tests/ValidatorTest.cs",
"chars": 11710,
"preview": "using MasterMemory.Tests.TestStructures;\nusing MessagePack;\nusing System;\nusing System.Collections.Generic;\nusing Syste"
}
]
About this extraction
This page contains the full source code of the neuecc/MasterMemory GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 142 files (448.9 KB), approximately 111.3k tokens, and a symbol index with 614 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.