/// Insert one or more rows into this sequence void c4_Sequence::InsertAt(int index_, c4_Cursor newElem_, int count_) { d4_assert(newElem_._seq != 0); c4_Notifier change(this); if (GetDependencies()) { change.StartInsertAt(index_, newElem_, count_); } SetNumRows(NumRows() + count_); c4_Bytes data; for (int i = 0; i < newElem_._seq->NumHandlers(); ++i) { c4_Handler &h = newElem_._seq->NthHandler(i); // added 06-12-1999 to do index remapping for derived seq's const c4_Sequence *hc = newElem_._seq->HandlerContext(i); int ri = newElem_._seq->RemapIndex(newElem_._index, hc); int colNum = PropIndex(h.Property()); d4_assert(colNum >= 0); if (h.Property().Type() == 'V') { // If inserting from self: Make sure we get a copy of the bytes, // so we don't get an invalid pointer if the memory get realloc'ed h.GetBytes(ri, data, newElem_._seq == this); // special treatment for subviews, insert empty, then overwrite // changed 19990904 - probably fixes a long-standing limitation c4_Bytes temp; h.ClearBytes(temp); c4_Handler &h2 = NthHandler(colNum); h2.Insert(index_, temp, count_); for (int j = 0; j < count_; ++j) { h2.Set(index_ + j, data); } } else { h.GetBytes(ri, data); NthHandler(colNum).Insert(index_, data, count_); } } // if number of props in dest is larger after adding, clear the rest // this way, new props get copied and undefined props get cleared if (newElem_._seq->NumHandlers() < NumHandlers()) { for (int j = 0; j < NumHandlers(); ++j) { c4_Handler &h = NthHandler(j); // if the property does not appear in the source if (newElem_._seq->PropIndex(h.PropId()) < 0) { h.ClearBytes(data); h.Insert(index_, data, count_); } } } }
/// Find the index of a property by its id int c4_Sequence::PropIndex(int propId_) { //! CACHING NOTE: derived views will fail if underlying view is restructured // still, this cache is kept, since sort will fail anyway... // The only safe change in these cases is adding new properties at the end. // use the map for the fastest result once known if (propId_ < _propertyLimit && _propertyMap[propId_] >= 0) { return _propertyMap[propId_]; } // locate the property using a linear search, return if not present int n = NumHandlers(); do { if (--n < 0) { return - 1; } } while (NthPropId(n) != propId_); // if the map is too small, resize it (with a little slack) if (propId_ >= _propertyLimit) { int round = (propId_ + 8) & ~0x07; short *vec = d4_new short[round]; for (int i = 0; i < round; ++i) { vec[i] = i < _propertyLimit ? _propertyMap[i] : - 1; } if (_propertyLimit > 0) { delete [] _propertyMap; } _propertyMap = vec; _propertyLimit = round; }
c4_HandlerSeq::~c4_HandlerSeq() { const bool rootLevel = _parent == this; c4_Persist *pers = _persist; if (rootLevel && pers != 0) { pers->DoAutoCommit(); } DetachFromParent(); DetachFromStorage(true); for (int i = 0; i < NumHandlers(); ++i) { delete &NthHandler(i); } _handlers.SetSize(0); ClearCache(); if (rootLevel) { delete _field; d4_assert(pers != 0); delete pers; } }
void c4_HandlerSeq::DetachFromStorage(bool full_) { if (_persist != 0) { int limit = full_ ? 0 : NumFields(); // get rid of all handlers which might do I/O for (int c = NumHandlers(); --c >= 0;) { c4_Handler &h = NthHandler(c); // all nested fields are detached recursively if (IsNested(c)) for (int r = 0; r < NumRows(); ++r) if (h.HasSubview(r)) { SubEntry(c, r).DetachFromStorage(full_); } if (c >= limit) { if (h.IsPersistent()) { delete &h; _handlers.RemoveAt(c); ClearCache(); } } } if (full_) { //UnmappedAll(); _persist = 0; } } }
/// Move a row to another position void c4_Sequence::Move(int from_, int to_) { c4_Notifier change(this); if (GetDependencies()) change.StartMove(from_, to_); //! careful, this does no index remapping, wrong for derived seq's for (int i = 0; i < NumHandlers(); ++i) NthHandler(i).Move(from_, to_); }
/// Replace the contents of a specified row void c4_Sequence::SetAt(int index_, c4_Cursor newElem_) { d4_assert(newElem_._seq != 0); c4_Bytes data; c4_Notifier change(this); if(GetDependencies()) change.StartSetAt(index_, newElem_); for(int i = 0; i < newElem_._seq->NumHandlers(); ++i) { c4_Handler &h = newElem_._seq->NthHandler(i); // added 06-12-1999 to do index remapping for derived seq's const c4_Sequence *hc = newElem_._seq->HandlerContext(i); int ri = newElem_._seq->RemapIndex(newElem_._index, hc); h.GetBytes(ri, data); // Set(index_, cursor._seq->NthProperty(i), data); int colNum = PropIndex(h.Property()); d4_assert(colNum >= 0); NthHandler(colNum).Set(index_, data); } // if number of props in dest is larger after adding, clear the rest // this way, new props get copied and undefined props get cleared if(newElem_._seq->NumHandlers() < NumHandlers()) { for(int j = 0; j < NumHandlers(); ++j) { c4_Handler &h = NthHandler(j); // if the property does not appear in the source if(newElem_._seq->PropIndex(h.PropId()) < 0) { h.ClearBytes(data); h.Set(index_, data); } } } }
/// Remove one or more rows from this sequence void c4_Sequence::RemoveAt(int index_, int count_) { c4_Notifier change(this); if (GetDependencies()) change.StartRemoveAt(index_, count_); SetNumRows(NumRows() - count_); //! careful, this does no index remapping, wrong for derived seq's for (int i = 0; i < NumHandlers(); ++i) NthHandler(i).Remove(index_, count_); }
/// Change number of rows, either by inserting or removing them void c4_Sequence::Resize(int newSize_, int) { if (NumHandlers() > 0) { int diff = newSize_ - NumRows(); if (diff > 0) { c4_Row empty; // make sure this doesn't recurse, see below InsertAt(NumRows(), &empty, diff); } else if (diff < 0) RemoveAt(newSize_, - diff); } else // need special case to avoid recursion for c4_Row allocations SetNumRows(newSize_); }
/// Compare the specified row with another one int c4_Sequence::Compare(int index_, c4_Cursor cursor_)const { d4_assert(cursor_._seq != 0); c4_Bytes data; for (int colNum = 0; colNum < NumHandlers(); ++colNum) { c4_Handler &h = NthHandler(colNum); const c4_Sequence *hc = HandlerContext(colNum); int i = RemapIndex(index_, hc); if (!cursor_._seq->Get(cursor_._index, h.PropId(), data)) h.ClearBytes(data); int f = h.Compare(i, data); if (f != 0) return f; } return 0; }
void c4_HandlerSeq::Restructure(c4_Field &field_, bool remove_) { //d4_assert(_field != 0); // all nested fields must be set up, before we shuffle them around for (int k = 0; k < NumHandlers(); ++k) if (IsNested(k)) { c4_Handler &h = NthHandler(k); for (int n = 0; n < NumRows(); ++n) if (h.HasSubview(n)) { SubEntry(k, n); } } for (int i = 0; i < field_.NumSubFields(); ++i) { c4_Field &nf = field_.SubField(i); c4_Property prop(nf.Type(), nf.Name()); int n = PropIndex(prop.GetId()); if (n == i) { continue; } if (n < 0) { _handlers.InsertAt(i, f4_CreateFormat(prop, *this)); NthHandler(i).Define(NumRows(), 0); } else { // move the handler to the front d4_assert(n > i); _handlers.InsertAt(i, _handlers.GetAt(n)); _handlers.RemoveAt(++n); } ClearCache(); // we mess with the order of handler, keep clearing it d4_assert(PropIndex(prop.GetId()) == i); } c4_Field *ofld = _field; // special case if we're "restructuring a view out of persistence", see below _field = remove_ ? 0 : &field_; // let handler do additional init once all have been prepared //for (int n = 0; n < NumHandlers(); ++n) // NthHandler(n).Define(NumRows(), 0); const char *desc = "[]"; c4_Field temp(desc); // all nested fields are restructured recursively for (int j = 0; j < NumHandlers(); ++j) if (IsNested(j)) { c4_Handler &h = NthHandler(j); for (int n = 0; n < NumRows(); ++n) if (h.HasSubview(n)) { c4_HandlerSeq &seq = SubEntry(j, n); if (j < NumFields()) { seq.Restructure(field_.SubField(j), false); } else if (seq._field != 0) { seq.Restructure(temp, true); } } } if (_parent == this) { delete ofld; } // the root table owns its field structure tree }