void CValueTable::SetValue(int ColIdx, int RowIdx, const CData& Val) { const CType* Type = GetColumnValueType(ColIdx); n_assert(!Type || Type == Val.GetType()); n_assert(IsRowValid(RowIdx)); void** pObj = GetValuePtr(ColIdx, RowIdx); if (Type) Type->Copy(IsSpecialType(Type) ? (void**)&pObj : pObj, Val.GetValueObjectPtr()); else *(CData*)pObj = Val; if (Flags.Is(_TrackModifications)) { RowStateBuffer[RowIdx] |= UpdatedRow; Flags.Set(_IsModified); Flags.Set(_HasModifiedRows); } }
void TTable::GroupByStrCol(TStr GroupBy, THash<TStr,TIntV>& Grouping, const TIntV& IndexSet, TBool All) const{ if(!ColTypeMap.IsKey(GroupBy)){TExcept::Throw("no such column " + GroupBy);} if(GetColType(GroupBy) != STR){TExcept::Throw(GroupBy + " values are not of expected type string");} if(All){ // optimize for the common and most expensive case - itearte over all valid rows for(TRowIterator it = BegRI(); it < EndRI(); it++){ UpdateGrouping<TStr>(Grouping, it.GetStrAttr(GroupBy), it.GetRowIdx()); } } else{ // consider only rows in IndexSet for(TInt i = 0; i < IndexSet.Len(); i++){ if(IsRowValid(IndexSet[i])){ TInt RowIdx = IndexSet[i]; UpdateGrouping<TStr>(Grouping, GetStrVal(GroupBy, RowIdx), RowIdx); } } } }
void TTable::GroupByFltCol(TStr GroupBy, THash<TFlt,TIntV>& grouping, const TIntV& IndexSet, TBool All) const{ if(!ColTypeMap.IsKey(GroupBy)){TExcept::Throw("no such column " + GroupBy);} if(GetColType(GroupBy) != FLT){TExcept::Throw(GroupBy + " values are not of expected type float");} if(All){ // optimize for the common and most expensive case - itearte over only valid rows for(TRowIterator it = BegRI(); it < EndRI(); it++){ UpdateGrouping<TFlt>(grouping, it.GetFltAttr(GroupBy), it.GetRowIdx()); } } else{ // consider only rows in IndexSet for(TInt i = 0; i < IndexSet.Len(); i++){ if(IsRowValid(IndexSet[i])){ TInt RowIdx = IndexSet[i]; const TFltV& Col = FltCols[GetColIdx(GroupBy)]; UpdateGrouping<TFlt>(grouping, Col[RowIdx], RowIdx); } } } }
// Finds a row index by single attribute value. This method can be slow since // it may search linearly (and vertically) through the table. // FIXME: keep row indices for indexed rows in nDictionaries? nArray<int> CValueTable::InternalFindRowIndicesByAttr(CAttrID AttrID, const CData& Value, bool FirstMatchOnly) const { nArray<int> Result; int ColIdx = GetColumnIndex(AttrID); const CType* Type = GetColumnValueType(ColIdx); n_assert(Type == Value.GetType()); for (int RowIdx = 0; RowIdx < GetRowCount(); RowIdx++) { if (IsRowValid(RowIdx)) { void** pObj = GetValuePtr(ColIdx, RowIdx); if (Type->IsEqualT(Value.GetValueObjectPtr(), IsSpecialType(Type) ? (void*)pObj : *pObj)) { Result.Append(RowIdx); if (FirstMatchOnly) return Result; } } } return Result; }
// This marks a row for deletion. Note that the row will only be marked // for deletion, deleted row indices are returned with the GetDeletedRowIndices() // call. The row will never be physically removed from memory! void CValueTable::DeleteRow(int RowIdx) { n_assert(IsRowValid(RowIdx)); if (Flags.Is(_TrackModifications)) { if (FirstDeletedRowIndex > RowIdx) FirstDeletedRowIndex = RowIdx; RowStateBuffer[RowIdx] |= DeletedRow; ++DeletedRowsCount; // NewRow flag has priority over DeletedRow flag, so clear it when new row deleted if (RowStateBuffer[RowIdx] & NewRow) { RowStateBuffer[RowIdx] &= ~NewRow; --NewRowsCount; } Flags.Set(_IsModified); } //UserData[RowIdx] = NULL; //???use refcounted to autokill? }