forked from Mirrors/openclonk
Support for setting array slices
parent
cf86158d01
commit
24cfd14f1c
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue