@SuppressWarnings("unchecked")
  public E lookUp(K key) {
    if (count == 0) { // no entries in table
      return null;
    }
    int tableLen = values.length;
    int hash1 = hashFn1(key);
    int hash2 = hashFn2(key);
    int i = 0;
    E matchValue = null;
    // Case 2: - when table is full and the key not present
    while (values[hash1] != null && i++ <= tableLen) {
      if (DELETED.equals(values[hash1])) {
        continue; // nothing to be done
      }

      K k = ((Entry) values[hash1]).key;
      if (nullSafeEquals(key, k)) {
        matchValue = ((Entry) values[hash1]).element;
        break;
      }
      // compute next offset
      hash1 = (hash1 + hash2) % tableLen;
    }
    return matchValue;
  }
 @SuppressWarnings("unchecked")
 public void delete(K key) {
   if (count == 0) {
     return; // table is empty
   }
   int tableLen = values.length;
   int hash1 = hashFn1(key);
   int hash2 = hashFn2(key);
   int i = 0;
   while (values[hash1] != null && i++ < tableLen) {
     if (!DELETED.equals(values[hash1])) {
       K k = ((Entry) values[hash1]).key;
       if (nullSafeEquals(key, k)) {
         values[hash1] = DELETED;
         count--;
         break;
       }
     }
     // compute next offset
     hash1 = (hash1 + hash2) % tableLen;
   }
 }