class HashEntryStages<K> implements HashEntry<K>, ChecksumEntry {

    @StageRef
    public VanillaChronicleHashHolder<?> hh;
    @StageRef
    public SegmentStages s;
    @StageRef
    public CheckOnEachPublicOperation checkOnEachPublicOperation;
    @StageRef
    public HashLookupPos hlp;

    public long pos = -1;
    @Stage("EntryOffset")
    public long keySizeOffset = -1;
    public long keySize = -1;
    public long keyOffset = -1;
    public boolean delayedUpdateChecksum = false;
    @StageRef
    public EntryKeyBytesData<K> entryKey;
    @Stage("EntrySizeInChunks")
    public int entrySizeInChunks = 0;
    @StageRef
    HashEntryChecksumStrategy hashEntryChecksumStrategy;
    public final ChecksumStrategy checksumStrategy = hh.h().checksumEntries ?
            hashEntryChecksumStrategy : NoChecksumStrategy.INSTANCE;

    public void initPos(long pos) {
        this.pos = pos;
    }

    public abstract void closePos();

    public abstract boolean entryOffsetInit();

    public void initEntryOffset(long keySizeOffset) {
        this.keySizeOffset = keySizeOffset;
    }

    public void initEntryOffset() {
        keySizeOffset = s.entrySpaceOffset + pos * hh.h().chunkSize;
    }

    public abstract void closeEntryOffset();

    public void initKeySize(long keySize) {
        this.keySize = keySize;
    }

    public abstract void closeKeySize();

    public void initKeyOffset(long keyOffset) {
        this.keyOffset = keyOffset;
    }

    public abstract void closeKeyOffset();

    public void readExistingEntry(long pos) {
        initPos(pos);
        Bytes segmentBytes = s.segmentBytesForRead();
        segmentBytes.readPosition(keySizeOffset);
        initKeySize(hh.h().keySizeMarshaller.readSize(segmentBytes));
        initKeyOffset(segmentBytes.readPosition());
    }

    public void readFoundEntry(long pos, long keySizeOffset, long keySize, long keyOffset) {
        initPos(pos);
        initEntryOffset(keySizeOffset);
        initKeySize(keySize);
        initKeyOffset(keyOffset);
    }

    public void closeEntry() {
        closePos();
        closeEntryOffset();
        closeKeySize();
        closeKeyOffset();
    }

    public void writeNewEntry(long pos, Data<?> key) {
        initPos(pos);
        initKeySize(key.size());
        Bytes segmentBytes = s.segmentBytesForWrite();
        segmentBytes.writePosition(keySizeOffset);
        hh.h().keySizeMarshaller.writeSize(segmentBytes, keySize);
        initKeyOffset(segmentBytes.writePosition());
        key.writeTo(s.segmentBS, keyOffset);
    }

    public void copyExistingEntry(
            long newPos, long bytesToCopy, long oldKeyAddr, long oldKeySizeAddr) {
        initPos(newPos);
        initKeyOffset(keySizeOffset + (oldKeyAddr - oldKeySizeAddr));
        // Calling Access.copy() which is probably slower because not of abstractions,
        // because there is no BytesStore.write(off, addr, len) method. Alternative is
        // to make a final BytesStore rawMemoryStore = new PointerBytesStore().set(0, Long.MAX_V)
        // and here: s.segmentBS.write(keySizeOffset, rawMemoryStore, keySizeAddr, bytesToCopy)
        Access.copy(
                nativeAccess(), null, oldKeySizeAddr,
                checkedBytesStoreAccess(), s.segmentBS, keySizeOffset,
                bytesToCopy);
    }

    public long keyEnd() {
        return keyOffset + keySize;
    }

    public long entryEnd() {
        return keyEnd();
    }

    public void initDelayedUpdateChecksum(boolean delayedUpdateChecksum) {
        // makes delayedUpdateChecksum dependent on keySizeOffset and Locks stages, to trigger
        // delayedUpdateChecksum close on these stages' close
        assert entryOffsetInit() && keySizeOffset >= 0;
        assert s.locksInit() && s.localLockState != LocalLockState.UNLOCKED;
        assert delayedUpdateChecksum; // doesn't make sense to init to "uninit" false value
        this.delayedUpdateChecksum = true;
    }

    abstract boolean delayedUpdateChecksumInit();

    public void closeDelayedUpdateChecksum() {
        if (hh.h().checksumEntries)
            hashEntryChecksumStrategy.computeAndStoreChecksum();
        delayedUpdateChecksum = false;
    }

    @Override
    public void updateChecksum() {
        checkOnEachPublicOperation.checkOnEachPublicOperation();
        if (!hh.h().checksumEntries) {
            throw new UnsupportedOperationException(hh.h().toIdentityString() +
                    ": Checksum is not stored in this Chronicle Hash");
        }
        s.innerUpdateLock.lock();
        initDelayedUpdateChecksum(true);
    }

    @Override
    public boolean checkSum() {<FILL_FUNCTION_BODY>}

    long entrySize() {
        return checksumStrategy.extraEntryBytes() + entryEnd() - keySizeOffset;
    }

    @NotNull
    @Override
    public Data<K> key() {
        checkOnEachPublicOperation.checkOnEachPublicOperation();
        return entryKey;
    }

    void initEntrySizeInChunks() {
        entrySizeInChunks = hh.h().inChunks(entrySize());
    }

    public void initEntrySizeInChunks(int actuallyUsedChunks) {
        entrySizeInChunks = actuallyUsedChunks;
    }

    public void innerRemoveEntryExceptHashLookupUpdate() {
        s.free(pos, entrySizeInChunks);
        s.incrementModCount();
    }
}

        checkOnEachPublicOperation.checkOnEachPublicOperation();
        if (!hh.h().checksumEntries) {
            throw new UnsupportedOperationException(hh.h().toIdentityString() +
                    ": Checksum is not stored in this Chronicle Hash");
        }
        // This is needed, because a concurrent update lock holder might perform an entry update,
        // but not yet written a checksum (because checksum write is delayed to the update unlock).
        // So checkSum() on read lock level might result to false negative results.
        s.innerUpdateLock.lock();
        return delayedUpdateChecksumInit() || checksumStrategy.innerCheckSum();
    
<no_super_class>