2021-09-01 11:47:21 +00:00
|
|
|
# SPDX-FileCopyrightText: 2021 ☭ Emery Hemingway
|
|
|
|
# SPDX-License-Identifier: Unlicense
|
2021-06-24 15:50:27 +00:00
|
|
|
|
|
|
|
## An unordered association of items to counts.
|
|
|
|
## An item count may be negative, unlike CountTable.
|
|
|
|
|
|
|
|
import tables
|
|
|
|
|
|
|
|
type
|
|
|
|
ChangeDescription* = enum
|
|
|
|
cdPresentToAbsent,
|
|
|
|
cdAbsentToAbsent,
|
|
|
|
cdAbsentToPresent,
|
|
|
|
cdPresentToPresent
|
|
|
|
|
|
|
|
Bag*[T] = Table[T, int]
|
|
|
|
|
|
|
|
proc change(count: var int; delta: int; clamp: bool): ChangeDescription =
|
|
|
|
var
|
|
|
|
oldCount = count
|
|
|
|
newCount = oldCount + delta
|
|
|
|
if clamp:
|
|
|
|
newCount = max(0, newCount)
|
|
|
|
if newCount == 0:
|
|
|
|
result =
|
|
|
|
if oldCount == 0: cdAbsentToAbsent
|
|
|
|
else: cdPresentToAbsent
|
|
|
|
else:
|
|
|
|
result =
|
|
|
|
if oldCount == 0: cdAbsentToPresent
|
|
|
|
else: cdPresentToPresent
|
|
|
|
count = newCount
|
|
|
|
|
|
|
|
proc change*[T](bag: var Bag[T]; key: T; delta: int; clamp = false): ChangeDescription =
|
|
|
|
assert(delta != 0)
|
|
|
|
result = change(bag.mGetOrPut(key, 0), delta, clamp)
|
|
|
|
if result in {cdAbsentToAbsent, cdPresentToAbsent}:
|
|
|
|
bag.del(key)
|
2022-03-10 23:30:07 +00:00
|
|
|
|
2023-07-20 17:31:02 +00:00
|
|
|
iterator items*[T](bag: Bag[T]): T =
|
|
|
|
for x in bag.keys: yield x
|
|
|
|
|
|
|
|
proc `$`*(bag: Bag): string =
|
|
|
|
result.add '{'
|
|
|
|
for x in bag.keys:
|
|
|
|
if result.len > 1: result.add ' '
|
|
|
|
result.add $x
|
|
|
|
result.add '}'
|
2024-03-01 14:05:03 +00:00
|
|
|
|
|
|
|
export tables.contains, tables.del, tables.len
|