//*************************************************************************** // // (c) 1996-2001 by Microsoft Corp. // // FLEXARRY.CPP // // CFlexArray implementation (non-arena). // // 15-Jul-97 raymcc Created. // //*************************************************************************** #include "precomp.h" #include #include //*************************************************************************** // // CFlexArray::CFlexArray // // Constructs the array. // // Parameters: // The starting preallocated size of the array. // The amount to grow by when the array fills up. // // Size() returns the number of elements in use, not the 'true' size. // //*************************************************************************** // ok CFlexArray::CFlexArray( int nSize, int nGrowBy ) { m_nExtent = nSize; m_nSize = 0; m_nGrowBy = nGrowBy; m_pArray = (void **) LocalAlloc(LMEM_ZEROINIT, sizeof(void *) * nSize); } //*************************************************************************** // // CFlexArray::~CFlexArray // //*************************************************************************** // ok CFlexArray::~CFlexArray() { LocalFree(m_pArray); } //*************************************************************************** // // Copy constructor. // // Copies the pointers, not their contents. // //*************************************************************************** // ok CFlexArray::CFlexArray(CFlexArray &Src) { m_pArray = 0; m_nSize = 0; m_nExtent = 0; m_nGrowBy = 0; *this = Src; } //*************************************************************************** // // operator = // // Assignment operator. // // Arenas are not copied. This allows transfer of arrays between arenas. // Arrays are copied by pointer only. // //*************************************************************************** // ok CFlexArray& CFlexArray::operator=(CFlexArray &Src) { m_nSize = Src.m_nSize; m_nExtent = Src.m_nExtent; m_nGrowBy = Src.m_nGrowBy; LocalFree(m_pArray); m_pArray = (void **) LocalAlloc(LMEM_ZEROINIT, sizeof(void *) * m_nExtent); memcpy(m_pArray, Src.m_pArray, sizeof(void *) * m_nExtent); return *this; } //*************************************************************************** // // CFlexArray::RemoveAt // // Removes the element at the specified location. Does not // actually delete the pointer. Shrinks the array over the top of // the 'doomed' element. // // Parameters: // The location of the element. // // Return value: // range_error The index is not legal. // no_error Success. // //*************************************************************************** // ok int CFlexArray::RemoveAt(int nIndex) { if (nIndex >= m_nSize) return range_error; for (int i = nIndex; i < m_nSize - 1; i++) m_pArray[i] = m_pArray[i + 1]; m_nSize--; m_pArray[m_nSize] = 0; return no_error; } //*************************************************************************** // // CFlexArray::InsertAt // // Inserts a new element at the specified location. The pointer is copied. // // Parameters: // The 0-origin location at which to insert the new element. // The pointer to copy. (contents are not copied). // // Return value: // array_full // out_of_memory // no_error // //*************************************************************************** // ok int CFlexArray::InsertAt(int nIndex, void *pSrc) { // If the array is full, we need to expand it. // =========================================== if (m_nSize == m_nExtent) { if (m_nGrowBy == 0) return array_full; m_nExtent += m_nGrowBy; void **pTmp = (void **) LocalAlloc(LMEM_ZEROINIT, sizeof(void *) * m_nExtent); if (!pTmp) return out_of_memory; for (int i = 0; i < m_nSize; i++) pTmp[i] = m_pArray[i]; LocalFree(m_pArray); m_pArray = pTmp; } // Special case of appending. This is so frequent // compared to true insertion that we want to optimize. // ==================================================== if (nIndex == m_nSize) { m_pArray[m_nSize++] = pSrc; return no_error; } // If here, we are inserting at some random location. // We start at the end of the array and copy all the elements // one position farther to the end to make a 'hole' for // the new element. // ========================================================== for (int i = m_nSize; i > nIndex; i--) m_pArray[i] = m_pArray[i - 1]; m_pArray[nIndex] = pSrc; m_nSize++; return no_error; } //*************************************************************************** // // CFlexArray::DebugDump // //*************************************************************************** void CFlexArray::DebugDump() { printf("----CFlexArray Debug Dump----\n"); printf("m_pArray = 0x%X\n", m_pArray); printf("m_nSize = %d\n", m_nSize); printf("m_nExtent = %d\n", m_nExtent); printf("m_nGrowBy = %d\n", m_nGrowBy); for (int i = 0; i < m_nExtent; i++) { if (i < m_nSize) printf("![%d] = %X\n", i, m_pArray[i]); else printf("?[%d] = %X\n", i, m_pArray[i]); } } //*************************************************************************** // // CFlexArray::Compress // // Removes NULL elements by moving all non-NULL pointers to the beginning // of the array. The array "Size" changes, but the extent is untouched. // //*************************************************************************** // ok void CFlexArray::Compress() { int nLeftCursor = 0, nRightCursor = 0; while (nLeftCursor < m_nSize - 1) { if (m_pArray[nLeftCursor]) { nLeftCursor++; continue; } else { nRightCursor = nLeftCursor + 1; while (m_pArray[nRightCursor] == 0 && nRightCursor < m_nSize) nRightCursor++; if (nRightCursor == m_nSize) break; // Short circuit, no more nonzero elements. m_pArray[nLeftCursor] = m_pArray[nRightCursor]; m_pArray[nRightCursor] = 0; } } while (m_pArray[m_nSize - 1] == 0 && m_nSize > 0) m_nSize--; } //*************************************************************************** // // CFlexArray::Empty // // Clears the array of all pointers (does not deallocate them) and sets // its apparent size to zero. // //*************************************************************************** // ok void CFlexArray::Empty() { LocalFree(m_pArray); m_pArray = (void **) LocalAlloc(LMEM_ZEROINIT, sizeof(void *) * m_nGrowBy); m_nSize = 0; m_nExtent = m_nGrowBy; } //*************************************************************************** // // CFlexArray::UnbindPtr // // Empties the array and returns the pointer to the data it contained // //*************************************************************************** void** CFlexArray::UnbindPtr() { void** pp = m_pArray; Empty(); return pp; } //*************************************************************************** // // CWStringArray::CWStringArray // // Constructs a wide-string array. // // Parameters: // The starting preallocated size of the array. // The amount to grow by when the array fills up. // // Size() returns the number of elements in use, not the 'true' size. // //*************************************************************************** CWStringArray::CWStringArray( int nSize, int nGrowBy ) : m_Array(nSize, nGrowBy) { } //*************************************************************************** // // Copy constructor. // //*************************************************************************** CWStringArray::CWStringArray(CWStringArray &Src) { *this = Src; } //*************************************************************************** // // Destructor. Cleans up all the strings. // //*************************************************************************** CWStringArray::~CWStringArray() { Empty(); } //*************************************************************************** // // CWStringArray::DeleteStr // // Frees the string at the specified index and sets the element to NULL. // Does not compress array. // // Does not currently do a range check. // // Parameters: // The 0-origin index of the string to remove. // // Return values: // no_error // //*************************************************************************** int CWStringArray::DeleteStr(int nIndex) { LocalFree(m_Array[nIndex]); m_Array[nIndex] = 0; return no_error; } //*************************************************************************** // // CWStringArray::FindStr // // Finds the specified string and returns its location. // // Parameters: // The string to find. // or // // Return value: // The 0-origin location of the string, or -1 if not found. // //*************************************************************************** int CWStringArray::FindStr(wchar_t *pTarget, int nFlags) { if (nFlags == no_case) { for (int i = 0; i < m_Array.Size(); i++) if (_wcsicmp((wchar_t *) m_Array[i], pTarget) == 0) return i; } else { for (int i = 0; i < m_Array.Size(); i++) if (wcscmp((wchar_t *) m_Array[i], pTarget) == 0) return i; } return not_found; } //*************************************************************************** // // operator = // //*************************************************************************** // Heap handle & allocation functions are not copied. This allows // transfer of arrays between heaps. CWStringArray& CWStringArray::operator =(CWStringArray &Src) { Empty(); for (int i = 0; i < Src.Size(); i++) { wchar_t *pSrc = (wchar_t *) Src.m_Array[i]; wchar_t *pCopy = (wchar_t *) LocalAlloc(LMEM_ZEROINIT, (wcslen(pSrc) + 1) * 2); wcscpy(pCopy, pSrc); m_Array.Add(pCopy); } return *this; } //*************************************************************************** // // CWStringArray::Add // // Appends a new string to the end of the array. // // Parameters: // The string to copy. // // Return value: // The return values of CFlexArray::Add. // //*************************************************************************** int CWStringArray::Add(wchar_t *pSrc) { wchar_t *pNewStr = (wchar_t *) LocalAlloc(LMEM_ZEROINIT, (wcslen(pSrc) + 1) * 2); wcscpy(pNewStr, pSrc); return m_Array.Add(pNewStr); } //*************************************************************************** // // CWStringArray::InsertAt // // Inserts a copy of a string in the array. // // Parameters: // The 0-origin location at which to insert the string. // The string to copy. // // Return values: // The return values of CFlexArray::InsertAt // //*************************************************************************** int CWStringArray::InsertAt(int nIndex, wchar_t *pSrc) { wchar_t *pNewStr = (wchar_t *) LocalAlloc(LMEM_ZEROINIT, (wcslen(pSrc) + 1) * 2); wcscpy(pNewStr, pSrc); return m_Array.InsertAt(nIndex, pNewStr); } //*************************************************************************** // // CWStringArray::RemoveAt // // Removes and deallocates the string at the specified location. // Shrinks the array. // // Parameters: // The 0-origin index of the 'doomed' string. // // Return value: // Same as CFlexArray::RemoveAt. // //*************************************************************************** int CWStringArray::RemoveAt(int nIndex) { wchar_t *pDoomedString = (wchar_t *) m_Array[nIndex]; LocalFree(pDoomedString); return m_Array.RemoveAt(nIndex); } //*************************************************************************** // // CWStringArray::SetAt // // Replaces the string at the targeted location with the new one. // The old string at the location is cleaned up. // // No range checking or out-of-memory checks at present. // // Parameters: // The 0-origin location at which to replace the string. // The string to copy. // // Return value: // no_error // //*************************************************************************** int CWStringArray::SetAt(int nIndex, wchar_t *pSrc) { wchar_t *pDoomedString = (wchar_t *) m_Array[nIndex]; if (pDoomedString) LocalFree(pDoomedString); wchar_t *pNewStr = (wchar_t *) LocalAlloc(LMEM_ZEROINIT, (wcslen(pSrc) + 1) * 2); wcscpy(pNewStr, pSrc); m_Array[nIndex] = pNewStr; return no_error; } //*************************************************************************** // // CWStringArray::ReplaceAt // // Directly replaces the pointer at the specified location with the // one in the parameter. No copy or cleanup. // // Parameters: // The 0-origin location at which to replace. // The new pointer to copy over the old one. // // Return value: // no_error (No checking done at present). // //*************************************************************************** int CWStringArray::ReplaceAt(int nIndex, wchar_t *pSrc) { m_Array[nIndex] = pSrc; return no_error; } //*************************************************************************** // // CWStringArray::Empty // // Empties the array, deallocates all strings, and sets the apparent // array size to zero. // //*************************************************************************** void CWStringArray::Empty() { for (int i = 0; i < m_Array.Size(); i++) LocalFree(m_Array[i]); m_Array.Empty(); } //*************************************************************************** // // CWStringArray::Sort // // Sorts the array according to UNICODE order. // (Shell sort). // //*************************************************************************** void CWStringArray::Sort() { for (int nInterval = 1; nInterval < m_Array.Size() / 9; nInterval = nInterval * 3 + 1); while (nInterval) { for (int iCursor = nInterval; iCursor < m_Array.Size(); iCursor++) { int iBackscan = iCursor; while (iBackscan - nInterval >= 0 && _wcsicmp((const wchar_t *) m_Array[iBackscan], (const wchar_t *) m_Array[iBackscan-nInterval]) < 0) { wchar_t *pTemp = (wchar_t *) m_Array[iBackscan - nInterval]; m_Array[iBackscan - nInterval] = m_Array[iBackscan]; m_Array[iBackscan] = pTemp; iBackscan -= nInterval; } } nInterval /= 3; } } //*************************************************************************** // // CWStringArray::Difference // // Set-theoretic difference operation on the arrays. // // Parameters: // First array (not modified). // Second array which is 'subtracted' from first (not modified). // Receives the difference. Should be an empty array on entry. // //*************************************************************************** void CWStringArray::Difference( CWStringArray &Src1, CWStringArray &Src2, CWStringArray &Diff ) { for (int i = 0; i < Src1.Size(); i++) if (Src2.FindStr(Src1[i], no_case) == -1) Diff.Add(Src1[i]); } //*************************************************************************** // // CWStringArray::Intersection // // Set-theoretic intersection operation on the arrays. // // Parameters: // First array (not modified). // Second array (not modified). // Receives the intersection. Should be an empty array on entry. //*************************************************************************** void CWStringArray::Intersection( CWStringArray &Src1, CWStringArray &Src2, CWStringArray &Output ) { for (int i = 0; i < Src1.Size(); i++) if (Src2.FindStr(Src1[i], no_case) != -1) Output.Add(Src1[i]); } //*************************************************************************** // // CWStringArray::Union // // Set-theoretic union operation on the arrays. // // Parameters: // First array (not modified). // Second array (not modified). // Receives the union. Should be an empty array on entry. // //*************************************************************************** void CWStringArray::Union( CWStringArray &Src1, CWStringArray &Src2, CWStringArray &Output ) { Output = Src1; for (int i = 0; i < Src2.Size(); i++) if (Output.FindStr(Src2[i], no_case) == not_found) Output.Add(Src2[i]); }