/// <summary>
        ///     Remove the number of {@link IByteBuffer}s starting from the given index.
        ///     @param cIndex the index on which the {@link IByteBuffer}s will be started to removed
        ///     @param numComponents the number of components to remove
        /// </summary>
        public CompositeByteBuffer RemoveComponents(int cIndex, int numComponents)
        {
            this.CheckComponentIndex(cIndex, numComponents);

            if (numComponents == 0)
            {
                return(this);
            }
            bool needsUpdate = false;

            for (int i = cIndex + numComponents; i >= cIndex; i--)
            {
                ComponentEntry c = this.components[i];
                needsUpdate |= c.Length > 0;
                c.FreeIfNecessary();
                this.components.RemoveAt(i);
            }

            if (needsUpdate)
            {
                // Only need to call updateComponentOffsets if the length was > 0
                this.UpdateComponentOffsets(cIndex);
            }
            return(this);
        }
        /// <summary>
        ///     Consolidate the composed {@link IByteBuffer}s
        ///     @param cIndex the index on which to start to compose
        ///     @param numComponents the number of components to compose
        /// </summary>
        public CompositeByteBuffer Consolidate(int cIndex, int numComponents)
        {
            this.CheckComponentIndex(cIndex, numComponents);
            if (numComponents <= 1)
            {
                return(this);
            }

            int            endCIndex    = cIndex + numComponents;
            ComponentEntry last         = this.components[endCIndex - 1];
            int            capacity     = last.EndOffset - this.components[cIndex].Offset;
            IByteBuffer    consolidated = this.AllocateBuffer(capacity);

            for (int i = cIndex; i < endCIndex; i++)
            {
                ComponentEntry c = this.components[i];
                IByteBuffer    b = c.Buffer;
                consolidated.WriteBytes(b);
                c.FreeIfNecessary();
            }

            this.components.RemoveRange(cIndex + 1, endCIndex - cIndex);
            this.components[cIndex] = new ComponentEntry(consolidated);
            this.UpdateComponentOffsets(cIndex);
            return(this);
        }
        /// <summary>
        ///     This should only be called as last operation from a method as this may adjust the underlying
        ///     array of components and so affect the index etc.
        /// </summary>
        void ConsolidateIfNeeded()
        {
            // Consolidate if the number of components will exceed the allowed maximum by the current
            // operation.
            int numComponents = this.components.Count;

            if (numComponents > this.maxNumComponents)
            {
                int capacity = this.components[numComponents - 1].EndOffset;

                IByteBuffer consolidated = this.AllocateBuffer(capacity);

                // We're not using foreach to avoid creating an iterator.
                for (int i = 0; i < numComponents; i++)
                {
                    ComponentEntry c1 = this.components[i];
                    IByteBuffer    b  = c1.Buffer;
                    consolidated.WriteBytes(b);
                    c1.FreeIfNecessary();
                }
                var c = new ComponentEntry(consolidated);
                c.EndOffset = c.Length;
                this.components.Clear();
                this.components.Add(c);
            }
        }
        /// <summary>
        ///     Consolidate the composed {@link IByteBuffer}s
        /// </summary>
        public CompositeByteBuffer Consolidate()
        {
            this.EnsureAccessible();
            int numComponents = this.NumComponents;

            if (numComponents <= 1)
            {
                return(this);
            }

            ComponentEntry last         = this.components[numComponents - 1];
            int            capacity     = last.EndOffset;
            IByteBuffer    consolidated = this.AllocateBuffer(capacity);

            for (int i = 0; i < numComponents; i++)
            {
                ComponentEntry c = this.components[i];
                IByteBuffer    b = c.Buffer;
                consolidated.WriteBytes(b);
                c.FreeIfNecessary();
            }

            this.components.Clear();
            this.components.Add(new ComponentEntry(consolidated));
            this.UpdateComponentOffsets(0);
            return(this);
        }
        /// <summary>
        ///     Remove the {@link IByteBuffer} from the given index.
        ///     @param cIndex the index on from which the {@link IByteBuffer} will be remove
        /// </summary>
        public CompositeByteBuffer RemoveComponent(int cIndex)
        {
            this.CheckComponentIndex(cIndex);
            ComponentEntry comp = this.components[cIndex];

            this.components.RemoveAt(cIndex);
            comp.FreeIfNecessary();
            if (comp.Length > 0)
            {
                // Only need to call updateComponentOffsets if the length was > 0
                this.UpdateComponentOffsets(cIndex);
            }
            return(this);
        }