|
-
May 2nd, 2012, 09:26 PM
#12
Re: Is there ASCII equivalent of CStringArray?
Here is a final version of the functions. Please note that everything posted here is not the greatest, final version that someone could come up with. Again, this was done quickly without any peer-review or extensive testing for flaws. But hopefully it gets the main idea across:
Here is CStringArrayUtils.h:
Code:
#pragma once
#include "stdafx.h"
#include <algorithm>
namespace CStringArrayUtils
{
template <typename T>
struct IndexSearcher
{
T m_srch;
IndexSearcher(const T& srch) : m_srch(srch) { }
bool operator()(const T& s) const
{
T strCur = s;
strCur.TrimRight();
return ( strCur == m_srch );
}
};
template <typename T>
struct CaseFinder
{
T m_srch;
CaseFinder(const T& srch) : m_srch(srch) { }
bool operator()(const T& s) const
{ return s.CompareNoCase(m_srch) == 0; }
};
template <typename CStringArrayType, typename UtilityFn>
int GetIndex(const CStringArrayType& arr, UtilityFn fn)
{
struct TempClass : public CStringArrayType
{ typedef CStringArrayType::BASE_TYPE STRING_TYPE; };
typedef TempClass::STRING_TYPE CStringType;
INT_PTR nItems = arr.GetCount();
const CStringType* ptr = std::find_if(arr.GetData(), arr.GetData() + nItems, fn);
int index = (int)std::distance(arr.GetData(), ptr);
if (index >= nItems )
return -1;
return index;
}
template <typename CStringArrayType>
struct DifferenceCreator
{
// Get the underlying CString type from the CStringArrayType
// This kludge is necessary, since MFC has the type as protected
struct TempClass : public CStringArrayType
{ typedef CStringArrayType::BASE_TYPE STRING_TYPE; };
typedef TempClass::STRING_TYPE CStringType;
const CStringArrayType* m_arr;
CStringArrayType* m_out;
DifferenceCreator(const CStringArrayType* arr, CStringArrayType* out) : m_arr(arr), m_out(out) {}
void operator()(const CStringType& str) const
{
if ( GetIndex(*m_arr, CaseFinder<CStringType>( str ) ) == -1 )
m_out->Add( str );
}
};
template <typename CStringArrayType>
void GetDifference(const CStringArrayType& arr1, const CStringArrayType& arr2, CStringArrayType& out)
{
// get difference for entire array
std::for_each(arr2.GetData(), arr2.GetData() + arr2.GetCount(),
DifferenceCreator<CStringArrayType>(&arr1, &out));
}
}
Here is a sample:
Code:
#include "stdafx.h"
#include "CStringArrayUtils.h"
using namespace CStringArrayUtils;
int main()
{
CStringArray testa, testb, testc;
testa.Add(CString("abc123"));
testa.Add(CString("xxxxxx"));
testa.Add(CString("x3"));
testb.Add(CString("abc123"));
testb.Add(CString("xxx2xxx"));
GetDifference(testa, testb, testc); // testc now has the difference
CString findstr1 = _T("xxxxxx");
CString findstr2 = _T("xxxx1x");
int in1 = GetIndex(testa, IndexSearcher<CString>( findstr1 ));
int in2 = GetIndex(testa, CaseFinder<CString>( findstr2 ));
}
The GetDifference is now a templated function, with the template dependent on the CStringArray type (either CStringArray, or CStringArrayA).
I changed a few things so that I could get the CString type from the CStringArray type. I don't know why MFC hides the BASE_TYPE typedef as protected, but that temporary struct I have in those classes are done only to get the BASE_TYPE of the CStringArray available to the functions. If MFC had made the BASE_TYPE typedef public, those extraneous three lines of code setting up a struct would not be necessary. I tested with VS 2008, so I don't know if the typedef has been moved to public in VS 2010.
Note that GetDifference() uses for_each and the DifferenceCreator function object, which itself uses GetIndex() and CaseFinder() to determine if the string is in the other array. Also note something surprising -- no for() loops in the entire code base.
All of this would be great if there was actually a CStringArrayA that follows the pattern of CStringArray, but I don't think it would be that difficult if you created such a class.
Code:
class CStringArrayA
{
CArray<CStringA, CStringA&> m_arr;
public:
typedef CStringA BASE_TYPE;
void Add(const CStringA& str) { m_arr.Add(str); }
// etc...
};
Then you continue on from there adding the rest of the functions to this class. Then you can use this class in the code above.
But the real point I'm showing you is that if there was the other CStringArrayA class, you need not have to duplicate all of these derived functions in that class, as the code would work for CStringArray, CStringArrayA, or any other class that has the same "pattern" as the CStringArray MFC class. As you can see, no derivation was done, the code is flexible in terms of supporting any CStringArray type that follows the MFC CStringArray pattern, and it is one area of the code (the header file).
If you want to see a small example of this very same concept I showed you, look at CStringT from ATL. You see that the arguments to that template describe how CStringT is supposed to behave based on compile-time type information.
Regards,
Paul McKenzie
Last edited by Paul McKenzie; May 5th, 2012 at 02:43 AM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|