/*
This file is part of Ingen.
Copyright 2007-2015 David Robillard
Ingen is free software: you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or any later version.
Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
You should have received a copy of the GNU Affero General Public License
along with Ingen. If not, see .
*/
#include
#include "ingen/Node.hpp"
#include "ingen/Store.hpp"
namespace ingen {
void
Store::add(Node* o)
{
if (find(o->path()) != end()) {
return;
}
emplace(o->path(), SPtr(o));
for (uint32_t i = 0; i < o->num_ports(); ++i) {
add(o->port(i));
}
}
/*
TODO: These methods are currently O(n_children) but should logarithmic. The
std::map methods do not allow passing a comparator, but std::upper_bound
does. This should be achievable by making a rooted comparator that is a
normal ordering except compares a special sentinel value as the greatest
element that is a child of the parent. Searching for this sentinel should
then find the end of the descendants in logarithmic time.
*/
Store::iterator
Store::find_descendants_end(const iterator parent)
{
iterator descendants_end = parent;
++descendants_end;
while (descendants_end != end() &&
descendants_end->first.is_child_of(parent->first)) {
++descendants_end;
}
return descendants_end;
}
Store::const_iterator
Store::find_descendants_end(const const_iterator parent) const
{
const_iterator descendants_end = parent;
++descendants_end;
while (descendants_end != end() &&
descendants_end->first.is_child_of(parent->first)) {
++descendants_end;
}
return descendants_end;
}
Store::const_range
Store::children_range(SPtr o) const
{
const const_iterator parent = find(o->path());
if (parent != end()) {
const_iterator first_child = parent;
++first_child;
return std::make_pair(first_child, find_descendants_end(parent));
}
return make_pair(end(), end());
}
void
Store::remove(const iterator top, Objects& removed)
{
if (top != end()) {
const iterator descendants_end = find_descendants_end(top);
removed.insert(top, descendants_end);
erase(top, descendants_end);
}
}
void
Store::rename(const iterator top, const Raul::Path& new_path)
{
const Raul::Path old_path = top->first;
// Remove the object and all its descendants
Objects removed;
remove(top, removed);
// Rename all the removed objects
for (Objects::const_iterator i = removed.begin(); i != removed.end(); ++i) {
const Raul::Path path = (i->first == old_path)
? new_path
: new_path.child(
Raul::Path(i->first.substr(old_path.base().length() - 1)));
i->second->set_path(path);
assert(find(path) == end()); // Shouldn't be dropping objects!
emplace(path, i->second);
}
}
unsigned
Store::child_name_offset(const Raul::Path& parent,
const Raul::Symbol& symbol,
bool allow_zero) const
{
unsigned offset = 0;
while (true) {
std::stringstream ss;
ss << symbol;
if (offset > 0) {
ss << "_" << offset;
}
if (find(parent.child(Raul::Symbol(ss.str()))) == end() &&
(allow_zero || offset > 0)) {
break;
} else if (offset == 0) {
offset = 2;
} else {
++offset;
}
}
return offset;
}
} // namespace ingen