If you want to do high-performance numerical computation in Excel, you will need to use the
FP data type. It is a two dimensional array of double precision floating point numbers defined by Microsoft as follows.
typedef struct _FP
{
unsigned short int rows;
unsigned short int columns;
double array[1]; /* Actually, array[rows][columns] */
} FP;
The funny looking one element array is what Dennis Ritchie deemed "unwarranted chumminess with the compiler." Our wrapper class (also called
FP, but in the xll namespace) uses
placement new to make an honest C++ citizen out of this gimmick.
xll::FP a;
assert (a.is_empty());
assert (a.size() == 0);
xll::FP b(2, 3);
assert (b.rows() == 2 && b.columns() == 3);
b[3] = 4; // 1-d index
assert (b(1, 0) == 4); // 2-d index
b.reshape(3,2);
assert (b.rows() == 3 && b.columns() == 2);
assert (b[3] == 4);
assert (b(1, 1) == 4);
std::sort(b.begin(), b.end()); // STL friendly
Of course Excel knows nothing about this data type so when you get an array passed in from Excel you should declare it as either
_FP or ::FP, but not
xll::FP.
static AddIn xai_array_unique(
"?xll_array_unique", XLL_FP XLL_FP,
"ARRAY.UNIQUE", "Array",
"STL", "Remove consecutive duplicates from Array."
);
_FP* WINAPI
xll_array_unique(const _FP* pa)
{
#pragma XLLEXPORT
static xll::FP a;
// Copy what pa points at to a
a = *pa;
// STL function to remove duplicates
double* pe = std::unique(a.begin(), a.end());
// Size of non-duplicates
a.reshape(static_cast<WORD>(pe - a.begin()), 1);
return a.get();
}
It is a good idea to declare pointers passed in from Excel as
const so the compiler will prevent you from stepping on Excel's memory territory. Note that your
xll::FP is declared
static because FP::get() returns a pointer to a
_FP and that needs to exist after the function call returns so Excel has a chance to copy the array back to its territory.