text: from ._skiplist import ffi, lib
  
  
  _undefined = object()
  
  
  class ObjectRef(object):
  
      def __init__(self):
          self.__alloc = ffi.new('uintptr_t **')
          self.ref = ffi.cast('void **', self.__alloc)
  
      @property
      def handle(self):
          return ffi.cast('void *', self.ref[0])
  
      @property
      def deref(self):
          return ffi.from_handle(self.handle)
  
  
  class SkipDict(object):
  
      __slots__ = ('__list', '__pointers')
  
      def __init__(self):
          self.__list = ffi.new('skiplist_skiplist *')
          self.__pointers = set()
          init_err = lib.skiplist_init(
              self.__list,
              ffi.addressof(lib, 'skiplist_int64_cmp'),
              # Null `void *userdata` for cmp and malloc functions.
              ffi.NULL,
              ffi.NULL)
          if init_err:
              raise RuntimeError("Error initializing skiplist")
  
      def __del__(self):
          lib.skiplist_free(self.__list)
  
      def __repr__(self):
          return 'SkipDict({' + ', '.join('{!r}: {!r}'.format(k, v) for k, v in self.iteritems()) + '})'
  
      def __len__(self):
          return lib.skiplist_size(self.__list)
  
      def __contains__(self, k):
          return bool(lib.skiplist_find(self.__list, k, ffi.NULL))
  
      def __nonzero__(self):
          return len(self) > 0
  
      def __getitem__(self, k):
          result = lib.skiplist_get(self.__list, k, ffi.NULL)
          if result == ffi.NULL:
              raise KeyError(k)
          return ffi.from_handle(result)
  
      def get(self, k, default=None):
          result = lib.skiplist_get(self.__list, k, ffi.NULL)
          if result == ffi.NULL:
              return default
          return ffi.from_handle(result)
  
      def __setitem__(self, k, value):
          handle = ffi.new_handle(value)
          self.__pointers.add(handle)
          prev = ObjectRef()
          did_overwrite = lib.skiplist_insert(self.__list, k, handle, prev.ref)
          if did_overwrite:
              self.__pointers.discard(prev.handle)
  
      def __delitem__(self, k):
          prev = ObjectRef()
          did_remove = lib.skiplist_remove(self.__list, k, prev.ref)
          if not did_remove:
              raise KeyError(k)
          self.__pointers.discard(prev.handle)
  
      def pop(self, k, default=_undefined):
          prev = ObjectRef()
          did_remove = lib.skiplist_remove(self.__list, k, prev.ref)
          if not did_remove:
              if default is _undefined:
                  raise KeyError(k)
              return default
          popped = prev.deref
          self.__pointers.discard(prev.handle)
          return popped
  
      def __iter__(self):
          for k, v in self.iteritems():
              yield k
  
      def iteritems(self):
          node = self.__list.head
          while node.next[0]:
              yield (node.next[0].key, ffi.from_handle(node.next[0].val))
              node = node.next[0]
  
      def minimum(self):
          key_pointer = ffi.new('int64_t *')
          val_ref = ObjectRef()
          has_result = lib.skiplist_min(self.__list, key_pointer, val_ref.ref)
          if not has_result:
              return None
          return (key_pointer[0], val_ref.deref)
  
      def maximum(self):
          key_pointer = ffi.new('int64_t *')
          val_ref = ObjectRef()
          has_result = lib.skiplist_max(self.__list, key_pointer, val_ref.ref)
          if not has_result:
              return None
          return (key_pointer[0], val_ref.deref)
  
      def pop_minimum(self):
          key_pointer = ffi.new('int64_t *')
          val_ref = ObjectRef()
          has_result = lib.skiplist_pop(self.__list, key_pointer, val_ref.ref)
          if not has_result:
              return None
          output = (key_pointer[0], val_ref.deref)
          self.__pointers.discard(val_ref.handle)
          return output
  
      def pop_maximum(self):
          key_pointer = ffi.new('int64_t *')
          val_ref = ObjectRef()
          has_result = lib.skiplist_shift(self.__list, key_pointer, val_ref.ref)
          if not has_result:
              return None
          output = (key_pointer[0], val_ref.deref)
          self.__pointers.discard(val_ref.handle)
          return output
  