Support for setting array slices

stable-5.1
Peter Wortmann 2010-08-03 21:47:45 +01:00
parent cf86158d01
commit 24cfd14f1c
5 changed files with 88 additions and 1 deletions

View File

@ -133,6 +133,7 @@ enum C4AulBCCType
AB_ARRAYA, // array or proplist access
AB_ARRAYA_SET,
AB_ARRAY_SLICE, // array slicing
AB_ARRAY_SLICE_SET,
AB_VARN, // a named var
AB_VARN_SET,
AB_PARN, // a named parameter

View File

@ -499,6 +499,30 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
break;
}
case AB_ARRAY_SLICE_SET:
{
C4Value &Array = pCurVal[-3];
C4Value &StartIndex = pCurVal[-2];
C4Value &EndIndex = pCurVal[-1];
C4Value &Value = pCurVal[0];
// Typcheck
if (!Array.ConvertTo(C4V_Array) || Array.GetType() == C4V_Any)
throw new C4AulExecError(pCurCtx->Obj, FormatString("array slice: can't access %s as an array!", Array.GetTypeName()).getData());
if (!StartIndex.ConvertTo(C4V_Int))
throw new C4AulExecError(pCurCtx->Obj, FormatString("array slice: start index of type %s, int expected!", StartIndex.GetTypeName()).getData());
if (!EndIndex.ConvertTo(C4V_Int))
throw new C4AulExecError(pCurCtx->Obj, FormatString("array slice: end index of type %s, int expected!", EndIndex.GetTypeName()).getData());
C4ValueArray *pArray = Array._getArray();
pArray->SetSlice(StartIndex._getInt(), EndIndex._getInt(), Value);
// Set value as result, remove both indices and first copy of value
Array = Value;
PopValues(3);
break;
}
case AB_STACK:
if (pCPos->Par.i < 0)
PopValues(-pCPos->Par.i);

View File

@ -846,6 +846,7 @@ static const char * GetTTName(C4AulBCCType e)
case AB_ARRAYA: return "ARRAYA"; // array access
case AB_ARRAYA_SET: return "ARRAYA_SET"; // setter
case AB_ARRAY_SLICE: return "ARRAY_SLICE";
case AB_ARRAY_SLICE_SET: return "ARRAY_SLICE_SET";
case AB_VARN: return "VARN"; // a named var
case AB_VARN_SET: return "VARN_SET";
case AB_PARN: return "PARN"; // a named parameter
@ -1100,6 +1101,9 @@ int C4AulParseState::GetStackValue(C4AulBCCType eType, intptr_t X)
case AB_PROPSET:
return -2;
case AB_ARRAY_SLICE_SET:
return -3;
default:
assert(false);
}
@ -1199,6 +1203,7 @@ C4AulBCC C4AulParseState::MakeSetter(bool fLeaveValue)
switch (Value.bccType)
{
case AB_ARRAYA: Setter.bccType = AB_ARRAYA_SET; break;
case AB_ARRAY_SLICE: Setter.bccType = AB_ARRAY_SLICE_SET; break;
case AB_PAR: Setter.bccType = AB_PAR_SET; break;
case AB_PARN: Setter.bccType = AB_PARN_SET; break;
case AB_VARN: Setter.bccType = AB_VARN_SET; break;

View File

@ -232,3 +232,58 @@ C4ValueArray * C4ValueArray::GetSlice(int32_t startIndex, int32_t endIndex)
}
}
void C4ValueArray::SetSlice(int32_t startIndex, int32_t endIndex, const C4Value &Val)
{
// index from back
if(startIndex < 0) startIndex += iSize;
if(endIndex < 0) endIndex += iSize;
// ensure relevant bounds
if(startIndex < 0) throw new C4AulExecError(NULL, "Array slice: invalid start index");
if(endIndex < 0) throw new C4AulExecError(NULL, "Array slice: invalid end index");
if(endIndex < startIndex)
endIndex = startIndex;
// setting an array?
if(Val.GetType() == C4V_Array)
{
const C4ValueArray &Other = *Val._getArray();
// Calculcate new size
int32_t iNewEnd = startIndex + Other.GetSize();
int32_t iNewSize = iNewEnd;
if(endIndex < iSize)
iNewSize += iSize - endIndex;
// Pre-resize moving
int32_t i, j;
if(iNewEnd < endIndex)
for(i = iNewEnd, j = endIndex; j < iSize; i++, j++)
pData[i] = pData[j];
// Resize (Note: Lots of unneccessary copying here, could be optimized)
int32_t iOldSize = iSize;
SetSize(iNewSize);
// Post-resize moving
if(iNewEnd > endIndex)
for(i = iNewSize, j = iOldSize; j > endIndex; i--, j--)
pData[i-1] = pData[j-1];
// Copy the data
for(i = startIndex, j = 0; j < Other.GetSize(); i++, j++)
pData[i] = Other.pData[j];
} else /* if(Val.GetType() != C4V_Array) */ {
// Need resize?
if(endIndex > iSize) SetSize(endIndex);
// Fill
for(int32_t i = startIndex; i < endIndex; i++)
pData[i] = Val;
}
}

View File

@ -82,8 +82,10 @@ public:
void IncRef() { iRefCnt++; }
void DecRef() { if (!--iRefCnt) delete this; }
// Return sub-array [startIndex, endIndex), or reference for [0, iSize)
// Return sub-array [startIndex, endIndex), or reference for [0, iSize). Throws C4AulExecError.
C4ValueArray * GetSlice(int32_t startIndex, int32_t endIndex);
// Sets sub-array [startIndex, endIndex). Might resize the array.
void SetSlice(int32_t startIndex, int32_t endIndex, const C4Value &Val);
// Change length
void SetLength(int32_t size);