code: protected void shift (int start)
      {
          // first, scan backwards to find the previous sentinel
          int mask = _buckets.length - 1;
          int sidx = start;
          while ((sidx = sidx + mask & mask) != start) {
              if (_buckets[sidx] == _sentinel) {
                  break;
              }
          }
  
          // then forwards to shift elements into place
          int idx = start, pidx = start;
          while ((idx = idx + 1 & mask) != start) {
              int bvalue = _buckets[idx];
              if (bvalue == _sentinel) {
                  _buckets[pidx] = _sentinel;
                  return;
              }
              int bidx = hash(bvalue) & mask;
              if (pidx > sidx ? (bidx > sidx && bidx <= pidx) : (bidx > sidx || bidx <= pidx)) {
                  _buckets[pidx] = bvalue;
                  pidx = idx;
              }
          }
  
          // we shouldn't get here
          throw new RuntimeException("Ran out of buckets fixing empty location at " + start);
      }
docs: Shifts elements over to fill a newly empty slot.  Anything between the previous sentinel and
  the empty slot (which moves as we shift elements), taking wrapping into account, needs to
  be checked and moved if necessary to ensure that it will be found by a search beginning at
  its hash-derived bucket index.  We stop when we encounter another sentinel.