code: def AddItem(self, item, f=lambda x: x):
      
      with self._mutex:
        if len(self.items) < self._max_size or self._max_size == 0:
          self.items.append(f(item))
        else:
          r = self._random.randint(0, self._num_items_seen)
          if r < self._max_size:
            self.items.pop(r)
            self.items.append(f(item))
          elif self.always_keep_last:
            self.items[-1] = f(item)
        self._num_items_seen += 1
docs: Add an item to the ReservoirBucket, replacing an old item if necessary.
  
      The new item is guaranteed to be added to the bucket, and to be the last
      element in the bucket. If the bucket has reached capacity, then an old item
      will be replaced. With probability (_max_size/_num_items_seen) a random item
      in the bucket will be popped out and the new item will be appended
      to the end. With probability (1 - _max_size/_num_items_seen)
      the last item in the bucket will be replaced.
  
      Since the O(n) replacements occur with O(1/_num_items_seen) likelihood,
      the amortized runtime is O(1).
  
      Args:
        item: The item to add to the bucket.
        f: A function to transform item before addition, if it will be kept in
          the reservoir.