From 71844dd2056e72bc1b82570e4754cbeeac4de344 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 26 Jul 2007 05:52:09 +0000 Subject: Added Raul::Table class (like an std::map but in an array, very fast to do a sorted iteration). Fixed unit test building. git-svn-id: http://svn.drobilla.net/lad/raul@629 a436a847-0d15-0410-975c-d299462d15a1 --- raul/TableImpl.hpp | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 raul/TableImpl.hpp (limited to 'raul/TableImpl.hpp') diff --git a/raul/TableImpl.hpp b/raul/TableImpl.hpp new file mode 100644 index 0000000..bac948e --- /dev/null +++ b/raul/TableImpl.hpp @@ -0,0 +1,166 @@ +/* This file is part of Raul. + * Copyright (C) 2007 Dave Robillard + * + * Raul is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * Raul 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 General Public License for details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +namespace Raul { + +#ifndef NDEBUG +template +bool +Table::is_sorted() const +{ + if (_size <= 1) + return true; + + K prev_key = _array[0].first; + + for (size_t i=1; i < _size; ++i) + if (_array[i].first < prev_key) + return false; + else + prev_key = _array[i].first; + + return true; +} +#endif + + +/** Binary search (O(log(n))) */ +template +typename Table::iterator +Table::find(const K& key) +{ + if (_size == 0) + return end(); + + size_t lower = 0; + size_t upper = _size - 1; + size_t i; + + while (upper >= lower) { + i = lower + ((upper - lower) / 2); + Entry& elem = _array[i]; + + if (elem.first == key) + return iterator(*this, i); + else if (i < _size-1 && elem.first < key) + lower = i + 1; + else if (i > 0) + upper = i - 1; + else + break; + } + + return end(); +} + + +template +void +Table::insert(K key, T value) +{ + Entry new_entry = make_pair(key, value); + + if (_size == 0) { + _array = (std::pair*)malloc(sizeof(Entry) * 2); + _array[0] = new_entry; + ++_size; + return; + } else if (_size == 1) { + if (key > _array[0].first) { + _array[1] = new_entry; + } else { + _array[1] = _array[0]; + _array[0] = new_entry; + } + ++_size; + return; + } + + size_t lower = 0; + size_t upper = _size - 1; + size_t i; + + // Find the earliest element > key + while (upper >= lower) { + i = lower + ((upper - lower) / 2); + assert(i >= lower); + assert(i <= upper); + assert(_array[lower].first <= _array[i].first); + assert(_array[i].first <= _array[upper].first); + + assert(i < _size); + Entry& elem = _array[i]; + + if (elem.first == key) { + break; + } else if (elem.first > key) { + if (i == 0 || _array[i-1].first < key) + break; + upper = i - 1; + } else { + lower = i + 1; + } + } + + // Lil' off by one touchup :) + if (i < _size && _array[i].first <= key) + ++i; + + _array = (Entry*)realloc(_array, (_size + 1) * sizeof(Entry)); + + // FIXME: This could be faster using memmove etc... + for (size_t j=_size; j > i; --j) + _array[j] = _array[j-1]; + + _array[i] = new_entry; + + ++_size; + + assert(is_sorted()); +} + + +template +void +Table::remove(K& key) +{ + iterator i = find(key); + if (i != _array.end()) + remove(i); +} + + +template +void +Table::remove(iterator i) +{ + _array.erase(i); + +#ifndef NDEBUG + assert(_array.is_sorted()); +#endif +} + + +} // namespace Raul + -- cgit v1.2.1