tdf#151001: Add support for EXPAND function

Change-Id: I4eabd526d656c13da7792d3c195f036ce78bd0d9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180706
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Xisco Fauli
2025-01-24 16:57:21 +01:00
parent 32f0b68a9c
commit 5506dd8bcf
18 changed files with 6188 additions and 8 deletions
+6
View File
@@ -282,6 +282,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF[] =
{ "COM.MICROSOFT.SORT" , SC_OPCODE_SORT },
{ "COM.MICROSOFT.SORTBY" , SC_OPCODE_SORTBY },
{ "COM.MICROSOFT.DROP" , SC_OPCODE_DROP },
{ "COM.MICROSOFT.EXPAND" , SC_OPCODE_EXPAND },
{ "COM.MICROSOFT.TAKE" , SC_OPCODE_TAKE },
{ "COM.MICROSOFT.TOCOL" , SC_OPCODE_TOCOL },
{ "COM.MICROSOFT.TOROW" , SC_OPCODE_TOROW },
@@ -745,6 +746,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML[] =
{ "_xlfn._xlws.SORT" , SC_OPCODE_SORT },
{ "_xlfn.SORTBY" , SC_OPCODE_SORTBY },
{ "_xlfn.DROP" , SC_OPCODE_DROP },
{ "_xlfn.EXPAND" , SC_OPCODE_EXPAND },
{ "_xlfn.TAKE" , SC_OPCODE_TAKE },
{ "_xlfn.TOCOL" , SC_OPCODE_TOCOL },
{ "_xlfn.TOROW" , SC_OPCODE_TOROW },
@@ -1211,6 +1213,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_PODF[] =
{ "SORT" , SC_OPCODE_SORT },
{ "SORTBY" , SC_OPCODE_SORTBY },
{ "DROP" , SC_OPCODE_DROP },
{ "EXPAND" , SC_OPCODE_EXPAND },
{ "TAKE" , SC_OPCODE_TAKE },
{ "TOCOL" , SC_OPCODE_TOCOL },
{ "TOROW" , SC_OPCODE_TOROW },
@@ -1677,6 +1680,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_API[] =
{ "SORT" , SC_OPCODE_SORT },
{ "SORTBY" , SC_OPCODE_SORTBY },
{ "DROP" , SC_OPCODE_DROP },
{ "EXPAND" , SC_OPCODE_EXPAND },
{ "TAKE" , SC_OPCODE_TAKE },
{ "TOCOL" , SC_OPCODE_TOCOL },
{ "TOROW" , SC_OPCODE_TOROW },
@@ -2141,6 +2145,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH[] =
{ "SORT" , SC_OPCODE_SORT },
{ "SORTBY" , SC_OPCODE_SORTBY },
{ "DROP" , SC_OPCODE_DROP },
{ "EXPAND" , SC_OPCODE_EXPAND },
{ "TAKE" , SC_OPCODE_TAKE },
{ "TOCOL" , SC_OPCODE_TOCOL },
{ "TOROW" , SC_OPCODE_TOROW },
@@ -2586,6 +2591,7 @@ const std::pair<TranslateId, int> RID_STRLIST_FUNCTION_NAMES[] =
{ NC_("RID_STRLIST_FUNCTION_NAMES", "SORT") , SC_OPCODE_SORT },
{ NC_("RID_STRLIST_FUNCTION_NAMES", "SORTBY") , SC_OPCODE_SORTBY },
{ NC_("RID_STRLIST_FUNCTION_NAMES", "DROP") , SC_OPCODE_DROP },
{ NC_("RID_STRLIST_FUNCTION_NAMES", "EXPAND") , SC_OPCODE_EXPAND },
{ NC_("RID_STRLIST_FUNCTION_NAMES", "TAKE") , SC_OPCODE_TAKE },
{ NC_("RID_STRLIST_FUNCTION_NAMES", "TOCOL") , SC_OPCODE_TOCOL },
{ NC_("RID_STRLIST_FUNCTION_NAMES", "TOROW") , SC_OPCODE_TOROW },
@@ -1280,6 +1280,7 @@ bool FormulaCompiler::IsMatrixFunction( OpCode eOpCode )
case ocSortBy :
case ocRandArray :
case ocDrop :
case ocExpand :
case ocTake :
case ocToCol :
case ocToRow :
+8 -7
View File
@@ -518,13 +518,14 @@
#define SC_OPCODE_MAT_SEQUENCE 503
#define SC_OPCODE_RANDARRAY 504
#define SC_OPCODE_DROP 505
#define SC_OPCODE_TAKE 506
#define SC_OPCODE_TOCOL 507
#define SC_OPCODE_TOROW 508
#define SC_OPCODE_UNIQUE 509
#define SC_OPCODE_WRAPCOLS 510
#define SC_OPCODE_WRAPROWS 511
#define SC_OPCODE_STOP_2_PAR 512 /* last function with two or more parameters' OpCode + 1 */
#define SC_OPCODE_EXPAND 506
#define SC_OPCODE_TAKE 507
#define SC_OPCODE_TOCOL 508
#define SC_OPCODE_TOROW 509
#define SC_OPCODE_UNIQUE 510
#define SC_OPCODE_WRAPCOLS 511
#define SC_OPCODE_WRAPROWS 512
#define SC_OPCODE_STOP_2_PAR 513 /* last function with two or more parameters' OpCode + 1 */
#define SC_OPCODE_STOP_FUNCTION SC_OPCODE_STOP_2_PAR /* last function's OpCode + 1 */
#define SC_OPCODE_LAST_OPCODE_ID (SC_OPCODE_STOP_FUNCTION - 1) /* last OpCode */
+2
View File
@@ -514,6 +514,7 @@ enum OpCode : sal_uInt16
ocMatSequence = SC_OPCODE_MAT_SEQUENCE,
ocRandArray = SC_OPCODE_RANDARRAY,
ocDrop = SC_OPCODE_DROP,
ocExpand = SC_OPCODE_EXPAND,
ocTake = SC_OPCODE_TAKE,
ocToCol = SC_OPCODE_TOCOL,
ocToRow = SC_OPCODE_TOROW,
@@ -1005,6 +1006,7 @@ inline std::string OpCodeEnumToString(OpCode eCode)
case ocSort: return "Sort";
case ocSortBy: return "SortBy";
case ocDrop: return "Drop";
case ocExpand: return "Expand";
case ocTake: return "Take";
case ocToCol: return "ToCol";
case ocToRow: return "ToRow";
+1
View File
@@ -56,6 +56,7 @@ https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part4-formula/OpenDocume
* Array Functions
* DROP
* EXPAND
* TAKE
* TOCOL
* TOROW
+1
View File
@@ -601,6 +601,7 @@ inline constexpr OUString HID_FUNC_FILTER_MS = u"SC_HID_FUNC_FILTER_MS"_ustr;
inline constexpr OUString HID_FUNC_SORT_MS = u"SC_HID_FUNC_SORT_MS"_ustr;
inline constexpr OUString HID_FUNC_SORTBY_MS = u"SC_HID_FUNC_SORTBY_MS"_ustr;
inline constexpr OUString HID_FUNC_DROP_MS = u"SC_HID_FUNC_DROP_MS"_ustr;
inline constexpr OUString HID_FUNC_EXPAND_MS = u"SC_HID_FUNC_EXPAND_MS"_ustr;
inline constexpr OUString HID_FUNC_TAKE_MS = u"SC_HID_FUNC_TAKE_MS"_ustr;
inline constexpr OUString HID_FUNC_TOCOL_MS = u"SC_HID_FUNC_TOCOL_MS"_ustr;
inline constexpr OUString HID_FUNC_TOROW_MS = u"SC_HID_FUNC_TOROW_MS"_ustr;
+14
View File
@@ -4263,6 +4263,20 @@ const TranslateId SC_OPCODE_DROP_ARY[] =
NC_("SC_OPCODE_DROP", "The number of columns to drop. A negative value drops from the end of the array.")
};
// -=*# Resource for function EXPAND #*=-
const TranslateId SC_OPCODE_EXPAND_ARY[] =
{
NC_("SC_OPCODE_EXPAND", "Expands or pads an array to specified row and column dimensions."),
NC_("SC_OPCODE_EXPAND", "Array"),
NC_("SC_OPCODE_EXPAND", "The array to expand."),
NC_("SC_OPCODE_EXPAND", "Rows"),
NC_("SC_OPCODE_EXPAND", "The number of rows in the expanded array. If missing, rows will not be expanded."),
NC_("SC_OPCODE_EXPAND", "Column"),
NC_("SC_OPCODE_EXPAND", "The number of columns in the expanded array. If missing, columns will not be expanded."),
NC_("SC_OPCODE_EXPAND", "Pad with"),
NC_("SC_OPCODE_EXPAND", "The value with which to pad. The default is #N/A.")
};
// -=*# Resource for function TAKE #*=-
const TranslateId SC_OPCODE_TAKE_ARY[] =
{
+1 -1
View File
@@ -77,7 +77,7 @@ public:
ScFunctionListObj::ScFunctionListObj()
: UnoApiTest(u"/sc/qa/extras/testdocuments"_ustr)
, XElementAccess(cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get())
, XIndexAccess(410)
, XIndexAccess(411)
, XNameAccess(u"IF"_ustr)
, XServiceInfo(u"stardiv.StarCalc.ScFunctionListObj"_ustr,
u"com.sun.star.sheet.FunctionDescriptions"_ustr)
File diff suppressed because it is too large Load Diff
+1
View File
@@ -3103,6 +3103,7 @@ CPPUNIT_TEST_FIXTURE(Test, testFunctionLists)
"DROP",
"ERROR.TYPE",
"ERRORTYPE",
"EXPAND",
"FILTER",
"GETPIVOTDATA",
"HLOOKUP",
+1
View File
@@ -794,6 +794,7 @@ ScFunctionList::ScFunctionList( bool bEnglishFunctionNames )
{ SC_OPCODE_MAT_SEQUENCE, ENTRY(SC_OPCODE_MAT_SEQUENCE_ARY), 0, ID_FUNCTION_GRP_MATRIX, HID_FUNC_MSEQUENCE_MS, 4, { 0, 1, 1, 1 }, 0 },
{ SC_OPCODE_RANDARRAY, ENTRY(SC_OPCODE_RANDARRAY_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_RANDARRAY_MS, 5, { 1, 1, 1, 1, 1 }, 0 },
{ SC_OPCODE_DROP, ENTRY(SC_OPCODE_DROP_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_DROP_MS, 3, { 0, 0, 1 }, 0 },
{ SC_OPCODE_EXPAND, ENTRY(SC_OPCODE_EXPAND_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_EXPAND_MS, 4, { 0, 0, 1, 1 }, 0 },
{ SC_OPCODE_TAKE, ENTRY(SC_OPCODE_TAKE_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_TAKE_MS, 3, { 0, 1, 1 }, 0 },
{ SC_OPCODE_TOCOL, ENTRY(SC_OPCODE_TOCOL_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_TOCOL_MS, 3, { 0, 1, 1 }, 0 },
{ SC_OPCODE_TOROW, ENTRY(SC_OPCODE_TOROW_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_TOROW_MS, 3, { 0, 1, 1 }, 0 },
+1
View File
@@ -725,6 +725,7 @@ private:
void ScSort();
void ScSortBy();
void ScDrop();
void ScExpand();
void ScTake();
void ScToCol();
void ScToRow();
+134
View File
@@ -8936,6 +8936,140 @@ void ScInterpreter::ScDrop()
PushMatrix(pResMat);
}
void ScInterpreter::ScExpand()
{
sal_uInt8 nParamCount = GetByte();
if (!MustHaveParamCount(nParamCount, 2, 4))
return;
// 4rd argument optional - pad_with
std::optional<bool> bDouble;
double fNumber(0.0);
svl::SharedString aString;
if (nParamCount == 4)
bDouble = GetDoubleOrString(fNumber, aString);
// 3rd argument optional - columns
std::optional<sal_Int32> nArgCols;
if (nParamCount >= 3)
{
if (!IsMissing())
nArgCols = GetInt32();
else
Pop();
}
// 2nd argument - rows
std::optional<sal_Int32> nArgRows;
if (nParamCount >= 2)
{
if (!IsMissing())
nArgRows = GetInt32();
else
Pop();
}
// 1st argument: take unique search range
ScMatrixRef pMatSource = nullptr;
SCSIZE nsC = 0, nsR = 0;
switch (GetStackType())
{
case svSingleRef:
case svDoubleRef:
case svMatrix:
case svExternalSingleRef:
case svExternalDoubleRef:
{
pMatSource = GetMatrix();
if (!pMatSource)
{
PushIllegalParameter();
return;
}
pMatSource->GetDimensions(nsC, nsR);
}
break;
default:
PushIllegalParameter();
return;
}
if (nGlobalError != FormulaError::NONE || nsC < 1 || nsR < 1)
{
PushIllegalArgument();
return;
}
SCSIZE nColumns = nsC;
SCSIZE nRows = nsR;
if (nArgCols.has_value())
{
if (o3tl::make_unsigned(std::abs(nArgCols.value())) < nsC)
{
PushIllegalArgument();
return;
}
else
nColumns = nArgCols.value();
}
if (nArgRows.has_value())
{
if (o3tl::make_unsigned(std::abs(nArgRows.value())) < nsR)
{
PushIllegalArgument();
return;
}
else
nRows = nArgRows.value();
}
ScMatrixRef pResMat = GetNewMat(nColumns, nRows, /*bEmpty*/true);
if (!pResMat)
{
PushIllegalArgument();
return;
}
for (SCSIZE col = 0; col < nColumns; ++col)
{
for (SCSIZE row = 0; row < nRows; ++row)
{
if (col < nsC && row < nsR)
{
if (pMatSource->IsEmptyCell(col, row))
{
pResMat->PutEmpty(col, row);
}
else if (!pMatSource->IsStringOrEmpty(col, row))
{
pResMat->PutDouble(pMatSource->GetDouble(col, row), col, row);
}
else
{
pResMat->PutString(pMatSource->GetString(col, row), col, row);
}
}
else
{
if (bDouble.has_value())
{
if (bDouble.value())
pResMat->PutDouble(fNumber, col, row);
else
pResMat->PutString(aString, col, row);
}
else
pResMat->PutError(FormulaError::NotAvailable, col, row);
}
}
}
PushMatrix(pResMat);
}
void ScInterpreter::ScTake()
{
sal_uInt8 nParamCount = GetByte();
+1
View File
@@ -4160,6 +4160,7 @@ StackVar ScInterpreter::Interpret()
case ocSort : ScSort(); break;
case ocSortBy : ScSortBy(); break;
case ocDrop : ScDrop(); break;
case ocExpand : ScExpand(); break;
case ocTake : ScTake(); break;
case ocToCol : ScToCol(); break;
case ocToRow : ScToRow(); break;
+1
View File
@@ -137,6 +137,7 @@ const ScParameterClassification::RawData ScParameterClassification::pRawData[] =
{ ocDevSq, {{ Reference }, 1, Value }},
{ ocDiv, {{ Array, Array }, 0, Value }},
{ ocDrop, {{ ReferenceOrRefArray, Value, Value, }, 0, ForceArrayReturn } },
{ ocExpand, {{ ReferenceOrRefArray, Value, Value, }, 0, ForceArrayReturn } },
{ ocEqual, {{ Array, Array }, 0, Value }},
{ ocFTest, {{ ForceArray, ForceArray }, 0, Value }},
{ ocFalse, {{ Bounds }, 0, Value }},
+1
View File
@@ -1592,6 +1592,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r )
case ocMatSequence:
case ocRandArray:
case ocDrop:
case ocExpand:
case ocTake:
case ocToCol:
case ocToRow:
+1
View File
@@ -620,6 +620,7 @@ const XclFunctionInfo saFuncTable_2021[] =
const XclFunctionInfo saFuncTable_2024[] =
{
EXC_FUNCENTRY_V_VR( ocDrop, 1, 3, 0, "DROP" ),
EXC_FUNCENTRY_V_VR( ocExpand, 2, 4, 0, "EXPAND" ),
EXC_FUNCENTRY_V_VR( ocTake, 1, 3, 0, "TAKE" ),
EXC_FUNCENTRY_V_VR( ocToCol, 1, 3, 0, "TOCOL" ),
EXC_FUNCENTRY_V_VR( ocToRow, 1, 3, 0, "TOROW" ),
+1
View File
@@ -895,6 +895,7 @@ const FunctionData saFuncTable2021[] =
const FunctionData saFuncTable2024[] =
{
{ "COM.MICROSOFT.DROP", "DROP", NOID, NOID, 1, 3, A, { VO }, FuncFlags::MACROCALL_NEW },
{ "COM.MICROSOFT.EXPAND", "EXPAND", NOID, NOID, 2, 4, A, { VO }, FuncFlags::MACROCALL_NEW },
{ "COM.MICROSOFT.TAKE", "TAKE", NOID, NOID, 1, 3, A, { VO }, FuncFlags::MACROCALL_NEW },
{ "COM.MICROSOFT.TOCOL", "TOCOL", NOID, NOID, 1, 3, A, { VO }, FuncFlags::MACROCALL_NEW },
{ "COM.MICROSOFT.TOROW", "TOROW", NOID, NOID, 1, 3, A, { VO }, FuncFlags::MACROCALL_NEW },