Skip to content

Add the shape-pattern transposition table and make it the default - #368

Merged
tameware merged 26 commits into
dds-bridge:developfrom
tameware:fable/bridge-solver-shape-pattern-transposition
Sep 12, 2026
Merged

tameware merged 26 commits into
dds-bridge:developfrom
tameware:fable/bridge-solver-shape-pattern-transposition

Conversation

@tameware

@tameware tameware commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add TransTableP, a transposition table organised as suit-length shape → relative-rank patterns, following the cache design of macroxue's bridge-solver. A pattern records only the cards that decided a result (those at or above the lowest winning rank per suit, by owner), so one entry generalises to many positions.
  • Under each shape patterns are unbounded in number, ordered most-general-first and bucketed by the owner of the first relevant suit's top card, so a lookup scans 5 of 17 buckets. Blocks are cache-line aligned and pooled per size class; on reaching the memory maximum the table is cleared rather than harvested.
  • Make TTKind::Pattern (2) the SolverConfig default. DDS_TT_KIND=small|large|pattern overrides it at runtime. C API signatures unchanged (tt_kind doc updated).
  • Update specs/transposition-table.md, specs/solver-context.md, docs/c++_interface.md.

Bridge-solver's subsumption tree was implemented first and profiled; it was a net loss for DDS's access pattern, so the flat generic-first list is what ships.

Results

Identical answers to TransTableL on list100, list1000 and the freak0 deal.

Workload Large Pattern
list1000 calc (per board) 91.3 ms 87.7 ms
list1000 solve (per board) 18.6 ms 18.9 ms
freak0 calc, 8 threads 11.7 s 8.8 s
freak0, 1 thread, large TT 25.3 s 14.3 s
freak0 @ 40 MB 69 s 28 s
freak0 @ 20 MB 1034 s 48 s

Parity on random deals; large wins on void-heavy deals and under memory pressure, where TransTableL's fixed per-shape blocks overflow (61% of adds on freak0) and lookups degrade to ~94-entry linear scans.

Not in this PR

  • .NET SolverConfig still defaults to TTKind.Large and its enum lacks Pattern = 2; the web WASM build pins Small.

Test plan

  • bazelisk test //... (93/93)
  • New white-box tests //library/tests/trans_table:trans_table (trans_table_p_test.cpp)
  • configure_tt_api_test: default kind, Pattern create/switch/resize, env override; dds_c_api_test with tt_kind = 2
  • dtest -s solve/calc on hands/list100.txt, hands/list1000.txt and freak0 with DDS_TT_KIND unset, large, pattern: no differences

tameware and others added 2 commits September 8, 2026 17:20
TransTableP keys positions by suit-length shape and stores, under each
shape, the relative-rank patterns that decided the result (the cards at
or above the lowest winning rank per suit, by owner), following the
cache design of macroxue's bridge-solver. Patterns are ordered most
general first and bucketed by the owner of the first relevant suit's top
card, so a lookup scans only the buckets it can match. Blocks are
cache-line aligned and pooled per size class; when the memory maximum is
reached the table is cleared rather than harvested.

Results are identical to TransTableL. Performance is at parity on random
deals and markedly better on void-heavy deals and under tight memory
limits, where TransTableL's fixed per-shape blocks overflow and lookups
degrade to long linear scans.

TTKind::Pattern (2) is the new SolverConfig default; DDS_TT_KIND=
small|large|pattern overrides it. Specs and C API docs updated.

Co-authored-by: Cursor <cursoragent@cursor.com>
alignas(CacheLine) rounded the 76-byte header up to 128 bytes implicitly,
which MSVC reports as C4324 and /WX turns into an error. Make the padding
an explicit member and static_assert the resulting layout, so the block
header is identical on every compiler.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tameware

tameware commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

See Issue #367

This took Fable a couple of hours to implement. The speedup is small but significant. @zzcgumn's call on whether to merge this. There are other techniques we can borrow from bridge-solver that will likely enhance performance further.

@tameware

tameware commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

Multithreaded benchmark:

% python3 python/utilities/src/benchmark.py --repeats 10 --branch develop --branch fable/bridge-solver-shape-pattern-transposition --max_deals 1000
Building dtest from 'develop'...
Building dtest from 'fable/bridge-solver-shape-pattern-transposition'...
Restoring 'benchmark'...
DDS dtest benchmark
===================
baseline:    develop  (/var/folders/12/xtx6dlwd0mdcxkspvmsszsrc0000gn/T/dds-dtest-bin.5wa8015w)
binary 2:    fable/bridge-solver-shape-pattern-transposition  (/var/folders/12/xtx6dlwd0mdcxkspvmsszsrc0000gn/T/dds-dtest-bin.60fc_zf0)
details:     off (summary only)
run order:   interleaved develop, fable/bridge-solver-shape-pattern-transposition
epsilon:     0.5%
hands dir:   /Users/adamw/src/dds/hands
max_deals:   1000
files:       list1000.txt list100.txt list10.txt list1.txt
solvers:     solve calc
git branch:  benchmark
repeats:     10


Summary (avg user ms)
==============================================================================
solver file               develop fable/bridge        rel note
------ ------------- ------------ ------------ ---------- ---------------
solve  list1000.txt          1.92         1.80      0.94x fable/bridge-solver-shape-pattern-transposition faster
solve  list100.txt           2.61         2.33      0.89x fable/bridge-solver-shape-pattern-transposition faster
solve  list10.txt           25.18        23.13      0.92x fable/bridge-solver-shape-pattern-transposition faster
solve  list1.txt             8.00         7.00      0.88x fable/bridge-solver-shape-pattern-transposition faster
calc   list1000.txt          7.10         6.88      0.97x fable/bridge-solver-shape-pattern-transposition faster
calc   list100.txt           7.16         6.82      0.95x fable/bridge-solver-shape-pattern-transposition faster
calc   list10.txt           22.37        20.05      0.90x fable/bridge-solver-shape-pattern-transposition faster
calc   list1.txt            53.60        50.00      0.93x fable/bridge-solver-shape-pattern-transposition faster
------ ------------- ------------ ------------ ---------- ---------------
TOTAL  solve                 2.20         2.05      0.93x fable/bridge-solver-shape-pattern-transposition faster
TOTAL  calc                  7.29         7.03      0.96x fable/bridge-solver-shape-pattern-transposition faster

@tameware

tameware commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

Single-threaded benchmark:

% python3 python/utilities/src/benchmark.py --repeats 10 --branch develop --branch fable/bridge-solver-shape-pattern-transposition --bridgesolver ../bridge-solver/solver -s calc --max_deals 100 -- -n 1
Building dtest from 'develop'...
Building dtest from 'fable/bridge-solver-shape-pattern-transposition'...
Restoring 'benchmark'...
Building current-tree dtest for --bridgesolver harness...
DDS dtest benchmark
===================
baseline:    develop  (/var/folders/12/xtx6dlwd0mdcxkspvmsszsrc0000gn/T/dds-dtest-bin.taq0ekva)
binary 2:    fable/bridge-solver-shape-pattern-transposition  (/var/folders/12/xtx6dlwd0mdcxkspvmsszsrc0000gn/T/dds-dtest-bin.oqsg7ec_)
binary 3:    solver  (/var/folders/12/xtx6dlwd0mdcxkspvmsszsrc0000gn/T/dds-dtest-bin.ti537hl1)
details:     off (summary only)
run order:   interleaved develop, fable/bridge-solver-shape-pattern-transposition, solver
hands dir:   /Users/adamw/src/dds/hands
max_deals:   100
files:       list100.txt list10.txt list1.txt
solvers:     calc
git branch:  benchmark
repeats:     10
bridgesolver: ../bridge-solver/solver
dtest args:  -n 1


Summary (avg user ms)
==============================================================================
solver file               develop fable/bridge       solver
------ ------------- ------------ ------------ ------------
calc   list100.txt          83.51        84.08        82.94
calc   list10.txt           76.63        75.25        62.91
calc   list1.txt           131.50       130.50       113.10
------ ------------- ------------ ------------ ------------
TOTAL  calc                 83.32        83.70        81.41

setenv/unsetenv do not exist on MSVC; use _putenv_s there, as args_test
already does.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tameware

tameware commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

"Freak" deal timing:

develop:

% time bazel-bin/utilities/dd_table_for_deal "N:AQT62..Q97.AT832 K85.KJ753..KJ765 9.AT8642.AJ8642. J743.Q9.KT53.Q94"
dd_table_for_deal:
------------------
            AQT62
            -
            Q97
            AT832
J743                    K85
Q9                      KJ753
KT53                    -
Q94                     KJ765
            9
            AT8642
            AJ8642
            -

      North South East  West
   NT     7     7     5     6
    S     8     8     5     5
    H     8     8     5     5
    D    11    11     2     2
    C     6     6     6     7

Par: NS 5D = 400
bazel-bin/utilities/dd_table_for_deal   27.56s user 0.12s system 228% cpu 12.098 total

This branch:

% time bazel-bin/utilities/dd_table_for_deal "N:AQT62..Q97.AT832 K85.KJ753..KJ765 9.AT8642.AJ8642. J743.Q9.KT53.Q94"
…
bazel-bin/utilities/dd_table_for_deal   15.06s user 0.09s system 168% cpu 8.987 total

bridge-solver:

% time ../bridge-solver/solver -f deals/freak/deal.0
Input file not found: 'deals/freak/deal.0'.
../bridge-solver/solver -f deals/freak/deal.0  0.00s user 0.00s system 51% cpu 0.006 total
(base) adamw@MacBook-Pro dds % time ../bridge-solver/solver -f ../bridge-solver/deals/freak/deal.0
                          ♠ AQT62 ♥ - ♦ Q97 ♣ AT832
  ♠ J743 ♥ Q9 ♦ KT53 ♣ Q94                       ♠ K85 ♥ KJ753 ♦ - ♣ KJ765
                          ♠ 9 ♥ AT8642 ♦ AJ8642 ♣ -
N  7  7  6  5  4.76 s 261344.0 M
S  8  8  5  5  5.11 s 261376.0 M
H  8  8  5  5  6.00 s 261520.0 M
D 11 11  2  2  6.07 s 261520.0 M
C  6  6  7  6  7.63 s 262000.0 M
../bridge-solver/solver -f ../bridge-solver/deals/freak/deal.0  7.57s user 0.05s system 99% cpu 7.634 total

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Duplicate inserts can trigger unnecessary table resets, and lowering the hard memory limit is not immediately enforced.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds the shape-pattern transposition table, makes it the default, and exposes configuration through existing APIs.

Changes:

  • Implements pooled, shape-keyed relative-rank pattern caching.
  • Adds comprehensive table and API tests.
  • Updates defaults, build targets, and documentation.
File summaries
File Description
specs/transposition-table.md Documents Pattern table behavior.
specs/solver-context.md Documents the new default.
library/tests/trans_table/trans_table_p_test.cpp Tests matching, storage, memory, and parity.
library/tests/trans_table/BUILD.bazel Registers Pattern table tests.
library/tests/system/configure_tt_api_test.cpp Tests configuration and environment overrides.
library/tests/dds_c_api_test.cpp Tests Pattern through the C API.
library/src/trans_table/trans_table_p.hpp Declares TransTableP.
library/src/trans_table/trans_table_p.cpp Implements pattern caching and memory management.
library/src/trans_table/BUILD.bazel Adds Pattern sources to build targets.
library/src/solver_context/solver_context.hpp Adds TTKind::Pattern and changes the default.
library/src/solver_context/solver_context.cpp Creates and configures Pattern tables.
library/src/api/dds_c_api.h Documents Pattern’s C ABI value.
docs/c++_interface.md Updates C++ configuration documentation.
Review details
  • Files reviewed: 13/13 changed files
  • Comments generated: 3
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread library/src/trans_table/trans_table_p.cpp
Comment thread library/src/trans_table/trans_table_p.cpp Outdated
Comment thread specs/transposition-table.md Outdated
set_memory_maximum() on a live TransTableP that is already above the new
limit now clears the table immediately instead of leaving it over budget
until the next block allocation; inserts into blocks with spare capacity
never consult the budget, so without this a lowered hard cap could go
unenforced indefinitely.

add() now searches the bucket for an identical pattern before reserving
capacity. Re-adding an existing pattern to a full block used to double
the block, or at the memory limit clear the whole table, for an update
that needed no allocation.

Spec: distinguish ordinary resets, which pool the pattern blocks, from
MemoryExhausted resets, which also free the pool.

Co-authored-by: Cursor <cursoragent@cursor.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Memory-exhaustion and teardown paths retain storage and may allocate beyond the configured hard cap.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

library/src/trans_table/trans_table_p.cpp:155

  • return_all_memory() leaves substantial dynamic storage behind: ownership_ keeps its 8,192-entry capacity, and free_spare_trees() only clears each pointer vector without releasing its backing allocation. This violates the base-class contract that all structures are deallocated and leaves memory_in_use() at roughly 384 KiB even after the call. Release these vector capacities as well.
auto TransTableP::return_all_memory() -> void
{
    release_trees();
    free_spare_trees();
    std::vector<ShapeSlot>().swap(shapes_);
}
  • Files reviewed: 13/13 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread library/src/trans_table/trans_table_p.cpp Outdated
…own.

A MemoryExhausted reset used to push every active block into the spare
pool, which may allocate, only to delete the pool immediately. It now
deletes the blocks outright, so the over-budget recovery path never
allocates. make_tt() uses the same path.

return_all_memory() now also drops the ownership table and the pool
vectors' capacity, so memory_in_use() is zero afterwards as the base
contract requires; init() rebuilds the ownership table per deal anyway.

Co-authored-by: Cursor <cursoragent@cursor.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Shape-table allocation can transiently exceed the documented hard memory cap, and environment tests leak process state.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

library/tests/system/configure_tt_api_test.cpp:54

  • This permanently removes a caller-provided DDS_TT_KIND, so subsequent tests in this executable no longer observe the environment they were launched with and become order-dependent. Use a guard that captures and restores the original value (as args_test.cpp:98 does); ScopedEnv above must likewise restore the previous value rather than always unsetting it.

library/src/trans_table/trans_table_p.cpp:440

  • This growth check budgets only the final replacement table, but fresh is allocated while the old shapes_ storage is still live. A rehash therefore exceeds the advertised hard cap by the entire old table and can fail under the memory pressure the cap is meant to control. Include current dynamic usage plus the new allocation in the check so the table resets when there is insufficient peak headroom.
    if (new_size * sizeof(ShapeSlot) + tree_bytes_ > maximum_bytes_) {
  • Files reviewed: 13/13 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread library/src/trans_table/trans_table_p.cpp Outdated
reset_memory() now frees the old shape table before allocating the
fresh one, and grow_shapes() budgets the peak of old and new tables
together, so neither path allocates beyond the configured maximum.

configure_tt_api_test's ScopedEnv restores the previous value of the
variable (or its absence) instead of always unsetting it, and the
default-kind test uses it rather than unsetting DDS_TT_KIND for the rest
of the process.

Co-authored-by: Cursor <cursoragent@cursor.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The owning table remains implicitly copyable, and one allocation-failure path leaks a newly allocated tree.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

library/src/trans_table/trans_table_p.cpp:419

  • release_tree(old) can allocate while growing the spare-vector and throw after fresh has been allocated but before it is attached to slot. On that path fresh is unreachable, so its aligned allocation leaks and tree_bytes_ remains permanently inflated. Clean up fresh if pooling the old block fails (or hold it in an RAII owner until commit).
  • Files reviewed: 13/13 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread library/src/trans_table/trans_table_p.hpp
The table owns raw pattern blocks, so the implicit copy operations would
alias and later double-free them; delete them.

reserve_one_more() now attaches the grown block to its slot before
pooling the old one, and deletes the old block if pooling throws, so an
allocation failure at that point leaks nothing and keeps the byte
accounting exact.

Co-authored-by: Cursor <cursoragent@cursor.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Spare-pool bookkeeping is excluded from hard-limit accounting, allowing retained allocation to exceed the configured maximum.

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

library/src/trans_table/trans_table_p.cpp:174

  • The hard-cap calculation omits the backing allocations owned by spare_trees_. Those vectors grow when old blocks are pooled, and free_spare_trees() only calls clear(), so a large pooled table can retain megabytes of pointer storage after a MemoryExhausted reset or a lower maximum while dynamic_bytes() reports that the cap is satisfied. Include the spare-vector capacities in memory accounting and release or budget their capacity on hard-cap paths.
    library/src/trans_table/trans_table_p.cpp:26
  • This says equal-weight patterns are newest-first, but insertion walks past all equal-weight nonmatches before inserting, so they remain oldest-first. Update the comment (or change insertion ordering) so the documented lookup order matches the implementation.
  • Files reviewed: 13/13 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

…g note.

dynamic_bytes() now includes the capacity of the spare-block pointer
vectors, and free_spare_trees() (over-budget and teardown paths) releases
that capacity as well, so nothing the table retains escapes the hard cap.

Patterns of equal weight are scanned oldest first, as the insertion code
has always done; the file comment claimed newest first. A test now pins
the actual order.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tameware

Copy link
Copy Markdown
Collaborator Author

Addressed the two suppressed notes from the last review in 0338f36: dynamic_bytes() now counts the spare-pool pointer vectors' capacity and free_spare_trees() releases it on the hard-cap/teardown paths (test: PooledBlockPointerStorageCountsTowardsMemoryInUse); the file comment now says oldest-first among equal-weight patterns, matching the code, pinned by AmongEquallyGenericPatternsTheOlderIsTriedFirst.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Two moderate configuration and lifecycle issues in solver_context.cpp remain unresolved.

Review details

Suppressed comments (2)

library/src/solver_context/solver_context.cpp:289

  • When an already-created Pattern table is reconfigured with the unset defMB/maxMB values (for example configure_tt(TTKind::Pattern, 0, 0)), this same-kind path forwards zero to resize_tt. Lazy creation resolves zero to the built-in limits, but TransTableP::set_memory_maximum(0) leaves maximum_bytes_ == 0, so reserve_one_more()/grow_shapes() treat every allocation as over-budget and repeatedly clear the table. Normalize non-positive limits to the effective defaults (including DDS_TT_LIMIT_MB) before an in-place resize, or preserve the resolved live limits.
  if (tt_kind_of(tt) != tt_kind_from_environment(kind)) {

library/src/solver_context/solver_context.cpp:292

  • Recreating the table here loses the deal-specific init(hand_lookup) state. If this happens after a solve and the next solve uses the same deal, newDeal is false so SetDealTables is skipped; the fresh TransTableP has an empty ownership_, making every lookup miss and every add return at trans_table_p.cpp:606-610. Reinitialize a newly created table for the current deal (or otherwise preserve/replay the hand lookup) so reconfiguration does not silently disable the cache.
  if (tt_kind_of(tt) != tt_kind_from_environment(kind)) {
    dispose_trans_table();
    // Force immediate creation with new config to keep behavior explicit.
    (void)trans_table();
  • Files reviewed: 17/17 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

…ed TT on the next solve

- configure_tt() runs the same fill_unset_limits() as lazy creation, so
  configure_tt(kind, 0, 0) on a live table no longer sets a zero maximum
  that clears the table on every allocation (test first).
- dispose_trans_table() forgets the thread's remembered deal, so a table
  recreated between two solves of the same deal is init()-ed by the next
  solve instead of staying inert (test first, end to end via solve_board_pbn).

Co-authored-by: Cursor <cursoragent@cursor.com>
@tameware

Copy link
Copy Markdown
Collaborator Author

Suppressed findings from review 5185961798, both confirmed and fixed in c996b81:

  • configure_tt(Pattern, 0, 0) on a live table — the in-place path forwarded zero to set_memory_maximum, and with maximum_bytes_ == 0 every allocation was over budget (the table stayed empty). configure_tt now resolves non-positive limits with the same fill_unset_limits() as lazy creation before applying DDS_TT_LIMIT_MB. Test ReconfiguringALiveTableWithUnsetLimitsResolvesThem failed with 0 of 300 entries retained before the change.
  • Recreated table never init()-ed for the same dealdispose_trans_table() now forgets the thread's remembered deal (ThreadData::suit), so the next solve, even of the same cards, is a new deal and runs SetDealTables(). This covers the configure_tt recreate path, clear_tt() and lazy recreation alike. End-to-end test ATableRecreatedBetweenSolvesOfTheSameDealIsInitialisedAgain (solve, Large→Pattern round trip, solve again via solve_board_pbn) had node_count() == 0 on the second solve before the change; it now asserts the same score and a populated cache. Spec updated for both.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Cached patterns must be cleared when ownership is reinitialized to prevent results from a previous deal being reused.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 17/17 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread library/src/trans_table/trans_table_p.cpp
…on the relevant cards

Co-authored-by: Cursor <cursoragent@cursor.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The change modifies core solver caching behavior, and a documentation discrepancy remains unresolved.

Review details

Suppressed comments (1)

specs/transposition-table.md:74

  • This paragraph still says the header documents 0 as "unlimited" and that reconciling the Doxygen is out of scope, but this PR updates trans_table.hpp:134-136 to explicitly say 0 is unsupported. The spec now contradicts the API documentation; remove the stale header claim.
  header's doxygen is out of scope here.) On `TransTableP` only the maximum is a
  • Files reviewed: 17/17 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Co-authored-by: Cursor <cursoragent@cursor.com>
@tameware

Copy link
Copy Markdown
Collaborator Author

Suppressed finding from review 5186024081: the spec paragraph no longer claims the header calls 0 "unlimited"; it now says 0 is unsupported, matching the updated set_memory_default doxygen (47536f5).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The broad new default implementation warrants final human review, including clarification of the reset-memory documentation contract.

Review details

Suppressed comments (1)

library/src/trans_table/trans_table.hpp:97

  • This new implementation-specific memory section does not reconcile the inherited TransTable::reset_memory() contract below, which still says that reset structures are retained for reuse. TransTableP::reset_memory(ResetReason::MemoryExhausted) explicitly deletes active and pooled blocks, so the public Doxygen is contradictory for the new default implementation; qualify the base reset contract (or otherwise document the reason-specific exception).
/// Implementations use different memory strategies. TransTableP grows on
/// demand and clears itself when the next allocation would exceed the maximum,
/// TransTableL uses paged memory with harvesting, and TransTableS uses a
/// pool-based approach with malloc/calloc. All support configurable memory
/// limits and graceful degradation.
  • Files reviewed: 17/17 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

…ansTableP

Co-authored-by: Cursor <cursoragent@cursor.com>
@tameware

Copy link
Copy Markdown
Collaborator Author

Suppressed finding from review 5186170629: the base reset_memory doxygen now states the one exception to "structures are retained" — a MemoryExhausted reset on TransTableP returns the pattern blocks to the allocator (pooling them could allocate while over budget) and the table regrows on demand (6cb62ec).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It changes the default solver cache across core logic, lifecycle, API, tests, and build systems, warranting final human review.

Review details
  • Files reviewed: 17/17 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It replaces the default hot-path cache with substantial new solver-critical memory and matching logic that warrants final human review.

Review details
  • Files reviewed: 17/17 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@tameware tameware added the Clean Copilot review Copilot reviewed and had neither new comments nor new suppressed comments. label Sep 12, 2026

@zzcgumn zzcgumn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels promising. At some point we will have to consolidate to only have type of transposition table.

@tameware
tameware merged commit a946fad into dds-bridge:develop Sep 12, 2026
11 checks passed
@tameware
tameware deleted the fable/bridge-solver-shape-pattern-transposition branch September 12, 2026 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Clean Copilot review Copilot reviewed and had neither new comments nor new suppressed comments.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants