docs: @Override
     public InternalCacheEntry<WrappedBytes, WrappedBytes> fromMemory(long address) {
        // 16 bytes for eviction if needed (optional)
        // 8 bytes for linked pointer
        int offset = evictionEnabled ? 24 : 8;
  
        byte metadataType = MEMORY.getByte(address, offset);
        offset += 1;
        int hashCode = MEMORY.getInt(address, offset);
        offset += 4;
        byte[] keyBytes = new byte[MEMORY.getInt(address, offset)];
        offset += 4;
  
        byte[] metadataBytes;
        switch (metadataType) {
           case IMMORTAL:
              metadataBytes = Util.EMPTY_BYTE_ARRAY;
              break;
           case MORTAL:
              metadataBytes = new byte[16];
              break;
           case TRANSIENT:
              metadataBytes = new byte[16];
              break;
           case TRANSIENT_MORTAL:
              metadataBytes = new byte[32];
              break;
           default:
              // This means we had CUSTOM or HAS_VERSION so we have to read it all
              metadataBytes = new byte[MEMORY.getInt(address, offset)];
              offset += 4;
        }
  
        byte[] valueBytes = new byte[MEMORY.getInt(address, offset)];
        offset += 4;
  
        MEMORY.getBytes(address, offset, keyBytes, 0, keyBytes.length);
        offset += keyBytes.length;
        MEMORY.getBytes(address, offset, metadataBytes, 0, metadataBytes.length);
        offset += metadataBytes.length;
        MEMORY.getBytes(address, offset, valueBytes, 0, valueBytes.length);
        offset += valueBytes.length;
  
        Metadata metadata;
        // This is a custom metadata
        if ((metadataType & CUSTOM) == CUSTOM) {
           try {
              metadata = (Metadata) marshaller.objectFromByteBuffer(metadataBytes);
           } catch (IOException | ClassNotFoundException e) {
              throw new CacheException(e);
           }
           return internalEntryFactory.create(new WrappedByteArray(keyBytes, hashCode),
                 new WrappedByteArray(valueBytes), metadata);
        } else {
           long lifespan;
           long maxIdle;
           long created;
           long lastUsed;
           offset = 0;
           boolean hasVersion = (metadataType & HAS_VERSION) == HAS_VERSION;
           // Ignore CUSTOM and VERSION to find type
           switch (metadataType & 0xFC) {
              case IMMORTAL:
                 lifespan = -1;
                 maxIdle = -1;
                 created = -1;
                 lastUsed = -1;
                 break;
              case MORTAL:
                 maxIdle = -1;
                 lifespan = Bits.getLong(metadataBytes, offset);
                 created = Bits.getLong(metadataBytes, offset += 8);
                 lastUsed = -1;
                 break;
              case TRANSIENT:
                 lifespan = -1;
                 maxIdle = Bits.getLong(metadataBytes, offset);
                 created = -1;
                 lastUsed = Bits.getLong(metadataBytes, offset += 8);
                 break;
              case TRANSIENT_MORTAL:
                 lifespan = Bits.getLong(metadataBytes, offset);
                 maxIdle = Bits.getLong(metadataBytes, offset += 8);
                 created = Bits.getLong(metadataBytes, offset += 8);
                 lastUsed = Bits.getLong(metadataBytes, offset += 8);
                 break;
              default:
                 throw new IllegalArgumentException("Unsupported type: " + metadataType);
           }
           if (hasVersion) {
              try {
                 EntryVersion version = (EntryVersion) marshaller.objectFromByteBuffer(metadataBytes, offset,
                       metadataBytes.length - offset);
                 return internalEntryFactory.create(new WrappedByteArray(keyBytes, hashCode),
                       new WrappedByteArray(valueBytes), version, created, lifespan, lastUsed, maxIdle);
              } catch (IOException | ClassNotFoundException e) {
                 throw new CacheException(e);
              }
           } else {
              return internalEntryFactory.create(new WrappedByteArray(keyBytes, hashCode),
                    new WrappedByteArray(valueBytes), (Metadata) null, created, lifespan, lastUsed, maxIdle);
           }
        }
     }