Merge origin/main (refusals rows 1-33)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
2fd8eb80cc
28 changed files with 59 additions and 24 deletions
|
|
@ -25,7 +25,7 @@ closure through UPM rather than NuGet restore.
|
|||
Install the Unity package from the immutable release tag:
|
||||
|
||||
```text
|
||||
https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v2.0.0
|
||||
https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v3.0.0
|
||||
```
|
||||
|
||||
## Rolling back across the store format
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<PackageId>GameCult.Math</PackageId>
|
||||
<!-- MIT overall; math.Phacelle.cs and CultPhasor.cs (and the two Phacelle HLSL files) are MPL-2.0; math.Cycles.cs and CultMath.Cycles.hlsl are Apache-2.0. -->
|
||||
<PackageLicenseExpression>MIT AND MPL-2.0 AND Apache-2.0</PackageLicenseExpression>
|
||||
<Version>0.5.0</Version>
|
||||
<Version>0.5.1</Version>
|
||||
<Description>Clean-room C# math shaped for HLSL-style renderer code.</Description>
|
||||
<Authors>GameCult</Authors>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ All notable changes to this package are documented in this file.
|
|||
Earlier releases (0.2.0-0.2.3) predate this package's changelog and are not
|
||||
backfilled here; see `docs/semver-policy.md` for why.
|
||||
|
||||
## [Unreleased]
|
||||
## [0.5.1] - 2026-11-11
|
||||
|
||||
### Added
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "org.gamecult.cultmath",
|
||||
"displayName": "CultMath",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"unity": "2021.3",
|
||||
"description": "Precompiled CultMath numeric primitives and matching HLSL semantics for GameCult Unity runtimes.",
|
||||
"license": "MIT AND MPL-2.0 AND Apache-2.0",
|
||||
|
|
|
|||
|
|
@ -352,6 +352,11 @@ namespace GameCult.Caching.Tests
|
|||
private static readonly Rec[] RepullAfter = Items_(("item:a1", "A"), ("item:b1", "B"), ("item:b2", "B"), ("item:c1", "A"));
|
||||
private static readonly Rec[] KeyCaseRecords = Items_(("a", "S"), ("z", "S"), ("B", "T"), ("C", "T"));
|
||||
private static readonly Rec[] HolderCaseRecords = Items_(("a", "S"), ("A", "S"));
|
||||
private static readonly Rec[] CrossSchemaRecords = { new("x:1", Alpha, "P"), new("y:1", Beta, "P") };
|
||||
// Distinct under any trim, case-fold, NFC or NFKC of the value: 'S' and 's', 'S' and 'S ', NFC and NFD, fullwidth S.
|
||||
private static readonly Rec[] DistinctValueRecords = Items_(
|
||||
("k:1", "S"), ("k:2", "s"), ("k:3", "S "), ("k:4", "\u00E9"), ("k:5", "e\u0301"), ("k:6", "\uFF33"), ("k:7", " S"));
|
||||
private static readonly Rec[] NormalKeyRecords = Items_(("\u00E9", "S"), ("e\u0301", "S"));
|
||||
private static readonly Rec[] KeyPunctuationRecords = Items_(("_", "S"), ("a", "S"), ("Z", "T"), ("b", "T"));
|
||||
private static readonly Rec[] SurrogateGroupRecords = Items_(("\uE000", "S"), ("\uE000b", "S"), ("\U0001F600", "T"), ("\U0001F600b", "T"));
|
||||
|
||||
|
|
@ -362,6 +367,8 @@ namespace GameCult.Caching.Tests
|
|||
("key-case-store.cc", KeyCaseRecords), ("key-punctuation-store.cc", KeyPunctuationRecords),
|
||||
("surrogate-groups-store.cc", SurrogateGroupRecords),
|
||||
("holder-case-store.cc", HolderCaseRecords),
|
||||
("cross-schema-store.cc", CrossSchemaRecords), ("distinct-values-store.cc", DistinctValueRecords),
|
||||
("normal-keys-store.cc", NormalKeyRecords),
|
||||
};
|
||||
|
||||
private static readonly Refusal SurrogateRefusal = new("k\U0001F600", "k\uE000", Item, "Sku");
|
||||
|
|
@ -371,6 +378,7 @@ namespace GameCult.Caching.Tests
|
|||
private static readonly Refusal RepullRefusal = new("item:a1", "item:c1", Item, "Sku");
|
||||
private static readonly Refusal KeyCaseRefusal = new("B", "C", Item, "Sku");
|
||||
private static readonly Refusal HolderCaseRefusal = new("A", "a", Item, "Sku");
|
||||
private static readonly Refusal NormalKeyRefusal = new("e\u0301", "\u00E9", Item, "Sku");
|
||||
private static readonly Refusal KeyPunctuationRefusal = new("Z", "b", Item, "Sku");
|
||||
private static readonly Refusal SurrogateGroupRefusal = new("\U0001F600", "\U0001F600b", Item, "Sku");
|
||||
|
||||
|
|
@ -408,6 +416,20 @@ namespace GameCult.Caching.Tests
|
|||
// Rows 23-24: two holders of one value that differ only by case are two holders; a case-folding dedupe would see one.
|
||||
new("batch-holders-by-case", new[] { Open(), Commit(HolderCaseRecords) }, HolderCaseRefusal),
|
||||
new("load-holders-by-case", new[] { Open("holder-case-store.cc") }, HolderCaseRefusal),
|
||||
// Row 25: the held `a` is replaced only by the exact key `a`, never by `A`.
|
||||
new("batch-replaced-by-case", new[] { Open(), Commit(Items_(("a", "S"))), Commit(Items_(("A", "S"))) }, HolderCaseRefusal),
|
||||
// Rows 26-31: identity is exact. One value in two schemas is two groups; values differing in case, trailing or leading space, normalisation form or width are two values; keys differing only by normalisation form are two holders.
|
||||
new("batch-value-in-two-schemas", new[] { Open(), Commit(CrossSchemaRecords) }, null),
|
||||
new("load-value-in-two-schemas", new[] { Open("cross-schema-store.cc") }, null),
|
||||
new("batch-distinct-values", new[] { Open(), Commit(DistinctValueRecords) }, null),
|
||||
new("load-distinct-values", new[] { Open("distinct-values-store.cc") }, null),
|
||||
new("batch-keys-by-normal-form", new[] { Open(), Commit(NormalKeyRecords) }, NormalKeyRefusal),
|
||||
new("load-keys-by-normal-form", new[] { Open("normal-keys-store.cc") }, NormalKeyRefusal),
|
||||
// Rows 32-33: one landing record sharing two unique aliases with a held one; the least alias by code unit is named ('Alt' before 'Sku'; 'Sku' before 'alt').
|
||||
new("put-onto-a-held-pair", new[] { Open(), Commit(new Rec("m", Pair, "S", "X")), Commit(new Rec("a", Pair, "S", "X")) },
|
||||
new Refusal("a", "m", Pair, "Alt")),
|
||||
new("put-onto-a-held-alias-pair", new[] { Open(), Commit(new Rec("m", Alias, "S", "X")), Commit(new Rec("a", Alias, "S", "X")) },
|
||||
new Refusal("a", "m", Alias, "Sku")),
|
||||
};
|
||||
|
||||
private static byte[] RefusalStoreBytes(Rec[] records)
|
||||
|
|
@ -528,6 +550,7 @@ namespace GameCult.Caching.Tests
|
|||
var count = reader.ReadArrayHeader();
|
||||
Assert.That(count, Is.EqualTo(Cases.Length));
|
||||
var walked = 0;
|
||||
var failed = new List<string>();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
Assert.That(reader.ReadArrayHeader(), Is.EqualTo(3));
|
||||
|
|
@ -588,6 +611,10 @@ namespace GameCult.Caching.Tests
|
|||
|
||||
walked++;
|
||||
}
|
||||
catch (AssertionException failure)
|
||||
{
|
||||
failed.Add($"{label}: {failure.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
cache?.Dispose();
|
||||
|
|
@ -595,7 +622,8 @@ namespace GameCult.Caching.Tests
|
|||
}
|
||||
}
|
||||
|
||||
Assert.That(walked, Is.EqualTo(24));
|
||||
Assert.That(failed, Is.Empty, "rows that failed");
|
||||
Assert.That(walked, Is.EqualTo(33));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ reviewed commit. Other runtimes are held to the same canonical text and the same
|
|||
`" "` and `item:d` holds Sku `U+0085`. Written through a role Sku.
|
||||
- `blank-store.cc`: the same, only `item:c` and `item:d`.
|
||||
- `pair-store.cc`, `surrogate-store.cc`, `types-store.cc`, `repull-before.cc`, `repull-after.cc`, `alias-store.cc`,
|
||||
`key-case-store.cc`, `key-punctuation-store.cc`, `surrogate-groups-store.cc`, `holder-case-store.cc`: single-file stores written like
|
||||
`key-case-store.cc`, `key-punctuation-store.cc`, `surrogate-groups-store.cc`, `holder-case-store.cc`, `cross-schema-store.cc`, `distinct-values-store.cc`, `normal-keys-store.cc`: single-file stores written like
|
||||
`duplicate-store.cc`, through roles, for the rows of `refusals.msgpack` that open or pull them. Schemas
|
||||
`tests.unique_item`, `tests.uq_pair` (Sku and Alt both unique), `tests.uq_alias` (Sku and `alt` both unique),
|
||||
`tests.uq_alpha` and `tests.uq_beta`, each slots `[0: Sku string, 1: second string]`, schema version the name plus
|
||||
|
|
@ -51,20 +51,29 @@ last succeeds and the last refuses with exactly the RULE text built from those f
|
|||
byte-identical. Schemas are those of the store files above; `second` is `Category` (plain) except in `tests.uq_pair`
|
||||
and `tests.uq_alias`, where it is `Alt` (unique, alias `Alt` and `alt` respectively).
|
||||
|
||||
The 13 rows of the spec are a floor; rows 14-24 extend it with orderings that a code-point, case-insensitive or
|
||||
The 13 rows of the spec are a floor; rows 14-33 extend it with orderings that a code-point, case-insensitive or
|
||||
culture compare would flip. Rows, in file order: 1 batch-later-value-staged-first, 2 batch-surrogate-keys, 3
|
||||
batch-interleaved-types, 4 batch-two-aliases, 5 held-then-landing, 6 held-in-the-least-group, 7 swap-off-a-held-value,
|
||||
8 load-two-aliases, 9 load-surrogate-keys, 10 load-interleaved-types, 11 repull-held-pair, 12 load-repull-after, 13
|
||||
commit-onto-a-loaded-holder, 14 batch-key-case (`B` before `a`), 15 batch-key-punctuation (`Z` before `_` before `a`),
|
||||
16 batch-key-case-in-a-group, 17 batch-surrogate-groups (U+1F600 before U+E000, the reverse of code-point order), 18
|
||||
batch-alias-case (alias `Sku` before `alt`), 19 load-alias-case, 20 load-key-case, 21 load-key-punctuation, 22
|
||||
load-surrogate-groups, 23 batch-holders-by-case (`a` and `A` holding one value: `A` before `a`), 24 load-holders-by-case.
|
||||
Rows 19-22 and 24 open a store holding the records of rows 18, 14, 15, 17 and 23, so a runtime with no batch
|
||||
load-surrogate-groups, 23 batch-holders-by-case (`a` and `A` holding one value: `A` before `a`), 24 load-holders-by-case, 25 batch-replaced-by-case (held `a`, then a commit of `A` on its value: `A` does not replace `a`),
|
||||
26 batch-value-in-two-schemas (one value in `tests.uq_alpha` and `tests.uq_beta` at two keys: two groups, success), 27
|
||||
load-value-in-two-schemas, 28 batch-distinct-values (`S`, `s`, `S `, ` S`, U+00E9, `e`+U+0301, U+FF33 are seven values: success), 29
|
||||
load-distinct-values, 30 batch-keys-by-normal-form (keys U+00E9 and `e`+U+0301 holding one value are two holders, `e`+U+0301 first),
|
||||
31 load-keys-by-normal-form, 32 put-onto-a-held-pair (held `m` and landing `a` share Sku and Alt in `tests.uq_pair`, one record per
|
||||
commit: `Alt` is named before `Sku`), 33 put-onto-a-held-alias-pair (the same in `tests.uq_alias`: `Sku` before `alt`).
|
||||
Rows 19-22, 24, 27, 29 and 31 open a store holding the records of rows 18, 14, 15, 17, 23, 26, 28 and 30, so a runtime with no batch
|
||||
commit still walks alias and cross-group key order.
|
||||
|
||||
A runtime performs every row its API can perform and asserts the count it walked:
|
||||
A runtime performs every row its API can perform and asserts the count it walks. These are the counts a runtime must
|
||||
assert, not a statement of which runtimes walk them today:
|
||||
|
||||
- C# and Rust: all 24.
|
||||
- Python: 23, every row but 3 (`put_envelopes` takes one type).
|
||||
- TypeScript: 12, rows 5, 8, 9, 10, 11, 12, 13, 19, 20, 21, 22 and 24 (no batch commit, so no row 1-4, 6, 7, 14-18 or 23;
|
||||
`variants:idea:unique-index-runtimes.ts-batch-commit`).
|
||||
- C# and Rust: all 33.
|
||||
- Python: 31, every row but 3 and 26 (`put_envelopes` takes one type, so no batch of two types).
|
||||
- TypeScript: 18, the rows with no multi-record commit: 5, 8, 9, 10, 11, 12, 13, 19, 20, 21, 22, 24, 25, 27, 29, 31, 32 and 33
|
||||
(no batch commit, so no row 1-4, 6, 7, 14-18, 23, 26, 28 or 30; `variants:idea:unique-index-runtimes.ts-batch-commit`).
|
||||
|
||||
Not pinned: the schema-name tiebreak. Record keys are unique across a whole cache, so two types never hold the same key and
|
||||
two groups can never tie on alias and key pair; the final `schema` comparison cannot decide a refusal.
|
||||
|
|
|
|||
BIN
tests/vectors/unique-index/cross-schema-store.cc
Normal file
BIN
tests/vectors/unique-index/cross-schema-store.cc
Normal file
Binary file not shown.
BIN
tests/vectors/unique-index/distinct-values-store.cc
Normal file
BIN
tests/vectors/unique-index/distinct-values-store.cc
Normal file
Binary file not shown.
BIN
tests/vectors/unique-index/normal-keys-store.cc
Normal file
BIN
tests/vectors/unique-index/normal-keys-store.cc
Normal file
Binary file not shown.
Binary file not shown.
|
|
@ -2,11 +2,9 @@
|
|||
|
||||
All notable changes to this package are documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
## [3.0.0] - 2026-11-11
|
||||
|
||||
Releases as 3.0.0 (major).
|
||||
|
||||
### Breaking (major)
|
||||
### Breaking
|
||||
|
||||
- A single-file store flush refuses a file it cannot read (empty, truncated, an unreadable stamp or body) with `CultStoreUnreadableException` and leaves the file as it is. A flush used to replace such a file. A write set cannot merge with a disk it cannot read, so the file is repaired or removed by its owner before the store writes again.
|
||||
- A single-file store reads v1, v2 and v3 stamps and refuses v4 and later by name; a directory store reads v4 and v5 and refuses v6 and later by name. Each judges the stamp before the body, so an unreadable body never makes a newer store look like damage.
|
||||
|
|
|
|||
|
|
@ -11,19 +11,19 @@ and OpenSSL license notices are included under `Third Party Notices`.
|
|||
Build it with `scripts/build-unity-package.ps1`. Do not edit generated plugin
|
||||
assemblies in the package output.
|
||||
|
||||
Install version `2.0.0` through Unity Package Manager with:
|
||||
Install version `3.0.0` through Unity Package Manager with:
|
||||
|
||||
```text
|
||||
https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v2.0.0
|
||||
https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v3.0.0
|
||||
```
|
||||
|
||||
The package depends on `org.gamecult.cultmath` (exactly 0.5.0) and does not
|
||||
The package depends on `org.gamecult.cultmath` (exactly 0.5.1) and does not
|
||||
carry its own `CultMath.dll`. Unity Package Manager resolves git packages only
|
||||
from the project manifest, so add CultMath beside CultLib in
|
||||
`Packages/manifest.json`:
|
||||
|
||||
```text
|
||||
"org.gamecult.cultmath": "https://github.com/GameCult/CultLib.git?path=/packages/cultmath/unity/org.gamecult.cultmath#cultmath-unity-v0.5.0"
|
||||
"org.gamecult.cultmath": "https://github.com/GameCult/CultLib.git?path=/packages/cultmath/unity/org.gamecult.cultmath#cultmath-unity-v0.5.1"
|
||||
```
|
||||
|
||||
CultMesh chooses mapped memory for reachable same-machine bodies and advertised
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"name": "org.gamecult.cultlib",
|
||||
"displayName": "CultLib",
|
||||
"version": "2.0.1",
|
||||
"version": "3.0.0",
|
||||
"unity": "2021.3",
|
||||
"dependencies": {
|
||||
"org.gamecult.cultmath": "0.5.0"
|
||||
"org.gamecult.cultmath": "0.5.1"
|
||||
},
|
||||
"description": "CultCache, CultNet, and CultMesh managed runtime assemblies for Unity.",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
Loading…
Reference in a new issue