⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 auto_buffer.hpp

📁 用STL的方式封装了WindowsAPI、COM调用、ACE、ATL、MFC、WTL等多种组件
💻 HPP
📖 第 1 页 / 共 3 页
字号:
#else /* ? STLSOFT_LF_ALLOCATOR_ALLOCATE_HAS_HINT */
        return get_allocator().allocate(cItems);
#endif /* STLSOFT_LF_ALLOCATOR_ALLOCATE_HAS_HINT */
    }

    void deallocate_(pointer p, size_type cItems)
    {
        STLSOFT_ASSERT(NULL != p);

#ifdef STLSOFT_LF_ALLOCATOR_DEALLOCATE_HAS_COUNT
        get_allocator().deallocate(p, cItems);
#else /* ? STLSOFT_LF_ALLOCATOR_DEALLOCATE_HAS_COUNT */
        STLSOFT_SUPPRESS_UNUSED(cItems);

        get_allocator().deallocate(p);
#endif /* STLSOFT_LF_ALLOCATOR_DEALLOCATE_HAS_COUNT */
    }

    pointer reallocate_(pointer p, size_type cItems, size_type cNewItems)
    {
        pointer new_p   =   allocate_(cNewItems, p);

        // This test is needed, since some allocators may not throw
        // bad_alloc
        if(NULL != new_p)
        {
            block_copy(new_p, p, cItems);

            deallocate_(p, cItems);
        }

        return new_p;
    }
protected:
    static void block_copy(pointer dest, const_pointer src, size_type cItems)
    {
        pod_copy_n(dest, src, cItems);
    }
    static void block_set(pointer dest, size_type cItems, const_reference value)
    {
        pod_fill_n(dest, cItems, value);
    }
/// @}

/// \name Construction
/// @{
public:
    /// \brief Constructs an auto_buffer with the given number of elements
    ///
    /// Constructs an auto_buffer with the given number of elements. If the
    /// allocation fails by throwing an exception, that exception is passed
    /// through to the caller. If allocation fails by returning a null
    /// pointer the auto_buffer instance is correctly constructed, and the
    /// \link #size size() \endlink method returns 0.
    ///
    /// \see \link #size size() \endlink
    /// \param cItems The number of items in the constructed instance
    ss_explicit_k auto_buffer(size_type cItems)
        : m_buffer((space < cItems) ? allocate_(cItems) : const_cast<pointer>(&m_internal[0]))
        , m_cItems((NULL != m_buffer) ? cItems : 0)
        , m_bExternal(space < cItems)
    {
        // Can't create one with an empty buffer. Though such is not legal
        // it is supported by some compilers, so we must ensure it cannot be
        // so
        STLSOFT_STATIC_ASSERT(0 != space);

        // These assertions ensure that the member ordering is not
        // changed, invalidating the initialisation logic of m_buffer and
        // m_cItems. The runtime assert is included for those compilers that
        // do not implement compile-time asserts.
#ifdef STLSOFT_CF_USE_RAW_OFFSETOF_IN_STATIC_ASSERT
        STLSOFT_STATIC_ASSERT(STLSOFT_RAW_OFFSETOF(class_type, m_buffer) < STLSOFT_RAW_OFFSETOF(class_type, m_cItems));
#endif /* STLSOFT_CF_USE_RAW_OFFSETOF_IN_STATIC_ASSERT */
        STLSOFT_MESSAGE_ASSERT("m_buffer must be before m_cItems in the auto_buffer definition", stlsoft_reinterpret_cast(ss_byte_t*, &m_buffer) < stlsoft_reinterpret_cast(ss_byte_t*, &m_cItems));

#ifndef _STLSOFT_AUTO_BUFFER_ALLOW_NON_POD
        // Use the must_be_pod constraint to ensure that
        // no type is managed in auto_buffer which would result in
        // dangerous mismanagement of the lifetime of its instances.
        //
        // Preprocessor specification of _STLSOFT_AUTO_BUFFER_ALLOW_NON_POD
        // prevents this, but the natural rules of the language will
        // still prevent non POD types being placed in m_internal[].
        stlsoft_constraint_must_be_pod(value_type);
#endif /* _STLSOFT_AUTO_BUFFER_ALLOW_NON_POD */

        STLSOFT_ASSERT(is_valid());
    }
    /// \brief Releases the allocated element array
    ///
    /// Releases any allocated memory. If the internal memory buffer was
    /// used, then nothing is done, otherwise the allocated memory is
    /// returned to the allocator.
#if defined(STLSOFT_CF_EXCEPTION_SIGNATURE_SUPPORT)
    ~auto_buffer()
#else /* ? STLSOFT_CF_EXCEPTION_SIGNATURE_SUPPORT */
    ~auto_buffer() stlsoft_throw_0()
#endif /* STLSOFT_CF_EXCEPTION_SIGNATURE_SUPPORT */
    {
        STLSOFT_ASSERT(is_valid());

        if(is_in_external_array_())
        {
            STLSOFT_ASSERT(NULL != m_buffer);
            STLSOFT_ASSERT(m_bExternal);
            STLSOFT_ASSERT(&m_internal[0] != m_buffer);

            deallocate_(m_buffer, m_cItems);
        }
    }
/// @}

/// \name Operations
/// @{
private:
    // Policy functions
    ss_bool_t   is_in_external_array_() const
    {
#if defined(STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK)
        // Old implementation always uses internal array if size() <= internal_size()
        STLSOFT_ASSERT((space < m_cItems) == (m_buffer != &m_internal[0]));

        return space < m_cItems;
#else /* ? STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK */
        // Old implementation always uses internal array if size() <= internal_size()
//        STLSOFT_ASSERT((m_buffer != &m_internal[0]) || !(space < m_cItems));
        STLSOFT_ASSERT((m_buffer != &m_internal[0]) == m_bExternal);
        STLSOFT_ASSERT(m_bExternal || !(space < m_cItems));

//        return m_buffer != &m_internal[0];
        return m_bExternal;
#endif /* STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK */
    }

public:
    /// \brief Expands or contracts the number of items in the buffer
    ///
    /// \param cItems The number of items to change in the buffer
    /// \return Returns \c true if successful. Function failure occurs when sufficient storage for the
    /// requested items cannot be allocated. In that case, std::bad_alloc will be throw for allocators
    /// that support it, otherwise the function will return \c false. In either case, the original
    /// storage and contents of the buffer will remain unchanged.
    ///
    /// \note When reducing the number of elements, the implementation favours speed above memory
    /// consumption. If the new item size is still larger than the internal storage size
    /// (\c internal_size()) then the heap allocated block will not be changed (i.e. it will not be
    /// exchanged for a smaller block).
    ///
    /// \note As from STLSoft version 1.9, the external array is not discarded in favour of the internal
    /// array when 0 < cItems < internal_size(). Only resize(0) will deallocate the external array.
    ss_bool_t resize(size_type cItems)
    {
        STLSOFT_ASSERT(is_valid());

        // There are four changes possible:
        //
        // 1. Expansion within the internal buffer
        // 2. Contraction within the internal buffer
        // 3. Expansion from the internal buffer to an allocated buffer
        // 4. Contraction from an allocated buffer to the internal buffer
        //  4.a Where n is 0, or when STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK is defined
        //  4.b Where 0 < n <= internal_size() - this is new behaviour - we do not go to the internal array
        // 5. Expansion from the allocated buffer to another allocated buffer
        // 6. Contraction from the allocated buffer to another allocated buffer

        if(m_cItems < cItems)
        {
            // Expansion; cases 1, 3 & 5

            if(is_in_external_array_())
            {
                // Current buffer is allocated: case 5
                pointer new_buffer  =   reallocate_(m_buffer, m_cItems, cItems);

                // Still test for NULL here, since some allocators will
                // not throw bad_alloc.
                if(NULL == new_buffer)
                {
                    return false;
                }

                // Now repoint to the new buffer
                m_buffer = new_buffer;
            }
            else
            {
                // Expanding from internal buffer; cases 1 & 3

                if(space < cItems)
                {
                    // Expanding to allocated buffer; case 3

                    pointer new_buffer = allocate_(cItems);

                    // Still test for NULL here, since some allocators will
                    // not throw bad_alloc.
                    if(NULL == new_buffer)
                    {
                        return false;
                    }

                    block_copy(new_buffer, m_buffer, m_cItems);

                    m_buffer = new_buffer;

                    m_bExternal = true;
                }
                else
                {
                    // Expanding to internal buffer; case 1

                    // Nothing to do
                    STLSOFT_ASSERT(!(space < cItems));
                }
            }
        }
        else
        {
            // Contraction; cases 2, 4 & 6

            if(is_in_external_array_())
            {
                // Current buffer is allocated: cases 4 & 6

                if(space < cItems)
                {
                    // Contracting within allocated buffer; case 6

                    // Nothing to do
                    STLSOFT_ASSERT(space < cItems);
                }
#if defined(STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK)
                else
#else /* ? STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK */
                else if(0 == cItems)
#endif /* STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK */
                {
                    // Contracting back to internal; case 4

                    block_copy(const_cast<pointer>(&m_internal[0]), m_buffer, cItems);

                    deallocate_(m_buffer, m_cItems);

                    m_buffer = const_cast<pointer>(&m_internal[0]);

                    m_bExternal = false;
                }
            }
            else
            {
                // Current buffer is internal; case 2

                // Nothing to do
                STLSOFT_ASSERT(!(space < cItems));
            }
        }

        m_cItems = cItems;

        STLSOFT_ASSERT(is_valid());

        return true;
    }

    /// \brief Swaps contents with the given buffer
    ///
    /// \note This method is only constant time when the memory for two buffers
    /// has been acquired via the allocator. Otherwise, it will depend on the
    /// costs of exchanging the memory
    ///
    /// \note Exception-safety: Provides the no-throw guarantee
    void swap(class_type &rhs) stlsoft_throw_0()
    {
        STLSOFT_ASSERT(is_valid());

        if( is_in_external_array_() &&
            rhs.is_in_external_array_())
        {
            // Both are allocated, so just swap them
            std_swap(m_buffer, rhs.m_buffer);
        }
        else if(is_in_external_array_())
        {
            // *this is allocated on the heap, rhs is using m_internal

            // 1. Copy the contents of rhs.m_internal to this->m_internal
            block_copy(&m_internal[0], &rhs.m_internal[0], rhs.m_cItems);

            // 2. Move m_buffer from *this to rhs
            rhs.m_buffer = m_buffer;

            // 3. Tell *this to use its internal buffer
            m_buffer = &m_internal[0];
        }
        else if(rhs.is_in_external_array_())
        {
            // This is a lazy cheat, but eminently effective.
            rhs.swap(*this);

            return;
        }
        else
        {
            // Both are using internal buffers, so we exchange the contents
            value_type  t[space];

            block_copy(&t[0],               &rhs.m_internal[0], rhs.m_cItems);
            block_copy(&rhs.m_internal[0],  &m_internal[0],     m_cItems);
            block_copy(&m_internal[0],      &t[0],              rhs.m_cItems);
        }

        std_swap(m_cItems,      rhs.m_cItems);
        std_swap(m_bExternal,   rhs.m_bExternal);

        STLSOFT_ASSERT(is_valid());
    }
/// @}

/// \name Operators
/// @{
public:
    // Note: The following two const and non-const implicit conversion
    // operators are correctly implemented. However, GCC will pedantically
    // give a verbose warning describing its having selected one over the
    // other, and this is, in current versions of the compiler, not
    // suppressable. The warnings must, alas, simply be ignored.

#ifdef _STLSOFT_AUTO_BUFFER_ALLOW_NON_CONST_CONVERSION_OPERATOR
    /// \brief An implicit conversion to a pointer to the start of the element array
    ///
    /// \deprecate This is deprecated
    operator pointer ()
    {
        STLSOFT_ASSERT(is_valid());

        return m_buffer;
    }
#else /* ? _STLSOFT_AUTO_BUFFER_ALLOW_NON_CONST_CONVERSION_OPERATOR */
    /// \brief Subscript operator
    reference operator [](size_type index)
    {
        STLSOFT_MESSAGE_ASSERT("Index is out of bounds", index <= m_cItems);

        STLSOFT_ASSERT(is_valid());

        return m_buffer[index];
    }

    /// \brief Subscript operator
    const_reference operator [](size_type index) const
    {
        STLSOFT_MESSAGE_ASSERT("Index is out of bounds", index <= m_cItems);

        STLSOFT_ASSERT(is_valid());

        return m_buffer[index];
    }
#endif /* _STLSOFT_AUTO_BUFFER_ALLOW_NON_CONST_CONVERSION_OPERATOR */

#ifdef _STLSOFT_AUTO_BUFFER_ALLOW_CONST_CONVERSION_OPERATOR
    /// \brief An implicit conversion to a pointer-to-const to the start of the element array
    operator const_pointer () const
    {
        STLSOFT_ASSERT(is_valid());

        return m_buffer;
    }
#endif /* _STLSOFT_AUTO_BUFFER_ALLOW_CONST_CONVERSION_OPERATOR */
/// @}

/// \name Accessors
/// @{
public:
    /// \brief Returns a pointer to the element array
    pointer data()
    {
        STLSOFT_ASSERT(is_valid());

        return m_buffer;
    }
    /// \brief Returns a pointer-to-const to the element array
    const_pointer data() const
    {
        STLSOFT_ASSERT(is_valid());

        return m_buffer;
    }
/// @}

/// \name Iteration
/// @{
public:
    /// \brief Returns a non-mutating iterator representing the start of the sequence
    const_iterator begin() const
    {
        STLSOFT_ASSERT(is_valid());

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -