Skip to content

Commit 7c9bafe

Browse files
committed
Update CLAUDE.md
1 parent 18cd525 commit 7c9bafe

1 file changed

Lines changed: 24 additions & 22 deletions

File tree

‎CLAUDE.md‎

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -450,18 +450,19 @@ Callers can access the intermediate dictionary by setting the `dontdraw` options
450450

451451
### Ghostscript Observed Behaviour
452452

453-
- Each `/name value def` has fixed cost; name lookup has similar cost
454-
- Basic stack ops (pop, index, roll) have similar cost to dict ops
455-
- Consecutive stack operations have small marginal cost after initial op
453+
- Dict reads are ~1.3x faster than stack `index`; writes (`def`) are ~1.25x slower than reads
454+
- Stack manipulation wins by avoiding `def`, not by faster access
455+
- `forall` avoids per-iteration `get` overhead compared to `for` + `get`
456+
- `N index` cost is independent of stack depth
457+
- `getinterval` cost is fixed regardless of size (returns a view, not a copy)
458+
- String literals `(...)` are allocated at definition time; array `[...]` and dict `<<...>>` literals are allocated at execution time
456459

457460

458461
### Optimization Patterns
459462

460-
- Use `//name` immediate lookup for static data (avoids runtime structure allocation cost)
463+
- Use `//name` immediate lookup for static data (avoids runtime allocation and dictionary lookups); use directly rather than creating local aliases (e.g., `//encoder.fnc1` not `/fnc1 //encoder.fnc1 def`)
461464
- Defer expensive computation to lazy init (first-run cost, cached thereafter)
462-
- Prefer stack manipulation over creating intermediate dictionaries
463-
- Use immediate references directly instead of creating local aliases (e.g., use `//encoder.fnc1` directly rather than `/fnc1 //encoder.fnc1 def`). This saves runtime dictionary lookups.
464-
- When latevars needs a helper function to compute values, define it in static scope (ensure to bind it; see `auspost.rsprod`) and reference via `//encoder.helper exec` in latevars to save lookups.
465+
- When latevars needs a helper function, define it in static scope (bind it; see `auspost.rsprod`) and reference via `//encoder.helper exec`
465466

466467
**Conditional Assignment Pattern**
467468

@@ -480,13 +481,13 @@ condition {
480481
```
481482

482483

483-
**"Switch" blocks (short circuit)**
484+
**"Switch" blocks (common exit)**
484485

485-
Long `ifelse` chains should be avoided by using a "common exit" pattern,
486-
clearly denoted by a comment on the first line:
486+
Long `ifelse` chains can be replaced with a "common exit" pattern for
487+
maintainability. Nested ifelse avoids the `repeat`/`exit` overhead, so prefer it in hot paths.
487488

488489
```postscript
489-
% Bad: Hard to modify
490+
% Nested ifelse (faster, harder to modify)
490491
condition1 {
491492
/c1
492493
} {
@@ -496,7 +497,7 @@ condition2 {
496497
/default
497498
} ifelse ... } ifelse
498499
499-
% Good: Clarity
500+
% Common exit (slower, easier to maintain)
500501
1 { % Common exit
501502
condition1 { /c1 exit } if
502503
condition2 { /c2 exit } if
@@ -590,25 +591,26 @@ elements, then repacking.
590591
} for
591592
```
592593

593-
It can be difficult to determine the required size for an array in advance.
594+
When array size isn't known in advance, `mark ... counttomark array astore` is
595+
fastest (~2x faster than pre-allocate, ~5x faster than aload rebuild):
594596

595-
It is sometimes necessary to over-size the array and later take the used prefix
596-
of the array with `/arr arr 0 len getinterval def`, but there is an associated
597-
cost of allocating a new array and copying the used elements.
597+
```postscript
598+
mark
599+
0 1 n 1 sub { computeValue } for
600+
counttomark array astore
601+
/result exch def
602+
```
598603

599-
Adding elements to the stack and later constructing the array (`mark ...
600-
counttomark array store /arr exch def`) might be preferable when the array size
601-
isn't known in advance.
604+
If size is bounded, over-size then trim with `getinterval`.
602605

603606
Extension of small arrays with `aload pop` is acceptable for one-time
604607
operations outside loops.
605608

606609

607610
**Hot Loop Stack Pattern**
608611

609-
In high computational complexity loops, avoid `/idx exch def`. Keep loop index
610-
on stack, reference with `index` and finally consume with `roll` (rather than
611-
`pop`):
612+
In hot loops, avoid `/idx exch def` which incurs `def` overhead each iteration.
613+
Keep loop index on stack instead:
612614

613615
```postscript
614616
% Bad: Creates dictionary entry each iteration

0 commit comments

Comments
 (0)