ヒープ管理クラス (CSmartHeapPtr) [ATL]

(2007.06.21)
#pragma once
 
// WAC.com Class Liblary for Visual C++
// Copyright (C) WAC.com Inc. All rights reserved.
//
// This file is a part of the WAC.com Class Liblary.
// The use and distribution terms for this software are covered by the
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
// which can be found in the file CPL.TXT at the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by
// the terms of this license. You must not remove this notice, or
// any other, from this software.
 
// '05.01.11 : コードの整備 (sha)
// '05.01.19 : コンストラクタの追加 (sug)
// '05.01.24 : コードの整備 (sha)
// '05.03.16 : コードの整備 (oka)
// '05.03.24 : コードの整備 (sug)
// '05.06.15 : StreamHelper.hに依存しないように修正 (sug)
// '05.07.04 : Reallocateを修正 (sha)
// '05.07.05 : コードの整備 (sha)
// '05.07.12 : ファイルのLoad, Save関数を追加 (sha)
// '07.03.29 : __MEMORYBLOCK_H__ を定義 (sha)
// '07.04.06 : コードの整備 (sha)
// '07.04.20 : コードの整備 (sha)
// '07.04.23 : コード整備 (sha)
// '07.06.20 : CMemoryBlock → CSmartHeapPtr に名称変更 (sha)
 
#ifndef __SMARTHEAPPTR_H__
#define __SMARTHEAPPTR_H__
#endif
 
#include <atlcore.h>
#include <atlfile.h>
 
#include "Allocator.h"
 
 
////////////////////////////////////////////////////////////////////////////////
// CSmartHeapPtrT
 
template <class T, class Allocator = CVirtualAllocator>
class CSmartHeapPtrT
{
protected:
    typedef CSmartHeapPtrT                        thisClass;
 
public:
    CSmartHeapPtrT()
    {
        m_dwElementSize = 0;
    }
    CSmartHeapPtrT(size_t dwElements)
    {
        HRESULT hr = S_OK;
 
        m_dwElementSize = 0;
 
        hr = this->Allocate(dwElements);
        if (FAILED(hr))
        {
            // 無視する。。
        }
    }
    CSmartHeapPtrT(const T* p, size_t dwElements)
    {
        HRESULT hr = S_OK;
 
        m_dwElementSize = 0;
 
        hr = this->Load(p, dwElements);
        if (FAILED(hr))
        {
            // 無視する。。
        }
    }
    CSmartHeapPtrT(IStreamPtr spStream)
    {
        HRESULT hr = S_OK;
 
        m_dwElementSize = 0;
 
        hr = this->Load(spStream);
        if (FAILED(hr))
        {
            // 無視する。。
        }
    }
    virtual ~CSmartHeapPtrT()
    {
    }
 
public:
    // メモリを割り当てる
    HRESULT Allocate(size_t dwElements)
    {
        bool br = m_heap.Allocate(dwElements);
        if (br == false)
        {
            return E_OUTOFMEMORY;
        }
        
        m_dwElementSize = dwElements;
 
        return S_OK;
    }
    // メモリを再割り当てする
    HRESULT Reallocate(size_t dwElements)
    {
        if (m_heap.m_pData == NULL)
        {
            return this->Allocate(dwElements);
        }
 
        if (m_dwElementSize == dwElements)
        {
            return S_FALSE;
        }
 
        bool br = m_heap.Reallocate(dwElements);
        if (br == false)
        {
            return E_OUTOFMEMORY;
        }
        
        m_dwElementSize = dwElements;
 
        return S_OK;
    }
    // メモリを開放する
    HRESULT Free()
    {
        m_heap.Free();
 
        m_dwElementSize = 0;
 
        return S_OK;
    }
 
public:
    operator T*() const throw()
    {
//        ATLASSERT(m_heap.m_pData != NULL);
        return m_heap.m_pData;
    }
    T* operator ->() const throw()
    {
//        ATLASSERT(m_heap.m_pData != NULL);
        return m_heap.m_pData;
    }
 
public:
    T* GetData()
    {
//        ATLASSERT(m_heap.m_pData != NULL);
        return m_heap.m_pData;
    }
    size_t GetElementSize() const
    {
        return m_dwElementSize;
    }
    size_t GetByteSize() const
    {
        return thisClass::ClacByteSize(m_dwElementSize);
    }
 
public:
    static size_t ClacByteSize(size_t dwElements)
    {
        return sizeof(T) * dwElements;
    }
    static size_t ClacElementSize(size_t dwByteSize)
    {
        ATLASSERT(sizeof(T));
        return dwByteSize / sizeof(T);
    }
 
public:
    HRESULT Append(const T* p, size_t dwElements)
    {
        if (p == NULL)
        {
            return E_POINTER;
        }
 
        if (dwElements == 0)
        {
            // NOTE: サイズが0の場合も成功とする
            return S_FALSE;
        }
 
        HRESULT hr = S_OK;
 
        size_t dwOldByteSize = this->GetByteSize();
        hr = this->Reallocate(dwElements);
        if (FAILED(hr))
        {
            return hr;
        }
 
        size_t dwByteSize = thisClass::ClacByteSize(dwElements);
        ::MoveMemory(m_heap.m_pData + dwOldByteSize, p, dwByteSize);
        
        return S_OK;
    }
 
public:
    HRESULT Load(const T* p, size_t dwElements)
    {
        if (p == NULL)
        {
            ATLASSERT(0);
            return E_POINTER;
        }
        
        HRESULT hr = S_OK;
 
        try
        {
            hr = this->Free();
            if (FAILED(hr))
            {
                // 無視する。。
            }
 
            size_t dwByteSize = thisClass::ClacByteSize(dwElements);
            if (dwByteSize == 0)
            {
                // NOTE: サイズが0の場合も成功とする
                return S_FALSE;
            }
 
            hr = this->Allocate(dwElements);
            if (FAILED(hr))
            {
                return hr;
            }
 
            ::MoveMemory(m_heap.m_pData, p, dwByteSize);
        }
        catch (...)
        {
            return E_FAIL;
        }
 
        return hr;
    }
 
public:
    HRESULT Load(IStreamPtr spStream, bool bReset = true)
    {
        if (spStream == NULL)
        {
            ATLASSERT(0);
            return E_INVALIDARG;
        }
 
        HRESULT hr = S_OK;
 
        try
        {
            hr = this->Free();
            if (FAILED(hr))
            {
                // 無視する。。
            }
 
            ULARGE_INTEGER llByteSize = { 0, 0 };
            hr = thisClass::Emulete_IStream_Size(spStream, &llByteSize);
            if (FAILED(hr))
            {
                return hr;
            }
 
            size_t dwByteSize = llByteSize.LowPart;
            if (dwByteSize == 0)
            {
                // NOTE: サイズが0の場合も成功とする
                return S_FALSE;
            }
 
            size_t dwElementSize = thisClass::ClacElementSize(dwByteSize);
            hr = this->Allocate(dwElementSize);
            if (FAILED(hr))
            {
                return hr;
            }
 
            // シーク位置を先頭に戻す
            hr = thisClass::Emulete_IStream_Reset(spStream);
            if (FAILED(hr))
            {
                // NOTE: 実装によっては無視する必要があるか?
                return hr;
            }
 
            hr = spStream->Read(m_heap.m_pData, (ULONG)dwByteSize, NULL);
            if (FAILED(hr))
            {
                return hr;
            }
 
            if (bReset)
            {
                // シーク位置を先頭に戻す
                hr = thisClass::Emulete_IStream_Reset(spStream);
                if (FAILED(hr))
                {
                    // NOTE: 実装によっては無視する必要があるか?
                    return hr;
                }
            }
        }
        catch (...)
        {
            return E_FAIL;
        }
 
        return S_OK;
    }
    HRESULT Save(IStreamPtr spStream, bool bReset = true)
    {
        if (spStream == NULL)
        {
            ATLASSERT(0);
            return E_INVALIDARG;
        }
 
        HRESULT hr = S_OK;
 
        try
        {
            // ストリームを空にする
            ULARGE_INTEGER ulnSize = {0, 0};
            hr = spStream->SetSize(ulnSize);
            if (FAILED(hr))
            {
                // 実装によるので無視する。
            }
 
            // シーク位置を先頭に戻す
            hr = thisClass::Emulete_IStream_Reset(spStream);
            if (FAILED(hr))
            {
                // NOTE: 実装によっては無視する必要があるか?
                return hr;
            }
 
            if (m_dwElementSize == 0)
            {
                return S_OK;
            }
 
            size_t dwByteSize = this->GetByteSize();
            hr = spStream->Write(m_heap.m_pData, (ULONG)dwByteSize, NULL);
            if (FAILED(hr))
            {
                return hr;
            }
 
            if (bReset)
            {
                // シーク位置を先頭に戻す
                hr = thisClass::Emulete_IStream_Reset(spStream);
                if (FAILED(hr))
                {
                    // NOTE: 実装によっては無視する必要があるか?
                    return hr;
                }
            }
        }
        catch (...)
        {
            return E_FAIL;
        }
 
        return S_OK;
    }
 
public:
    HRESULT Load(LPCTSTR szFileName)
    {
        if (szFileName == NULL)
        {
            return E_INVALIDARG;
        }
 
        HRESULT hr = S_OK;
 
        try
        {
            ULONGLONG llFileSize = 0;
            hr = thisClass::GetFileSize(szFileName, llFileSize);
            if (FAILED(hr))
            {
                return hr;
            }
 
            // メモリの確保
            hr = this->Allocate((size_t)llFileSize);
            if (FAILED(hr))
            {
                return hr;
            }
 
            CAtlFile file;
 
            hr = file.Create(szFileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING);
            if (FAILED(hr))
            {
                return E_FAIL;
            }
 
            hr = file.Read(m_heap.m_pData, (DWORD)llFileSize);
            if (FAILED(hr))
            {
                return E_FAIL;
            }
 
            file.Close();
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return S_OK;
    }
    HRESULT Save(LPCTSTR szFileName)
    {
        if (szFileName == NULL)
        {
            return E_INVALIDARG;
        }
 
        HRESULT hr = S_OK;
 
        try
        {
            CAtlFile file;
 
            hr = file.Create(szFileName, GENERIC_WRITE, FILE_SHARE_WRITE, CREATE_ALWAYS);
            if (FAILED(hr))
            {
                return E_FAIL;
            }
 
            size_t dwByteSize = this->GetByteSize();
#pragma warning(disable: 4267)
            hr = file.Write(m_heap.m_pData, dwByteSize);
#pragma warning(default: 4267)
            if (FAILED(hr))
            {
                return hr;
            }
 
            file.Close();
        }
        catch (...)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        return hr;
    }
 
protected:
    // StreamHelper.hよりコピー
    // shlwapi.dll version 5.0 or later 互換
    static HRESULT Emulete_IStream_Reset(IStream *pstm)
    {
        if (pstm == NULL)
        {
            return E_FAIL;
        }
 
        HRESULT hr = S_OK;
 
        try
        {
            LARGE_INTEGER zeroPos = {0, 0};
            ULARGE_INTEGER streamSize = {0, 0};
            hr = pstm->Seek(zeroPos, STREAM_SEEK_SET, &streamSize);
            if (FAILED(hr))
            {
                return hr;
            }
        }
        catch (...)
        {
            return E_FAIL;
        }
 
        return hr;
    }
    // StreamHelper.hよりコピー
    // shlwapi.dll version 5.0 or later 互換
    static HRESULT Emulete_IStream_Size(
        IStream *pstm,
        ULARGE_INTEGER *pui)
    {
        if (pstm == NULL)
        {
            return E_FAIL;
        }
 
        if (pui == NULL)
        {
            return E_POINTER;
        }
 
        HRESULT hr = S_OK;
 
        try
        {
            ULARGE_INTEGER zero = {0, 0};
            *pui = zero;
 
            STATSTG stat;
            memset(&stat, 0, sizeof(stat));
 
            hr = pstm->Stat(&stat, STATFLAG_NONAME);
            if (FAILED(hr))
            {
                return hr;
            }
 
            *pui = stat.cbSize;
        }
        catch (...)
        {
            return E_FAIL;
        }
 
        return hr;
    }
    // FileHelper.h よりコピー
    static HRESULT GetFileSize(
        LPCTSTR szFileName,
        ULONGLONG& nLen)
    {
        WIN32_FIND_DATA wfd;
        memset(&wfd, 0, sizeof(wfd));
        HANDLE hFind = ::FindFirstFile(szFileName, &wfd);
        if (hFind == INVALID_HANDLE_VALUE)
        {
            return E_FAIL;
        }
        ::FindClose(hFind);
 
        ULARGE_INTEGER liFileSize;
        liFileSize.HighPart = wfd.nFileSizeHigh;
        liFileSize.LowPart = wfd.nFileSizeLow;
 
        nLen = liFileSize.QuadPart;
 
        return S_OK;
    }
 
protected:
    CHeapPtr<T, Allocator> m_heap;
    size_t m_dwElementSize;
};
 
typedef CSmartHeapPtrT<BYTE>        CSmartHeapPtr;
一覧に戻る
© 2003 WAC.com All Right Reserved.