pragma solidity >=0.4.9 <0.6.0;

library Set {
  // We define a new struct datatype that will be used to
  // hold its data in the calling contract.
  struct Data { mapping(uint => bool) flags; }

  // Note that the first parameter is of type "storage
  // reference" and thus only its storage address and not
  // its contents is passed as part of the call.  This is a
  // special feature of library functions.  It is idiomatic
  // to call the first parameter 'self', if the function can
  // be seen as a method of that object.
  function insert(Data storage self, uint value) public
      returns (bool)
  {
      if (self.flags[value])
          return false; // already there
        self.flags[value] = true;

      return true;
  }

  function remove(Data storage self, uint value) public
      returns (bool)
  {
      if (!self.flags[value])
          return false; // not there
      self.flags[value] = false;
      return true;
  }

  function contains(Data storage self, uint value) public
      returns (bool)
  {
      return self.flags[value];
  }
}


contract C {
    Set.Data knownValues;

    function register(uint value) public {
        // The library functions can be called without a
        // specific instance of the library, since the
        // "instance" will be the current contract.
        address payable a;
        a.send(10 wei);
        if (!Set.insert(knownValues, value))
            revert();
    }

    // In this contract, we can also directly access knownValues.flags, if we want.
}