docs: def compare_dict_iter(propval_a, propval_b, fs_a=None, fs_b=None,
                        options=None):
      """Generator for comparing 'simple' dicts when they are encountered.  This
      does not currently recurse further.  Arguments are as per other
      ``compare_``\ *X* functions.
      """
      if fs_a is None:
          fs_a = FieldSelector(tuple())
          fs_b = FieldSelector(tuple())
      if not options:
          options = DiffOptions()
      propvals = dict(a=propval_a, b=propval_b)
      values = dict()
      rev_keys = dict()
      for x in "a", "b":
          propval_x = propvals[x]
          vals = values[x] = set()
          rev_key = rev_keys[x] = dict()
          seen = collections.Counter()
          for k, v in collection_generator(propval_x):
              v = options.normalize_item(
                  v, propval_a if options.duck_type else propval_x
              )
              if not v.__hash__:
                  v = repr(v)
              if v is not _nothing or not options.ignore_empty_slots:
                  vals.add((v, seen[v]))
                  rev_key[(v, seen[v])] = k
                  seen[v] += 1
  
      removed = values['a'] - values['b']
      added = values['b'] - values['a']
  
      if options.moved or options.unchanged:
          unchanged = values['a'] & values['b']
          for v, seq in unchanged:
              a_key = rev_keys['a'][v, seq]
              b_key = rev_keys['b'][v, seq]
              if options.moved and a_key != b_key:
                  yield DiffInfo(
                      diff_type=DiffTypes.MOVED,
                      base=fs_a + [a_key],
                      other=fs_b + [b_key],
                  )
              elif options.unchanged:
                  yield DiffInfo(
                      diff_type=DiffTypes.NO_CHANGE,
                      base=fs_a + [a_key],
                      other=fs_b + [b_key],
                  )
  
      removed_keys = set(rev_keys['a'][v, seq] for v, seq in removed)
      added_keys = set(rev_keys['b'][v, seq] for v, seq in added)
      modified_keys = set(removed_keys.intersection(added_keys))
  
      for v, seq in removed:
          a_key = rev_keys['a'][v, seq]
          if a_key in modified_keys:
              continue
          selector = fs_a + [a_key]
          yield DiffInfo(
              diff_type=DiffTypes.REMOVED,
              base=selector,
              other=fs_b,
          )
  
      for v, seq in added:
          b_key = rev_keys['b'][v, seq]
          if b_key in modified_keys:
              continue
          selector = fs_b + [b_key]
          yield DiffInfo(
              diff_type=DiffTypes.ADDED,
              base=fs_a,
              other=selector,
          )
  
      for key in modified_keys:
          yield DiffInfo(
              diff_type=DiffTypes.MODIFIED,
              base=fs_a + [key],
              other=fs_b + [key],
          )