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
================================================
13
false
$(Version)
Cysharp
Cysharp
© Cysharp, Inc.
database, embedded, inmemory, unity
https://github.com/Cysharp/MasterMemory
README.md
$(PackageProjectUrl)
git
MIT
Icon.png
================================================
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.
## 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)
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 result = db.PersonTable.FindByGenderAndAge((Gender.Female, 23));
// Get nearest value(choose lower(default) or higher).
RangeView age1 = db.PersonTable.FindClosestByAge(31);
// Get range(min-max inclusive).
RangeView 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`(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 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` FindBy***(TKey key)
* bool TryFindBy***(TKey key, out T result)
* `T|RangeView` FindClosestBy***(TKey key, bool selectLower = true)
* `RangeView` 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` All
* `RangeView` AllReverse
* `RangeView` SortBy***
* `T[] GetRawDataUnsafe()`
`struct RangeView : IEnumerable` is the view of database elements. It has following property/method.
* `T` [int index]
* `int` Count
* `T` First
* `T` Last
* `RangeView` Reverse
* `IEnumerator` 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 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 to targeted validation
[MemoryTable("quest_master"), MessagePackObject(true)]
public class Quest : IValidatable
{
// 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.Validate(IValidator validator)
{
// get the external reference table
var items = validator.GetReferenceSet- ();
// 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
{
ValidatableSet GetTableSet();
ReferenceSet GetReferenceSet();
void Validate(Expression> predicate);
void Validate(Func predicate, string message);
void ValidateAction(Expression> predicate);
void ValidateAction(Func predicate, string message);
void Fail(string message);
bool CallOnce();
}
class ReferenceSet
{
IReadOnlyList TableData { get; }
void Exists(Expression> elementSelector, Expression> referenceElementSelector);
void Exists(Expression> elementSelector, Expression> referenceElementSelector, EqualityComparer equalityComparer);
}
class ValidatableSet
{
IReadOnlyList TableData { get; }
void Unique(Expression> selector);
void Unique(Expression> selector, IEqualityComparer equalityComparer);
void Unique(Func selector, string message);
void Unique(Func selector, IEqualityComparer equalityComparer, string message);
void Sequential(Expression> selector, bool distinct = false);
ValidatableSet Where(Func 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