同步操作将从 陈炳煌/sqlitebrowser 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
#ifndef ROW_CACHE_H#define ROW_CACHE_H#include <vector>#include <numeric>#include <algorithm>#include <stdexcept>/**cache structure adapted to the existing access patterns inSqliteTableModel. handles many large segments with gaps in betweenwell.logical structure resembling a std::vector<std::optional<T>>, butimplementation avoids actually allocating space for the non-emptyoptionals, and supports (hopefully) more efficient insertion /deletion.actually, this is not even a "cache" - once set, elements are neverthrown away to make space for new elements.TODO introduce maximum segment size?**/template <typename T>class RowCache{public:using value_type = T;/// constructs an empty cacheexplicit RowCache ();/// \returns number of cached rowssize_t numSet () const;/// \returns number of segmentssize_t numSegments () const;/// \returns 1 if specified row is loaded, 0 otherwisesize_t count (size_t pos) const;/// \returns specified row. \throws if not availableconst T & at (size_t pos) const;T & at (size_t pos);/// assigns value to specified row; may increase numSet() by onevoid set (size_t pos, T && value);/// insert new element; increases numSet() by onevoid insert (size_t pos, T && value);/// delete element; decreases numSet() by onevoid erase (size_t pos);/// reset to state after constructionvoid clear ();/// given a range of rows (end is exclusive), narrow it in order/// to remove already-loaded rows from both ends.void smallestNonAvailableRange (size_t & row_begin, size_t & row_end) const;private:/// a single segment containing contiguous entriesstruct Segment{size_t pos_begin;std::vector<T> entries;/// returns past-the-end position of this segmentsize_t pos_end () const { return pos_begin + entries.size(); }};/// collection of non-overlapping segments, in order of increasing/// positionusing Segments = std::vector<Segment>;Segments segments;// ------------------------------------------------------------------------------/// \returns first segment that definitely cannot contain 'pos',/// because it starts at some later position.typename Segments::const_iterator getSegmentBeyond (size_t pos) const {// first segment whose pos_begin > pos (so can't contain pos itself):return std::upper_bound(segments.begin(), segments.end(), pos, pred);}typename Segments::iterator getSegmentBeyond (size_t pos) {return std::upper_bound(segments.begin(), segments.end(), pos, pred);}static bool pred (size_t pos, const Segment & s) { return pos < s.pos_begin; }// ------------------------------------------------------------------------------/// \returns segment containing 'pos'typename Segments::const_iterator getSegmentContaining (size_t pos) const{auto it = getSegmentBeyond(pos);if(it != segments.begin()) {auto prev_it = it - 1;if(pos < prev_it->pos_end())return prev_it;}return segments.end();}};template <typename T>RowCache<T>::RowCache (){}template <typename T>size_t RowCache<T>::numSet () const{return std::accumulate(segments.begin(), segments.end(), size_t(0),[](size_t r, const Segment & s) { return r + s.entries.size(); });}template <typename T>size_t RowCache<T>::numSegments () const{return segments.size();}template <typename T>size_t RowCache<T>::count (size_t pos) const{return getSegmentContaining(pos) != segments.end();}template <typename T>const T & RowCache<T>::at (size_t pos) const{auto it = getSegmentContaining(pos);if(it != segments.end())return it->entries[pos - it->pos_begin];throw std::out_of_range("no matching segment found");}template <typename T>T & RowCache<T>::at (size_t pos){return const_cast<T&>(static_cast<const RowCache &>(*this).at(pos));}template <typename T>void RowCache<T>::set (size_t pos, T && value){auto it = getSegmentBeyond(pos);if(it != segments.begin()){auto prev_it = it - 1;auto d = pos - prev_it->pos_begin; // distance from segment start (>=0)if(d < prev_it->entries.size()){// replace valueprev_it->entries[d] = std::move(value);return;}if(d == prev_it->entries.size()){// extend existing segmentprev_it->entries.insert(prev_it->entries.end(), std::move(value));return;}}// make new segmentsegments.insert(it, { pos, { std::move(value) } });}template <typename T>void RowCache<T>::insert (size_t pos, T && value){auto it = getSegmentBeyond(pos);if(it != segments.begin()){auto prev_it = it - 1;auto d = pos - prev_it->pos_begin; // distance from segment start (>=0)if(d <= prev_it->entries.size()){// can extend existing segmentprev_it->entries.insert(prev_it->entries.begin() + d, std::move(value));goto push;}}// make new segmentit = segments.insert(it, { pos, { std::move(value) } }) + 1;push:// push back all later segmentsstd::for_each(it, segments.end(), [](Segment &s){ s.pos_begin++; });}template <typename T>void RowCache<T>::erase (size_t pos){auto it = getSegmentBeyond(pos);// if previous segment actually contains pos, shorten itif(it != segments.begin()){auto prev_it = it - 1;auto d = pos - prev_it->pos_begin; // distance from segment start (>=0)if(d < prev_it->entries.size()){prev_it->entries.erase(prev_it->entries.begin() + d);if(prev_it->entries.empty()){it = segments.erase(prev_it);}}}// pull forward all later segmentsstd::for_each(it, segments.end(), [](Segment &s){ s.pos_begin--; });}template <typename T>void RowCache<T>::clear (){segments.clear();}template <typename T>void RowCache<T>::smallestNonAvailableRange (size_t & row_begin, size_t & row_end) const{if(row_end < row_begin)throw std::invalid_argument("end must be >= begin");while(row_begin < row_end) {auto it = getSegmentContaining(row_begin);if(it == segments.end())break;row_begin = it->pos_end();}while(row_end > row_begin) {auto it = getSegmentContaining(row_end - 1);if(it == segments.end())break;row_end = it->pos_begin;}if(row_end < row_begin)row_end = row_begin;}#endif // SEGMENTING_CACHE_H
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。