Top-level multi-box packer with catalog box selection. Faithful port of BoxPacker's
Packer::doBasicPacking + getBoxList.
Greedy loop: sort items (largest first) and boxes (smallest first); while items remain,
trial-pack each candidate box (boxes that can hold all remaining items first) with
VolumePacker, pick the best packed box per the PackedBoxSorter, remove those items,
and repeat.
Options: :packed_box_sorter (module, default DefaultPackedBoxSorter),
:strict_ordering? (default false). Boxes implementing ExBoxPacker.LimitedSupplyBox
are only used up to their available quantity. Items implementing ExBoxPacker.LinkedItem
are kept together as linked-item groups (a linked group is never split across boxes).
:timeout (number of SECONDS, default nil = unbounded) bounds packing time. When set,
ExBoxPacker.TimeoutError is raised (it propagates from pack/3, pack!/3 and
pack_all_possible/3) once the deadline is exceeded during the per-box trial-packing loop.
Port of BoxPacker's TimeoutChecker/DefaultTimeoutChecker.
Summary
Functions
@spec pack([ExBoxPacker.Box.t()], [ExBoxPacker.Item.t()], keyword()) :: {:ok, ExBoxPacker.Result.PackedBoxList.t()} | {:error, Exception.t()}
Pack items into the fewest boxes. Returns {:ok, PackedBoxList} or {:error, NoBoxesAvailableError}.
@spec pack!([ExBoxPacker.Box.t()], [ExBoxPacker.Item.t()], keyword()) :: ExBoxPacker.Result.PackedBoxList.t()
Like pack/3 but returns the PackedBoxList directly or raises NoBoxesAvailableError.
@spec pack_all_possible([ExBoxPacker.Box.t()], [ExBoxPacker.Item.t()], keyword()) :: {ExBoxPacker.Result.PackedBoxList.t(), [ExBoxPacker.Item.t()]}
Pack as much as possible; never errors. Returns {PackedBoxList, leftover_items}.