118 lines
3.0 KiB
C++
118 lines
3.0 KiB
C++
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright 2015 Realm Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "index_set.hpp"
|
|
|
|
using namespace realm;
|
|
|
|
size_t IndexSet::size() const
|
|
{
|
|
size_t size = 0;
|
|
for (auto const& range : m_ranges) {
|
|
size += range.second - range.first;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
std::vector<IndexSet::Range>::iterator IndexSet::find(size_t index)
|
|
{
|
|
for (auto it = m_ranges.begin(), end = m_ranges.end(); it != end; ++it) {
|
|
if (it->second > index)
|
|
return it;
|
|
}
|
|
return m_ranges.end();
|
|
}
|
|
|
|
void IndexSet::add(size_t index)
|
|
{
|
|
do_add(find(index), index);
|
|
}
|
|
|
|
void IndexSet::do_add(std::vector<Range>::iterator it, size_t index)
|
|
{
|
|
bool more_before = it != m_ranges.begin(), valid = it != m_ranges.end();
|
|
if (valid && it->first <= index && it->second > index) {
|
|
// index is already in set
|
|
}
|
|
else if (more_before && (it - 1)->second == index) {
|
|
// index is immediate after an existing range
|
|
++(it - 1)->second;
|
|
}
|
|
else if (more_before && valid && (it - 1)->second == it->first) {
|
|
// index joins two existing ranges
|
|
(it - 1)->second = it->second;
|
|
m_ranges.erase(it);
|
|
}
|
|
else if (valid && it->first == index + 1) {
|
|
// index is immediately before an existing range
|
|
--it->first;
|
|
}
|
|
else {
|
|
// index is not next to an existing range
|
|
m_ranges.insert(it, {index, index + 1});
|
|
}
|
|
}
|
|
|
|
void IndexSet::set(size_t len)
|
|
{
|
|
m_ranges.clear();
|
|
if (len) {
|
|
m_ranges.push_back({0, len});
|
|
}
|
|
}
|
|
|
|
void IndexSet::insert_at(size_t index)
|
|
{
|
|
auto pos = find(index);
|
|
if (pos != m_ranges.end()) {
|
|
if (pos->first >= index)
|
|
++pos->first;
|
|
++pos->second;
|
|
for (auto it = pos + 1; it != m_ranges.end(); ++it) {
|
|
++it->first;
|
|
++it->second;
|
|
}
|
|
}
|
|
do_add(pos, index);
|
|
}
|
|
|
|
size_t IndexSet::iterator::operator*() const
|
|
{
|
|
return m_data->first + m_offset;
|
|
}
|
|
|
|
IndexSet::iterator& IndexSet::iterator::operator++()
|
|
{
|
|
++m_offset;
|
|
if (m_offset + m_data->first == m_data->second) {
|
|
++m_data;
|
|
m_offset = 0;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool IndexSet::iterator::operator==(iterator other) const
|
|
{
|
|
return m_data == other.m_data && m_offset == other.m_offset;
|
|
}
|
|
|
|
bool IndexSet::iterator::operator!=(iterator other) const
|
|
{
|
|
return m_data != other.m_data || m_offset != other.m_offset;
|
|
}
|