let s:save_cpo = &cpo set cpo&vim let s:TRUE = !0 let s:FALSE = 0 function! s:set(...) abort return call(s:set._new, a:000, s:set) endfunction function! s:frozenset(...) abort return call(s:frozenset._new, a:000, s:frozenset) endfunction function! s:_hash_func(x) abort return a:x endfunction let s:_base_set = { \ '_is_set' : s:TRUE, \ '_data' : {}, \ '_hash_func' : function('s:_hash_func') \ } function! s:_base_set._new(...) abort let obj = deepcopy(self) let xs = get(a:, 1, []) let obj._hash_func = get(a:, 2, obj._hash_func) call obj._set_data(xs) return obj endfunction "" Return the union of two sets as a new set. " (I.e. all elements that are in either set.) function! s:_base_set.union(t) abort let r = deepcopy(self) call r._update(a:t) return r endfunction let s:_base_set.or = s:_base_set.union "" Return the intersection of two sets as a new set. " (I.e. all elements that are in both sets.) function! s:_base_set.intersection(t) abort let t = self._to_set(a:t) let [little, big] = self.len() <= t.len() ? [self, t] : [t, self] return self._new(filter(copy(big.to_list()), 'little.in(v:val)')) endfunction let s:_base_set.and = s:_base_set.intersection "" Return the symmetric difference of two sets as a new set. " (I.e. all elements that are in exactly one of the sets.) function! s:_base_set.symmetric_difference(t) abort let t = self._to_set(a:t) return self._new(filter(copy(self.to_list()), '!t.in(v:val)') \ + filter(copy(t.to_list()), '!self.in(v:val)')) endfunction let s:_base_set.xor = s:_base_set.symmetric_difference "" Return the difference of two sets as a new Set. function! s:_base_set.difference(t) abort let t = self._to_set(a:t) return self._new(filter(copy(self.to_list()), '!t.in(v:val)')) endfunction let s:_base_set.sub = s:_base_set.difference "" Report whether another set contains this set. function! s:_base_set.issubset(t) abort let t = self._to_set(a:t) return self.len() > t.len() ? s:FALSE \ : empty(filter(copy(self.to_list()), '!t.in(v:val)')) endfunction "" Report whether this set contains another set. function! s:_base_set.issuperset(t) abort let t = self._to_set(a:t) return self.len() < t.len() ? s:FALSE \ : empty(filter(copy(t.to_list()), '!self.in(v:val)')) endfunction " less than equal & greater than equal let s:_base_set.le = s:_base_set.issubset let s:_base_set.ge = s:_base_set.issuperset " less than function! s:_base_set.lt(t) abort let t = self._to_set(a:t) return self.len() < t.len() && self.issubset(t) endfunction " greater than function! s:_base_set.gt(t) abort let t = self._to_set(a:t) return self.len() > t.len() && self.issuperset(t) endfunction function! s:_base_set.len() abort return len(self._data) endfunction function! s:_base_set.to_list() abort return values(self._data) endfunction function! s:_base_set._update(xs) abort for X in (s:_is_set(a:xs) ? a:xs.to_list() : a:xs) call self._add(X) unlet X endfor endfunction function! s:_base_set._add(x) abort let key = self._hash(a:x) if !has_key(self._data, key) let self._data[key] = a:x endif endfunction " Report whether an element is a member of a set. function! s:_base_set.in(x) abort return has_key(self._data, self._hash(a:x)) endfunction function! s:_base_set._to_set(x) abort return s:_is_set(a:x) ? a:x : self._new(a:x) endfunction function! s:_base_set._clear() abort let self._data = {} endfunction function! s:_base_set._set_data(xs) abort call self._clear() call self._update(a:xs) endfunction function! s:_base_set._hash(x) abort return string(self._hash_func(a:x)) endfunction " frozenset: Immutable set class. let s:frozenset = deepcopy(s:_base_set) " Set: Mutable set class. let s:set = deepcopy(s:_base_set) " Update a set with the union of itself and another. function! s:set.update(iterable) abort call self._update(a:iterable) endfunction " Update a set with the union of itself and another. function! s:set.ior(t) abort call self.update(a:t) return self endfunction " Update a set with the intersection of itself and another. function! s:set.intersection_update(t) abort let r = self.and(a:t).to_list() call self.clear() call self.update(r) endfunction " Update a set with the intersection of itself and another. function! s:set.iand(t) abort call self.intersection_update(a:t) return self endfunction " Update a set with the symmetric difference of itself and another. function! s:set.symmetric_difference_update(t) abort let t = self._to_set(a:t) if self is t call self.clear() return endif for X in t.to_list() if self.in(X) call self.remove(X) else call self._add(X) endif unlet X endfor endfunction " Update a set with the symmetric difference of itself and another. function! s:set.ixor(t) abort call self.symmetric_difference_update(a:t) return self endfunction " Remove all elements of another set from this set. function! s:set.difference_update(t) abort let t = self._to_set(a:t) if self is t call self.clear() return endif for X in filter(t.to_list(), 'self.in(v:val)') call self.remove(X) unlet X endfor endfunction " Remove all elements of another set from this set. function! s:set.isub(t) abort call self.difference_update(a:t) return self endfunction " Remove all elements from this set. function! s:set.clear() abort call self._clear() endfunction "" Add an element to a set. " This has no effect if the element is already present. function! s:set.add(x) abort return self._add(a:x) endfunction "" Remove an element from a set; it must be a member. " If the element is not a member, throw Exception. function! s:set.remove(e) abort try unlet self._data[self._hash(a:e)] catch /^Vim\%((\a\+)\)\?:E716/ call s:_throw('the element is not a member') endtry endfunction "" Remove an element from a set if it is a member. " If the element is not a member, do nothing. function! s:set.discard(e) abort try call self.remove(a:e) catch /vital: Data.Set: the element is not a member/ " Do nothing endtry endfunction " Remove and return an arbitrary set element. function! s:set.pop() abort try let k = keys(self._data)[0] catch /^Vim\%((\a\+)\)\?:E684/ call s:_throw('set is empty') endtry let v = self._data[k] unlet self._data[k] return v endfunction " Helper: function! s:_is_set(x) abort return type(a:x) is type({}) && get(a:x, '_is_set', s:FALSE) endfunction function! s:_throw(message) abort throw 'vital: Data.Set: ' . a:message endfunction let &cpo = s:save_cpo unlet s:save_cpo " ___Revitalizer___ " NOTE: below code is generated by :Revitalize. " Do not mofidify the code nor append new lines if v:version > 703 || v:version == 703 && has('patch1170') function! s:___revitalizer_function___(fstr) abort return function(a:fstr) endfunction else function! s:___revitalizer_SID() abort return matchstr(expand(''), '\zs\d\+\ze____revitalizer_SID$') endfunction let s:___revitalizer_sid = '' . s:___revitalizer_SID() . '_' function! s:___revitalizer_function___(fstr) abort return function(substitute(a:fstr, 's:', s:___revitalizer_sid, 'g')) endfunction endif let s:___revitalizer_functions___ = {'set': s:___revitalizer_function___('s:set'),'frozenset': s:___revitalizer_function___('s:frozenset')} unlet! s:___revitalizer_sid delfunction s:___revitalizer_function___ function! vital#_easymotion#Data#Set#import() abort return s:___revitalizer_functions___ endfunction " ___Revitalizer___