MFC dictionary collection with key unicity and ordering by position

前端 未结 5 1661
深忆病人
深忆病人 2021-01-26 15:18

Looking at table on http://msdn.microsoft.com/en-us/library/y1z022s1%28v=vs.80%29.aspx#_core_collection_shape_features

I can not see a MFC collection for the purpose I n

5条回答
  •  無奈伤痛
    2021-01-26 15:35

    I decided to derive a templated class from both CMap and CArray and write the ArrayMapTempl.h file as follows:

    //Author: Sérgio Loureiro. This is open source.
    
    #include 
    
    template
    class CArrayMap: protected CArray, protected CMap
    {
    private:
        bool m_isChangingSize;
    public:
        CArrayMap():
          m_isChangingSize(false)
        {
        };
    
        CArrayMap(const CArrayMap& src){};
        CArrayMap operator=(const CArrayMap& src){return *this;};
    
        // Attributes
        INT_PTR GetSize() const;
        INT_PTR GetCount() const;
        BOOL IsEmpty() const;
        INT_PTR GetUpperBound() const;
    
        // Lookup
        int Lookup(ARG_KEY key) const;
        int Lookup(ARG_KEY key, VALUE& rValue) const;
    
    // Operations
        // Clean up
        void RemoveAll();
    
        // Accessing elements
        const CPair& GetAt(INT_PTR nIndex) const;
        CPair& GetAt(INT_PTR nIndex);
        void SetAt(INT_PTR nIndex, ARG_KEY newKey, ARG_VALUE newValue);
        const CPair& ElementAt(INT_PTR nIndex) const;
        CPair& ElementAt(INT_PTR nIndex);
    
        // Direct Access to the element data
        const CPair& GetData() const;
        CPair& GetData();
    
        // Potentially growing the array
        INT_PTR Add(ARG_KEY newKey, ARG_VALUE newValue);
        void Copy(const CArrayMap& src);
    
        // overloaded operator helpers
        const CPair& operator[](INT_PTR nIndex) const;
        CPair& operator[](INT_PTR nIndex);
    
        // Operations that move elements around
    
        BOOL Swap(INT_PTR nIndex, INT_PTR nIndex2);
        BOOL MoveUp(INT_PTR nIndex);
        BOOL MoveDown(INT_PTR nIndex);
    
        BOOL SwapByKey(ARG_KEY key, ARG_KEY key2);
        BOOL MoveUpByKey(ARG_KEY key);
        BOOL MoveDownByKey(ARG_KEY key);
    
        BOOL InsertAt(INT_PTR nIndex, ARG_KEY newKey, ARG_VALUE newValue);
        BOOL RemoveAt(INT_PTR nIndex);
        BOOL RemoveByKey(ARG_KEY key);
    
    
    public:
        void Serialize(CArchive&);
    #ifdef _DEBUG
        void Dump(CDumpContext&) const;
        void AssertValid() const;
    #endif
    
    #if 0   
    public:
    // Construction
        CArray();
    
    // Attributes
        INT_PTR GetSize() const;
        INT_PTR GetCount() const;
        BOOL IsEmpty() const;
        INT_PTR GetUpperBound() const;
        void SetSize(INT_PTR nNewSize, INT_PTR nGrowBy = -1);
    
    // Operations
        // Clean up
        void FreeExtra();
        void RemoveAll();
    
        // Accessing elements
        const TYPE& GetAt(INT_PTR nIndex) const;
        TYPE& GetAt(INT_PTR nIndex);
        void SetAt(INT_PTR nIndex, ARG_TYPE newElement);
        const TYPE& ElementAt(INT_PTR nIndex) const;
        TYPE& ElementAt(INT_PTR nIndex);
    
        // Direct Access to the element data (may return NULL)
        const TYPE* GetData() const;
        TYPE* GetData();
    
        // Potentially growing the array
        void SetAtGrow(INT_PTR nIndex, ARG_TYPE newElement);
        INT_PTR Add(ARG_TYPE newElement);
        INT_PTR Append(const CArray& src);
        void Copy(const CArray& src);
    
        // overloaded operator helpers
        const TYPE& operator[](INT_PTR nIndex) const;
        TYPE& operator[](INT_PTR nIndex);
    
        // Operations that move elements around
        void RemoveAt(INT_PTR nIndex, INT_PTR nCount = 1);
        void InsertAt(INT_PTR nStartIndex, CArray* pNewArray);
    
    // Implementation
    protected:
        TYPE* m_pData;   // the actual array of data
        INT_PTR m_nSize;     // # of elements (upperBound - 1)
        INT_PTR m_nMaxSize;  // max allocated
        INT_PTR m_nGrowBy;   // grow amount
    
    public:
        ~CArray();
        void Serialize(CArchive&);
    #ifdef _DEBUG
        void Dump(CDumpContext&) const;
        void AssertValid() const;
    #endif
    #endif
    
    //----------------------------------------------------------------------------------------
    #if 0
    public:
        // CPair
        struct CPair
        {
            const KEY key;
            VALUE value;
        protected:
            CPair( ARG_KEY keyval ) : key( keyval ) {}
        };
    
    protected:
        // Association
        class CAssoc : public CPair
        {
            friend class CMap;
            CAssoc* pNext;
            UINT nHashValue;  // needed for efficient iteration
        public:
            CAssoc( ARG_KEY key ) : CPair( key ) {}
        };
    
    public:
    // Construction
        /* explicit */ CMap(INT_PTR nBlockSize = 10);
    
    // Attributes
        // number of elements
        INT_PTR GetCount() const;
        INT_PTR GetSize() const;
        BOOL IsEmpty() const;
    
        // Lookup
        BOOL Lookup(ARG_KEY key, VALUE& rValue) const;
        const CPair *PLookup(ARG_KEY key) const;
        CPair *PLookup(ARG_KEY key);
    
    // Operations
        // Lookup and add if not there
        VALUE& operator[](ARG_KEY key);
    
        // add a new (key, value) pair
        void SetAt(ARG_KEY key, ARG_VALUE newValue);
    
        // removing existing (key, ?) pair
        BOOL RemoveKey(ARG_KEY key);
        void RemoveAll();
    
        // iterating all (key, value) pairs
        POSITION GetStartPosition() const;
    
        const CPair *PGetFirstAssoc() const;
        CPair *PGetFirstAssoc();
    
        void GetNextAssoc(POSITION& rNextPosition, KEY& rKey, VALUE& rValue) const;
    
        const CPair *PGetNextAssoc(const CPair *pAssocRet) const;
        CPair *PGetNextAssoc(const CPair *pAssocRet);
    
        // advanced features for derived classes
        UINT GetHashTableSize() const;
        void InitHashTable(UINT hashSize, BOOL bAllocNow = TRUE);
    
    // Implementation
    protected:
        CAssoc** m_pHashTable;
        UINT m_nHashTableSize;
        INT_PTR m_nCount;
        CAssoc* m_pFreeList;
        struct CPlex* m_pBlocks;
        INT_PTR m_nBlockSize;
    
        CAssoc* NewAssoc(ARG_KEY key);
        void FreeAssoc(CAssoc*);
        CAssoc* GetAssocAt(ARG_KEY, UINT&, UINT&) const;
    
    public:
        ~CMap();
        void Serialize(CArchive&);
    #ifdef _DEBUG
        void Dump(CDumpContext&) const;
        void AssertValid() const;
    #endif
    #endif
    
    };
    
    template 
    inline INT_PTR CArrayMap::GetSize() const
    {
        ASSERT(CArray::m_nSize == CMap::m_nCount);
        return CArray::GetSize();
    };
    
    
    template 
    inline INT_PTR CArrayMap::GetCount() const
    {
        ASSERT(CArray::m_nSize == CMap::m_nCount);
        return CArray::GetCount();
    }
    
    
    template 
    inline BOOL CArrayMap::IsEmpty() const
    { 
        ASSERT(CArray::m_nSize == CMap::m_nCount);
        return CArray::IsEmpty();
    }
    
    template 
    inline INT_PTR CArrayMap::GetUpperBound() const
    { 
        ASSERT(CArray::m_nSize == CMap::m_nCount);
        return CArray::GetUpperBound();
    }
    
    
    template 
    inline INT_PTR CArrayMap::Add(ARG_KEY newKey, ARG_VALUE newValue)
    { 
        VALUE rValue;
        if( CMap::Lookup(newKey,rValue))    //already exists
            return -1;
    
        INT_PTR nIndex = CArray::m_nSize;   //old size will be the new position
    
        m_isChangingSize= true;
        CMap::operator[] (newKey)= newValue;
        CArray::Add(newKey);
        m_isChangingSize= false;
    
        ASSERT(CArray::m_nSize == CMap::m_nCount);
        return nIndex;
    };
    
    
    template 
    inline const typename CMap::CPair&
        CArrayMap::GetAt(INT_PTR nIndex) const
    { 
        ASSERT(nIndex >= 0 && nIndex < m_nSize);
        if(nIndex >= 0 && nIndex < m_nSize)
        {
            return *CMap::PLookup(CArray::GetAt(nIndex));
        }
        AfxThrowInvalidArgException();
    };
    
    
    template 
    inline typename CMap::CPair&
        CArrayMap::GetAt(INT_PTR nIndex)
    { 
        ASSERT(nIndex >= 0 && nIndex < m_nSize);
        if(nIndex >= 0 && nIndex < m_nSize)
        {
            return *CMap::PLookup(CArray::GetAt(nIndex));
        }
        AfxThrowInvalidArgException();
    };
    
    template
    int CArrayMap::Lookup(ARG_KEY key) const
    {
        VALUE rValue;
        return this->Lookup(key, rValue);
    };
    
    template
    int CArrayMap::Lookup(ARG_KEY key, VALUE& rValue) const
    {
        for (int i=0; i
    void CArrayMap::RemoveAll()
    {
        m_isChangingSize=true;
        CMap::RemoveAll();
        CArray::RemoveAll();
        m_isChangingSize=false;
    
        ASSERT(CArray::m_nSize == CMap::m_nCount);
    };
    
    
    
    template 
    BOOL CArrayMap::Swap(INT_PTR nIndex, INT_PTR nIndex2)
    {
        if(nIndex<0 || nIndex2<0)
            return FALSE;
    
        if(nIndex>=m_nSize || nIndex2>=m_nSize)
            return FALSE;
    
        //Swap with itself. Everything is fine and nothing needs to be done
        if(nIndex == nIndex2)
            return TRUE;
    
        KEY k= CArray::GetAt(nIndex);
        CArray::SetAt(nIndex, CArray::GetAt(nIndex2));
        CArray::SetAt(nIndex, k);
    };
    
    template 
    BOOL CArrayMap::MoveUp(INT_PTR nIndex)
    {
        if (nIndex == 0)
            return FALSE;
        return Swap(nIndex,nIndex-1);
    };
    
    template 
    BOOL CArrayMap::MoveDown(INT_PTR nIndex)
    {
        if (nIndex == m_nSize-1)
            return FALSE;
        return Swap(nIndex,nIndex+1);
    };
    
    template 
    BOOL CArrayMap::SwapByKey(ARG_KEY key, ARG_KEY key2)
    {
        int nIndex= Lookup(key);
        int nIndex2= Lookup(key2);
        if(nIndex == -1 || nIndex2 == -1)
            return FALSE;
    
        return Swap(nIndex,nIndex2);
    }
    
    template 
    BOOL CArrayMap::MoveUpByKey(ARG_KEY key)
    {
        int nIndex= Lookup(key);
        if(nIndex == -1)
            return FALSE;
    
        return MoveUp(nIndex);
    }
    
    template 
    BOOL CArrayMap::MoveDownByKey(ARG_KEY key)
    {
        int nIndex= Lookup(key);
        if(nIndex == -1)
            return FALSE;
    
        return MoveDown(nIndex);
    }
    
    
    
    template 
    int CArrayMap::InsertAt(INT_PTR nIndex,ARG_KEY newKey, ARG_VALUE newValue)
    {
    
        AssertValid();          //ASSERT_VALID(this);
    
        if(nIndex < 0)
            return FALSE;   //AfxThrowInvalidArgException();
    
        if(nIndex > m_nSize)    //doesn't make sense to grow more than last+1 , given newKey has to be unique
            return FALSE;
    
        //I am not using this->Lookup(ARG_KEY key), because I 
        //presume CMap::Lookup(ARG_KEY key, VALUE& rValue) will be faster,
        //as it does not need to traverse the array.    
    
        VALUE rValue;
        if(CMap::Lookup(newKey,rValue)) //already exists
            return FALSE;
    
        m_isChangingSize=true;
        CMap::operator[] (newKey)= newValue;
        CArray::InsertAt(nIndex,newKey,1);
        m_isChangingSize=false;
    
        ASSERT(CArray::m_nSize == CMap::m_nCount);
        return TRUE;
    }
    
    
    template 
    BOOL CArrayMap::RemoveAt(INT_PTR nIndex)
    {
        if(nIndex<0 || nIndex>= m_nSize)
            return FALSE;
    
        KEY k= CArray::GetAt(nIndex);
    
        //I am not using this->Lookup(ARG_KEY key), because I 
        //presume CMap::Lookup(ARG_KEY key, VALUE& rValue) will be faster,
        //as it does not need to traverse the array.    
    
        VALUE rValue;
        if(CMap::Lookup(k,rValue))  //already exists
        {
            m_isChangingSize= true;
            CMap::RemoveKey(k);
            CArray::RemoveAt(nIndex);
            m_isChangingSize= false;
    
            ASSERT(CArray::m_nSize == CMap::m_nCount);
            return TRUE;
        }
        else
            return FALSE;
    };
    
    template 
    BOOL CArrayMap::RemoveByKey(ARG_KEY key)
    {
        int nIndex= Lookup(key);
        if(nIndex == -1)
            return FALSE;
    
        KEY k= CArray::GetAt(nIndex);
    
        return RemoveAt(nIndex);
    };
    
    
    template
    void CArrayMap::Serialize(CArchive& ar)
    {
        ASSERT(CArray::m_nSize == CMap::m_nCount);
        //ASSERT_VALID((const CArray *)this);
        //ASSERT_VALID((const CMap *)this);
    
        CObject::Serialize(ar);
    
        if (ar.IsStoring())
        {
            ar.WriteCount(m_nSize);
            if (m_nSize == 0)
                return;  // nothing more to do
    
            for(INT_PTR i=0;i( &reinterpret_cast< int& >( const_cast< KEY& > ( static_cast< const KEY& >( CArray::operator[]( i ) ) ) ) );
                pValue = reinterpret_cast< VALUE* >( &reinterpret_cast< int& >( static_cast< VALUE& >( CMap::operator[]( *pKey ) ) ) );
                SerializeElements(ar, pKey, 1);
                SerializeElements(ar, pValue, 1);
            }
        }
        else
        {
            DWORD_PTR nNewCount = ar.ReadCount();
            while (nNewCount--)
            {
                KEY newKey[1];
                VALUE newValue[1];
                SerializeElements(ar, newKey, 1);
                SerializeElements(ar, newValue, 1);
                this->Add(newKey[0], newValue[0]);  //includes checking if it already exists
            }
        }
    }
    
    #ifdef _DEBUG
    template
    void CArrayMap::Dump(CDumpContext& dc) const
    {
        ASSERT(CArray::m_nSize == CMap::m_nCount);
    
        CObject::Dump(dc);
    
        dc << "with " << m_nSize << " elements";
        if (dc.GetDepth() > 0)
        {
            // Dump in format "[key] -> value"
            KEY key[1];
            VALUE val[1];
    
            POSITION pos = GetStartPosition();
            while (pos != NULL)
    
            for (int i=0; i(dc, key, 1);
                dc << "] = ";
                DumpElements(dc, val, 1);
            }
        }
    
        dc << "\n";
    }
    
    template
    void CArrayMap::AssertValid() const
    {
        CArray::AssertValid();
        CMap::AssertValid();
    
        if(!m_isChangingSize)   
            ASSERT(CArray::m_nSize == CMap::m_nCount);
    }
    
    #endif //_DEBUG
    

    Now I have everything I need. I didn't test everything, but I believe that only little corrections will be needed, if needed.

    Anyway, thank you all for the answers and comments.

提交回复
热议问题