mirror of
https://github.com/textmate/textmate.git
synced 2026-04-28 03:00:34 -04:00
160 lines
5.3 KiB
C++
160 lines
5.3 KiB
C++
#ifndef INDEXED_MAP_H_MY6VEIKA
|
||
#define INDEXED_MAP_H_MY6VEIKA
|
||
|
||
#include <oak/basic_tree.h>
|
||
#include <oak/misc.h>
|
||
#include <oak/debug.h>
|
||
#include <text/format.h>
|
||
|
||
template <typename _ValT = bool>
|
||
struct indexed_map_t
|
||
{
|
||
WATCH_LEAKS(indexed_map_t);
|
||
|
||
private:
|
||
struct key_t
|
||
{
|
||
key_t () : length(0), number_of_children(0) { }
|
||
key_t (ssize_t len, size_t numberOfChildren = 1) : length(len), number_of_children(numberOfChildren) { }
|
||
|
||
key_t operator+ (key_t const& rhs) const { return key_t(length + rhs.length, number_of_children + rhs.number_of_children); }
|
||
key_t operator- (key_t const& rhs) const { return key_t(length - rhs.length, number_of_children - rhs.number_of_children); }
|
||
|
||
ssize_t length;
|
||
size_t number_of_children;
|
||
};
|
||
|
||
static int comp_abs (ssize_t key, key_t const& offset, key_t const& node) { return key < offset.length + node.length ? -1 : (key == offset.length + node.length ? 0 : +1); }
|
||
static int comp_nth (ssize_t key, key_t const& offset, key_t const& node) { return key < offset.number_of_children ? -1 : (key == offset.number_of_children ? 0 : +1); }
|
||
|
||
typedef oak::basic_tree_t<key_t, _ValT> tree_t;
|
||
mutable tree_t _tree; // this is made mutable because the type doesn’t have const versions of find, {upper,lower}_bound, and begin/end.
|
||
|
||
void remove (typename tree_t::iterator first, typename tree_t::iterator last)
|
||
{
|
||
std::vector<ssize_t> toRemove;
|
||
foreach(info, first, last)
|
||
toRemove.push_back(info->offset.length + info->key.length);
|
||
riterate(key, toRemove)
|
||
remove(*key);
|
||
}
|
||
|
||
public:
|
||
struct iterator : public std::iterator< std::bidirectional_iterator_tag, std::pair<ssize_t, _ValT> >
|
||
{
|
||
iterator (tree_t& tree, typename tree_t::iterator const& base) : _tree(tree), _base(base) { update_value(); }
|
||
|
||
bool operator== (iterator const& rhs) const { return _base == rhs._base; }
|
||
bool operator!= (iterator const& rhs) const { return _base != rhs._base; }
|
||
iterator& operator-- () { --_base; update_value(); return *this; }
|
||
iterator& operator++ () { ++_base; update_value(); return *this; }
|
||
size_t index () const { return _base != _tree.end() ? _base->offset.number_of_children : _tree.aggregated().number_of_children; }
|
||
|
||
iterator& operator= (iterator const& rhs) { this->~iterator(); new(this) iterator(rhs); return *this; }
|
||
|
||
std::pair<ssize_t, _ValT> const* operator-> () const { return &_value; }
|
||
std::pair<ssize_t, _ValT> const& operator* () const { return _value; }
|
||
|
||
typename tree_t::iterator base () { return _base; }
|
||
|
||
private:
|
||
void update_value ()
|
||
{
|
||
if(_base != _tree.end())
|
||
{
|
||
_value.first = _base->offset.length + _base->key.length;
|
||
_value.second = _base->value;
|
||
}
|
||
}
|
||
|
||
tree_t& _tree;
|
||
typename tree_t::iterator _base;
|
||
std::pair<ssize_t, _ValT> _value;
|
||
};
|
||
|
||
bool empty () const { return _tree.empty(); }
|
||
void swap (indexed_map_t& rhs) { _tree.swap(rhs._tree); }
|
||
void clear () { _tree.clear(); }
|
||
size_t size () const { return _tree.aggregated().number_of_children; }
|
||
size_t number_of_nodes () const { return _tree.size(); }
|
||
size_t height () const { return _tree.height(); }
|
||
|
||
iterator begin () const { return iterator(_tree, _tree.begin()); }
|
||
iterator end () const { return iterator(_tree, _tree.end()); }
|
||
iterator find (ssize_t key) const { return iterator(_tree, _tree.find(key, &comp_abs)); }
|
||
iterator lower_bound (ssize_t key) const { return iterator(_tree, _tree.lower_bound(key, &comp_abs)); }
|
||
iterator upper_bound (ssize_t key) const { return iterator(_tree, _tree.upper_bound(key, &comp_abs)); }
|
||
iterator nth (size_t n) const { return iterator(_tree, _tree.find(n, &comp_nth)); }
|
||
|
||
void set (ssize_t pos, _ValT const& value)
|
||
{
|
||
auto alreadyThere = _tree.find(pos, &comp_abs);
|
||
if(alreadyThere != _tree.end())
|
||
{
|
||
alreadyThere->value = value;
|
||
return;
|
||
}
|
||
|
||
auto it = _tree.upper_bound(pos, &comp_abs);
|
||
if(it != _tree.begin())
|
||
{
|
||
auto tmp = it;
|
||
--tmp;
|
||
pos -= tmp->offset.length + tmp->key.length;
|
||
}
|
||
|
||
if(it != _tree.end())
|
||
{
|
||
it->key.length -= pos;
|
||
_tree.update_key(it);
|
||
}
|
||
|
||
_tree.insert(it, pos, value);
|
||
}
|
||
|
||
void remove (ssize_t pos)
|
||
{
|
||
auto it = _tree.find(pos, &comp_abs);
|
||
if(it == _tree.end())
|
||
return;
|
||
|
||
auto tmp = it;
|
||
if(++tmp != _tree.end())
|
||
{
|
||
tmp->key.length += it->key.length;
|
||
_tree.update_key(tmp);
|
||
}
|
||
|
||
_tree.erase(it);
|
||
ASSERT(find(pos) == end());
|
||
}
|
||
|
||
void remove (iterator first, iterator last)
|
||
{
|
||
remove(first.base(), last.base());
|
||
}
|
||
|
||
void replace (ssize_t from, ssize_t to, size_t newLength, bool bindRight = true)
|
||
{
|
||
auto it = bindRight ? _tree.lower_bound(to, &comp_abs) : _tree.upper_bound(to, &comp_abs);
|
||
if(it != _tree.end())
|
||
{
|
||
it->key.length += newLength;
|
||
_tree.update_key(it);
|
||
}
|
||
|
||
if(bindRight)
|
||
remove(_tree.lower_bound(from, &comp_abs), _tree.lower_bound(to, &comp_abs));
|
||
else remove(_tree.upper_bound(from, &comp_abs), _tree.upper_bound(to, &comp_abs));
|
||
|
||
it = bindRight ? _tree.lower_bound(to, &comp_abs) : _tree.upper_bound(to, &comp_abs);
|
||
if(it != _tree.end())
|
||
{
|
||
it->key.length -= to - from;
|
||
_tree.update_key(it);
|
||
}
|
||
}
|
||
};
|
||
|
||
#endif /* end of include guard: INDEXED_MAP_H_MY6VEIKA */
|