Click here to Skip to main content
15,881,173 members
Articles / Desktop Programming / MFC

What's New in ACF 0.3

Rate me:
Please Sign up or sign in to vote.
3.39/5 (7 votes)
23 Jun 20043 min read 40.4K   193   8  
This article introduces what's new in ACF (Another C++ Framework) version 0.3.
//---------------------------------------------------------------------
//
// Copyright (C) 2004 Yingle Jia
//
// Permission to copy, use, modify, sell and distribute this software is 
// granted provided this copyright notice appears in all copies. 
// This software is provided "as is" without express or implied warranty, 
// and with no claim as to its suitability for any purpose.
//
// AcfAutoBuffer.h - defines class AutoBuffer
//

#ifndef __Acf_AutoBuffer__
#define __Acf_AutoBuffer__

namespace Acf {

//---------------------------------------------------------------------
// class AutoBuffer
//
// Implements a resizable buffer which automatically switchs between 
// stack-based buffer and heap-based buffer. The stack buffer length 
// can be specified at compile-time.
//
// This class is internally used by Array, String and StringBuilder.
//

template<typename T, int StackBufferLength = 128 / sizeof(T)>
class AutoBuffer
{
// Constants
private:
    static const int StackBufferByteLength = StackBufferLength * sizeof(T);
    static const int DataByteLength = StackBufferByteLength > sizeof(T*) ? 
        StackBufferByteLength : sizeof(T*);

// Fields
private:
#ifdef _DEBUG
    T* _ptr; // pointer to the buffer (for debugging)
#endif // #ifdef _DEBUG

    int _length;
    byte _data[DataByteLength]; // heap pointer or stack buffer, i.e.
//    union {
//        T* _heapPtr;
//        byte _buffer[StackBufferLength * sizeof(T)];
//    };

    T* ReinterpretGetStackBuffer()
    {
        return reinterpret_cast<T*>(this->_data);
    }

    T*& ReinterpretGetHeapPtrRef()
    {
        return *reinterpret_cast<T**>(this->_data);
    }

    T* InternalGetBuffer()
    {
        ACFASSERT(this->_length != 0);

        if (StackBufferLength == 0)
            return ReinterpretGetHeapPtrRef();

        if (this->_length > StackBufferLength)
            return ReinterpretGetHeapPtrRef();
        else
            return ReinterpretGetStackBuffer();
    }

// Constructors
public:
    AutoBuffer() : _length(0)
    {
    }
    explicit AutoBuffer(int length) : _length(0)
    {
        SetLength(length);
    }

// Destructor
public:
    ~AutoBuffer()
    {
        SetLength(0);
    }

// Properties
public:
	// Length
	__declspec(property(get=get_Length)) int Length;
    int get_Length()
    {
        return this->_length;
    }

    // []
    const T& operator[](int index) const
    {
        if (index < 0 || index >= this->_length)
            throw IndexOutOfRangeException();

        return *(InternalGetBuffer() + index);
    }
    T& operator[](int index)
    {
        if (index < 0 || index >= this->_length)
            throw IndexOutOfRangeException();

        return *(InternalGetBuffer() + index);
    }

// Methods
public:
    T* GetBuffer()
    {
        if (this->_length == 0)
            throw InvalidOperationException();

        return InternalGetBuffer();
    }

    void SetLength(int value)
    {
        if (value < 0)
            throw ArgumentOutOfRangeException();

        if (this->_length == value)
            return;

        if (value > this->_length)
        {
            // Grow

            if (value > StackBufferLength)
            {
                // New buffer on heap (old buffer can be stack or heap)

                T* pOld = (this->_length == 0) ? null : InternalGetBuffer();
                T* pNew = Acf::Alloc<T>(value);

                // Copy old elements (may throw)
                if (this->_length != 0)
                {
                    try
                    {
                        Acf::Language::Construct(pNew, this->_length, pOld);
                    }
                    catch (...)
                    {
                        Acf::Free(pNew);
                        throw;
                    }
                }

                // Destruct old elements and free memory
                if (this->_length != 0)
                    Acf::Language::Destruct(pOld, this->_length);
                if (this->_length > StackBufferLength)
                    Acf::Free(pOld);

                ReinterpretGetHeapPtrRef() = pNew;
            }
            else
            {
                // Both on stack (no need to copy, just call default constructors for 
                // the new elements)

                T* p = ReinterpretGetStackBuffer();
                memset(p + this->_length, 0, (value - this->_length) * sizeof(T));
                Acf::Language::Construct(p + this->_length, value - this->_length);
            }
        }
        else
        {
            // Shrink

            if (this->_length > StackBufferLength)
            {
                // Old buffer on heap (new buffer can be stack or heap)

                T* pOld = InternalGetBuffer();
                T* pNew = null;
                if (value > StackBufferLength)
                {
                    pNew = Acf::Alloc<T>(value);
                }
                else
                {
                    pNew = ReinterpretGetStackBuffer();
                    memset(pNew, 0, value * sizeof(T));
                }

                // Copy old elements
                if (value != 0)
                {
                    try
                    {
                        Acf::Language::Construct(pNew, value, pOld);
                    }
                    catch (...)
                    {
                        if (value > StackBufferLength)
                            Acf::Free(pNew);
                        throw;
                    }
                }

                // Destruct old elements and free memory
                Acf::Language::Destruct(pOld, this->_length);
                Acf::Free(pOld);

                if (value > StackBufferLength)
                    ReinterpretGetHeapPtrRef() = pNew;
            }
            else
            {
                // Both on stack (no need to copy, just destruct the extra elements)

                T* p = ReinterpretGetStackBuffer();
                Acf::Language::Destruct(p + value, this->_length - value);
            }
        }

        this->_length = value;

#ifdef _DEBUG
        this->_ptr = (this->_length == 0) ? null : InternalGetBuffer();
#endif // #ifdef _DEBUG
    }

private:
    AutoBuffer(const AutoBuffer& src);
    AutoBuffer& operator=(const AutoBuffer& src);
};

} // namespace Acf

#endif // #ifndef __Acf_AutoBuffer__

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
China China
Yingle Jia is a software engineer located in Beijing, China. He currently works at IBM CSDL (China Software Development Lab). His interests include C++/COM/C#/.NET/XML, etc. He likes coding and writing.

He is the creator of ACF (Another C++ Framework) project. See http://acfproj.sourceforge.net/.

He also has a blog at http://blogs.wwwcoder.com/yljia/

Comments and Discussions