You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 7c9bafe
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: CLAUDE.md
+24-22Lines changed: 24 additions & 22 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -450,18 +450,19 @@ Callers can access the intermediate dictionary by setting the `dontdraw` options
450
450
451
451
### Ghostscript Observed Behaviour
452
452
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
456
459
457
460
458
461
### Optimization Patterns
459
462
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`)
- 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`
465
466
466
467
**Conditional Assignment Pattern**
467
468
@@ -480,13 +481,13 @@ condition {
480
481
```
481
482
482
483
483
-
**"Switch" blocks (short circuit)**
484
+
**"Switch" blocks (common exit)**
484
485
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.
487
488
488
489
```postscript
489
-
% Bad: Hard to modify
490
+
% Nested ifelse (faster, harder to modify)
490
491
condition1 {
491
492
/c1
492
493
} {
@@ -496,7 +497,7 @@ condition2 {
496
497
/default
497
498
} ifelse ... } ifelse
498
499
499
-
% Good: Clarity
500
+
% Common exit (slower, easier to maintain)
500
501
1 { % Common exit
501
502
condition1 { /c1 exit } if
502
503
condition2 { /c2 exit } if
@@ -590,25 +591,26 @@ elements, then repacking.
590
591
} for
591
592
```
592
593
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):
594
596
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
+
```
598
603
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`.
602
605
603
606
Extension of small arrays with `aload pop` is acceptable for one-time
604
607
operations outside loops.
605
608
606
609
607
610
**Hot Loop Stack Pattern**
608
611
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.
0 commit comments