protected final void writeStreamHeader() throws IOException {
            if (_classDescriptor == null)
                super.writeStreamHeader();
        }
    }

    DefaultValueCoder getCurrentCoder() {
        return _currentCoder;
    }

    Object getCurrentObject() {
        return _currentObject;
    }

    void setCurrentCoder(DefaultValueCoder coder) {
        _currentCoder = coder;
    }

    void setCurrentObject(Object object) {
        _currentObject = object;
    }

    private ValueCache getValueCache() {
        if (_valueCache == null && _valueCacheWeakRef != null) {
            _valueCache = _valueCacheWeakRef.get();
        }
        if (_valueCache == null) {
            _valueCache = new ValueCache();
            _valueCacheWeakRef = new WeakReference<ValueCache>(_valueCache);
        }
        return _valueCache;
    }

    private void releaseValueCache() {
        _serializedItemCount = 0;
        if (_valueCache != null) {
            _valueCache.clear();
            // Clear the hard reference.
            _valueCache = null;
        }
    }

    /**
     * Holds a collection of Object values associated with their position within
     * the serialized Value. Used only during get and put operations so that
     * reference graphs with cycles can be encoded and decoded properly. A
     * Persistit instance has a collection of ValueCache objects that get() and
     * put() operations allocate and relinquish when done.
     */
    static class ValueCache {
        private final static int INITIAL_SIZE = 256;

        /**
         * handle -> Object
         */
        Object[] _array = new Object[INITIAL_SIZE];

        int _handleCount = 0;

        ValueCache() {
            clear();
        }

        /**
         * Look up the handle for an Object that has already been stored in this
         * Value.
         * 
         * @param object
         * @return The handle, or -1 if the object has not been stored yet.
         */
        int lookup(Object object) {
            for (int index = _handleCount; --index >= 0;) {
                if (_array[index] == object) {
                    return index;
                }
            }
            return -1;
        }

        /**
         * Get the object stored with the supplied handle value.
         * 
         * @param handle
         * @return The object
         */
        Object get(int handle) {
            return _array[handle];
        }

        /**
         * Record the association between the supplied handle and object values.
         * Subsequent lookup and get operations will then be able to find this
         * object or fetch it by handle.
         * 
         * @param handle
         * @param object
         * @return previous handle, or -1 if none
         */
        void store(int handle, Object object) {
            if (handle >= _array.length)
                grow(1 + handle * 2);
            if (handle >= _handleCount) {
                _handleCount = handle + +1;
            }
            _array[handle] = object;
        }

        int put(int handle, Object object) {
            int previous = lookup(object);
            if (previous != -1) {
                return previous;
            }
            store(handle, object);
            return -1;
        }

        /**
         * Enlarges the backing arrays to support more objects
         */
        void grow(int newSize) {
            Object[] temp = _array;
            _array = new Object[newSize];
            System.arraycopy(temp, 0, _array, 0, temp.length);
        }

        /**
         * Clears all object/handle associations.
         */
        void clear() {
            for (int index = _handleCount; --index >= 0;) {
                _array[index] = null;
            }
            _handleCount = 0;
        }
    }

    private static class DisplayMarker {
        int _start;

        DisplayMarker(int start) {
            _start = start;
        }

        public String toString() {
            return "@" + Integer.toString(_start);
        }
    }

    static class Version {
        private final long _versionHandle;
        private final long _commitTimestamp;
        private final Value _value;

        private Version(long versionHandle, long commitTimestamp, Value value) {
            _versionHandle = versionHandle;
            _commitTimestamp = commitTimestamp;
            _value = value;
        }

        /**
         * @return the versionHandle
         */
        public long getVersionHandle() {
            return _versionHandle;
        }

        /**
         * @return the commitTimestamp
         */
        public long getCommitTimestamp() {
            return _commitTimestamp;
        }

        /**
         * @return the value
         */
        public Value getValue() {
            return _value;
        }

        public long getStartTimestamp() {
            return TransactionIndex.vh2ts(_versionHandle);
        }

        public int getStep() {
            return TransactionIndex.vh2step(_versionHandle);
        }

        public String toString() {
            try {
                StringBuilder sb = new StringBuilder();
                sb.append(String.format("%,d", getStartTimestamp()));
                if (getStep() > 0) {
                    sb.append(String.format("#%02d", getStep()));
                }
                sb.append("<" + TransactionStatus.tcString(_commitTimestamp) + ">");
                sb.append(":");
                sb.append(_value);
                return sb.toString();
            } catch (Exception e) {
                e.printStackTrace();
                return e.toString();
            }
        }
    }

    /**
     * Construct a list of <code>Version</code> objects, each denoting one of
     * the multi-value versions currently held in this Value object.
     * 
     * @return the list of <code>Version<code>s
     * @throws PersistitException
     */
    List<Version> unpackMvvVersions() throws PersistitException {
        final List<Version> versions = new ArrayList<Version>();
        MVV.VersionVisitor visitor = new MVV.VersionVisitor() {

            @Override
            public void sawVersion(long version, int valueOffset, int valueLength) {
                long tc = -1;

                try {
                    tc = _persistit.getTransactionIndex().commitStatus(version, TransactionStatus.UNCOMMITTED, 0);
                } catch (Exception e) {
                    tc = -1;
                }
                Value value = new Value(_persistit);
                value.ensureFit(valueLength);
                System.arraycopy(_bytes, valueOffset, value.getEncodedBytes(), 0, valueLength);
                value.setEncodedSize(valueLength);
                value.trim();
                versions.add(new Version(version, tc, value));
            }

            @Override
            public void init() throws PersistitException {

            }
        };
        MVV.visitAllVersions(visitor, getEncodedBytes(), 0, getEncodedSize());
        return versions;
    }

    private void putCharSequenceInternal(CharSequence string) {
        int length = string.length();
        ensureFit(length + 1);
        final int saveSize = _size;
        int index = _size;
        _bytes[index++] = (byte) CLASS_STRING;

        int maxLength = _bytes.length;

        for (int i = 0; i < length; i++) {
            char c = string.charAt(i);

            if (c <= 0x007F) {
                if (index + 1 > maxLength) {
                    _size = index;
                    ensureFit(index + 1 + (length - i) * 2);
                    maxLength = _bytes.length;
                }
                _bytes[index++] = (byte) c;
            } else if (c > 0x07FF) {
                if (index + 3 > maxLength) {
                    _size = index;
                    ensureFit(index + 3 + (length - i) * 2);
                    maxLength = _bytes.length;
                }
                _bytes[index++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
                _bytes[index++] = (byte) (0x80 | ((c >> 6) & 0x3F));
                _bytes[index++] = (byte) (0x80 | ((c >> 0) & 0x3F));
            } else {
                if (index + 2 > maxLength) {
                    _size = index;
                    ensureFit(index + 2 + (length - i) * 2);
                    maxLength = _bytes.length;
                }
                _bytes[index++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
                _bytes[index++] = (byte) (0x80 | ((c >> 0) & 0x3F));
            }
        }