[mdds] 23/62: Imported Upstream version 0.7.0
This is an automated email from the git hooks/post-receive script.
rene pushed a commit to branch master
in repository mdds.
commit 1e9a412e2051fda2ef2b6674487121d6b68b9f2f
Author: Rene Engelhard <rene@debian.org>
Date: Thu Apr 21 14:50:48 2016 +0200
Imported Upstream version 0.7.0
---
Makefile.in | 4 +
NEWS | 24 +
include/mdds/mixed_type_matrix_element.hpp | 4 +
include/mdds/multi_type_vector.hpp | 329 ++++-
include/mdds/multi_type_vector_def.inl | 702 +++++++----
include/mdds/multi_type_vector_itr.hpp | 341 +++++-
include/mdds/multi_type_vector_types.hpp | 25 +-
include/mdds/rectangle_set_def.inl | 24 +-
src/flat_segment_tree_test.cpp | 6 -
src/multi_type_matrix_test.cpp | 2 +-
src/multi_type_vector_test_custom.cpp | 128 +-
src/multi_type_vector_test_default.cpp | 1813 ++++++++++++++++++++++++++--
12 files changed, 2932 insertions(+), 470 deletions(-)
diff --git a/Makefile.in b/Makefile.in
index d822306..481b84a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -176,6 +176,10 @@ test.mtv: multi_type_vector_test_default multi_type_vector_test_custom
./multi_type_vector_test_default func
./multi_type_vector_test_custom func
+test.mtv.perf: multi_type_vector_test_default multi_type_vector_test_custom
+ ./multi_type_vector_test_default perf
+ ./multi_type_vector_test_custom perf
+
test.mtv.mem: multi_type_vector_test_default multi_type_vector_test_custom
valgrind --tool=memcheck --leak-check=full ./multi_type_vector_test_default func
valgrind --tool=memcheck --leak-check=full ./multi_type_vector_test_custom func
diff --git a/NEWS b/NEWS
index ab7bad6..8278043 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,27 @@
+mdds 0.7.0
+
+* multi_type_vector
+
+ * add variants of set() methods (both single- and multi-value)
+ insert(), set_empty() and insert_empty() methods that take an
+ iterator as an additional position hint parameter for block lookup
+ speed optimization.
+
+ * add support for non-const iterators which allow the client code to
+ modify values directly from the iterators.
+
+ * set() methods (both single- and multi-parameter variants),
+ set_empty(), insert() and insert_empty() methods now return
+ iterator that references the block to which the values are set or
+ inserted.
+
+ * fixed bugs in set() method (single-parameter variant) which would
+ insert a new block at incorrect position.
+
+ * fixed bugs in set() method (multi-parameter variant) which would
+ fail to merge neighboring blocks of identical type under certain
+ conditions.
+
mdds 0.6.1
* all
diff --git a/include/mdds/mixed_type_matrix_element.hpp b/include/mdds/mixed_type_matrix_element.hpp
index e8c159b..c20dc2a 100644
--- a/include/mdds/mixed_type_matrix_element.hpp
+++ b/include/mdds/mixed_type_matrix_element.hpp
@@ -99,6 +99,10 @@ struct element
element& operator= (const element& r)
{
+ if (&r == this)
+ // assignment to self.
+ return *this;
+
if (m_type == element_string)
delete mp_string;
diff --git a/include/mdds/multi_type_vector.hpp b/include/mdds/multi_type_vector.hpp
index 889fe91..b8f9c93 100644
--- a/include/mdds/multi_type_vector.hpp
+++ b/include/mdds/multi_type_vector.hpp
@@ -1,6 +1,6 @@
/*************************************************************************
*
- * Copyright (c) 2011-2012 Kohei Yoshida
+ * Copyright (c) 2011-2013 Kohei Yoshida
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -55,9 +55,9 @@ public:
typedef typename mdds::mtv::base_element_block element_block_type;
typedef typename mdds::mtv::element_t element_category_type;
+ typedef _ElemBlockFunc element_block_func;
private:
- typedef _ElemBlockFunc element_block_func;
struct block
{
@@ -72,14 +72,55 @@ private:
typedef std::vector<block*> blocks_type;
+ struct iterator_trait
+ {
+ typedef multi_type_vector parent;
+ typedef blocks_type blocks;
+ typedef typename blocks_type::iterator base_iterator;
+ };
+
+ struct reverse_iterator_trait
+ {
+ typedef multi_type_vector parent;
+ typedef blocks_type blocks;
+ typedef typename blocks_type::reverse_iterator base_iterator;
+ };
+
+ struct const_iterator_trait
+ {
+ typedef multi_type_vector parent;
+ typedef blocks_type blocks;
+ typedef typename blocks_type::const_iterator base_iterator;
+ };
+
+ struct const_reverse_iterator_trait
+ {
+ typedef multi_type_vector parent;
+ typedef blocks_type blocks;
+ typedef typename blocks_type::const_reverse_iterator base_iterator;
+ };
+
+ typedef __mtv::iterator_value_node<size_type, element_block_type> itr_node;
+ typedef __mtv::private_data_forward_update<itr_node> itr_forward_update;
+ typedef __mtv::private_data_no_update<itr_node> itr_no_update;
+
public:
- typedef __mtv::iterator_base<multi_type_vector, blocks_type, typename blocks_type::const_iterator> const_iterator;
- typedef __mtv::iterator_base<multi_type_vector, blocks_type, typename blocks_type::const_reverse_iterator> const_reverse_iterator;
+ typedef __mtv::iterator_base<iterator_trait, itr_forward_update> iterator;
+ typedef __mtv::iterator_base<reverse_iterator_trait, itr_no_update> reverse_iterator;
+
+ typedef __mtv::const_iterator_base<const_iterator_trait, iterator> const_iterator;
+ typedef __mtv::const_iterator_base<const_reverse_iterator_trait, reverse_iterator> const_reverse_iterator;
+
+ iterator begin();
+ iterator end();
const_iterator begin() const;
const_iterator end() const;
+ reverse_iterator rbegin();
+ reverse_iterator rend();
+
const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;
@@ -125,9 +166,46 @@ public:
*
* @param pos position to insert the value to.
* @param value value to insert.
+ * @return iterator position pointing to the block where the value is
+ * inserted.
*/
template<typename _T>
- void set(size_type pos, const _T& value);
+ iterator set(size_type pos, const _T& value);
+
+ /**
+ * Set a value of an arbitrary type to a specified position. The type of
+ * the value is inferred from the value passed to this method. The new
+ * value will overwrite an existing value at the specified position
+ * position if any.
+ *
+ * <p>This variant takes an iterator as an additional parameter, which is
+ * used as a block position hint to speed up the lookup of the
+ * right block to insert the value into. The other variant that doesn't
+ * take an iterator always starts the block lookup from the first block,
+ * which does not scale well as the block size grows.</p>
+ *
+ * <p>This position hint iterator must <b>precede</b> the insertion
+ * position to yield any performance benefit.</p>
+ *
+ * <p>The caller is responsible for ensuring that the passed iterator is
+ * valid. The behavior of this method when passing an invalid iteraotr is
+ * undefined.</p>
+ *
+ * <p>The method will throw an <code>std::out_of_range</code> exception
+ * if the specified position is outside the current container range.</p>
+ *
+ * <p>Calling this method will not change the size of the container.</p>
+ *
+ * @param pos_hint iterator used as a block position hint, to specify
+ * which block to start when searching for the right block
+ * to insert the value into.
+ * @param pos position to insert the value to.
+ * @param value value to insert.
+ * @return iterator position pointing to the block where the value is
+ * inserted.
+ */
+ template<typename _T>
+ iterator set(iterator pos_hint, size_type pos, const _T& value);
/**
* Set multiple values of identical type to a range of elements starting
@@ -146,9 +224,52 @@ public:
* values being set.
* @param it_end iterator that points to the end position of the values
* being set.
+ * @return iterator position pointing to the block where the value is
+ * inserted. When no value insertion occurs because the value set
+ * is empty, the end iterator position is returned.
*/
template<typename _T>
- void set(size_type pos, const _T& it_begin, const _T& it_end);
+ iterator set(size_type pos, const _T& it_begin, const _T& it_end);
+
+ /**
+ * Set multiple values of identical type to a range of elements starting
+ * at specified position. Any existing values will be overwritten by the
+ * new values.
+ *
+ * <p>This variant takes an iterator as an additional parameter, which is
+ * used as a block position hint to speed up the lookup of the first
+ * insertion block. The other variant that doesn't take an iterator
+ * always starts the block lookup from the first block, which does not
+ * scale well as the block size grows.</p>
+ *
+ * <p>This position hint iterator must <b>precede</b> the insertion
+ * position to yield any performance benefit.</p>
+ *
+ * <p>The caller is responsible for ensuring that the passed iterator is
+ * valid. The behavior of this method when passing an invalid iteraotr is
+ * undefined.</p>
+ *
+ * <p>The method will throw an <code>std::out_of_range</code> exception if
+ * the range of new values would fall outside the current container
+ * range.</p>
+ *
+ * <p>Calling this method will not change the size of the container.</p>
+ *
+ * @param pos_hint iterator used as a block position hint, to specify
+ * which block to start when searching for the right block
+ * to insert the value into.
+ * @param pos position of the first value of the series of new values
+ * being inserted.
+ * @param it_begin iterator that points to the begin position of the
+ * values being set.
+ * @param it_end iterator that points to the end position of the values
+ * being set.
+ * @return iterator position pointing to the block where the value is
+ * inserted. When no value insertion occurs because the value set
+ * is empty, the end iterator position is returned.
+ */
+ template<typename _T>
+ iterator set(iterator pos_hint, size_type pos, const _T& it_begin, const _T& it_end);
/**
* Insert multiple values of identical type to a specified position.
@@ -167,9 +288,52 @@ public:
* values being inserted.
* @param it_end iterator that points to the end position of the values
* being inserted.
+ * @return iterator position pointing to the block where the value is
+ * inserted. When no value insertion occurs because the value set
+ * is empty, the end iterator position is returned.
*/
template<typename _T>
- void insert(size_type pos, const _T& it_begin, const _T& it_end);
+ iterator insert(size_type pos, const _T& it_begin, const _T& it_end);
+
+ /**
+ * Insert multiple values of identical type to a specified position.
+ * Existing values that occur at or below the specified position will get
+ * shifted after the insertion. No existing values will be overwritten by
+ * the inserted values.
+ *
+ * <p>This variant takes an iterator as an additional parameter, which is
+ * used as a block position hint to speed up the lookup of the first
+ * insertion block. The other variant that doesn't take an iterator
+ * always starts the block lookup from the first block, which does not
+ * scale well as the block size grows.</p>
+ *
+ * <p>This position hint iterator must <b>precede</b> the insertion
+ * position to yield any performance benefit.</p>
+ *
+ * <p>The caller is responsible for ensuring that the passed iterator is
+ * valid. The behavior of this method when passing an invalid iteraotr is
+ * undefined.</p>
+ *
+ * <p>The method will throw an <code>std::out_of_range</code> exception
+ * if the specified position is outside the current container range.</p>
+ *
+ * <p>Calling this method will increase the size of the container by
+ * the length of the new values inserted.</p>
+ *
+ * @param pos_hint iterator used as a block position hint, to specify
+ * which block to start when searching for the right block
+ * to insert the value into.
+ * @param pos position at which the new values are to be inserted.
+ * @param it_begin iterator that points to the begin position of the
+ * values being inserted.
+ * @param it_end iterator that points to the end position of the values
+ * being inserted.
+ * @return iterator position pointing to the block where the value is
+ * inserted. When no value insertion occurs because the value set
+ * is empty, the end iterator position is returned.
+ */
+ template<typename _T>
+ iterator insert(iterator pos_hint, size_type pos, const _T& it_begin, const _T& it_end);
/**
* Get the value of an element at specified position. The caller must
@@ -222,8 +386,41 @@ public:
*
* @param start_pos starting position
* @param end_pos ending position, inclusive.
+ * @return iterator position pointing to the block where the elements are
+ * emptied.
*/
- void set_empty(size_type start_pos, size_type end_pos);
+ iterator set_empty(size_type start_pos, size_type end_pos);
+
+ /**
+ * Set specified range of elements to be empty. Any existing values will
+ * be overwritten.
+ *
+ * <p>This variant takes an iterator as an additional parameter, which is
+ * used as a block position hint to speed up the lookup of the first block
+ * to empty. The other variant that doesn't take an iterator always
+ * starts the block lookup from the first block, which does not
+ * scale well as the block size grows.</p>
+ *
+ * <p>This position hint iterator must <b>precede</b> the start
+ * position to yield any performance benefit.</p>
+ *
+ * <p>The caller is responsible for ensuring that the passed iterator is
+ * valid. The behavior of this method when passing an invalid iteraotr is
+ * undefined.</p>
+ *
+ * <p>The method will throw an <code>std::out_of_range</code> exception if
+ * either the starting or the ending position is outside the current
+ * container size.</p>
+ *
+ * @param pos_hint iterator used as a block position hint, to specify
+ * which block to start when searching for the right
+ * blocks to empty.
+ * @param start_pos starting position
+ * @param end_pos ending position, inclusive.
+ * @return iterator position pointing to the block where the elements are
+ * emptied.
+ */
+ iterator set_empty(iterator pos_hint, size_type start_pos, size_type end_pos);
/**
* Erase elements located between specified start and end positions. The
@@ -253,8 +450,45 @@ public:
*
* @param pos position at which to insert a range of empty elements.
* @param length number of empty elements to insert.
+ * @return iterator position pointing to the block where the empty range
+ * is inserted. When no insertion occurs because the length is
+ * zero, the end iterator position is returned.
+ */
+ iterator insert_empty(size_type pos, size_type length);
+
+ /**
+ * Insert a range of empty elements at specified position.
+ *
+ * <p>This variant takes an iterator as an additional parameter, which is
+ * used as a block position hint to speed up the lookup of the block in
+ * which to insert the new empty segment. The other variant that doesn't
+ * take an iterator always starts the block lookup from the first block,
+ * which does not scale well as the block size grows.</p>
+ *
+ * <p>This position hint iterator must <b>precede</b> the start
+ * position to yield any performance benefit.</p>
+ *
+ * <p>The caller is responsible for ensuring that the passed iterator is
+ * valid. The behavior of this method when passing an invalid iteraotr is
+ * undefined.</p>
+ *
+ * <p>The method will throw an <code>std::out_of_range</code> exception if
+ * either the specified position is outside the current container
+ * range.</p>
+ *
+ * <p>Calling this method will increase the size of the container by
+ * the length of the inserted empty elements.</p>
+ *
+ * @param pos_hint iterator used as a block position hint, to specify
+ * which block to start when searching for the right block
+ * in which to insert the empty segment.
+ * @param pos position at which to insert a range of empty elements.
+ * @param length number of empty elements to insert.
+ * @return iterator position pointing to the block where the empty range
+ * is inserted. When no insertion occurs because the length is
+ * zero, the end iterator position is returned.
*/
- void insert_empty(size_type pos, size_type length);
+ iterator insert_empty(iterator pos_hint, size_type pos, size_type length);
/**
* Clear the content of the container. The size of the container will
@@ -325,26 +559,53 @@ public:
private:
- void get_block_position(
- size_type row, size_type& start_pos, size_type& block_index, size_type start_block=0, size_type start_block_row=0) const;
+ template<typename _T>
+ iterator set_impl(size_type pos, size_type start_row, size_type block_index, const _T& value);
+
+ /**
+ * Find the correct block position for given logical row ID.
+ *
+ * @param row logical ID of the row that belongs to the block being looked
+ * up for.
+ *
+ * @param start_pos logical ID of the first row of the block being looked
+ * up for. The caller needs to assign its initial value
+ * before calling this method in case the search needs to
+ * start with a block that's not the first block. Assign
+ * 0 if the search starts from the first block.
+ *
+ * @param block_index index of the block being looked up for. The caller
+ * needs to assign its initial index which will be the
+ * index of the block from which the search starts.
+ * Assign 0 if the search starts from the first block.
+ *
+ * @return true if block position is found, false otherwise.
+ */
+ bool get_block_position(size_type row, size_type& start_pos, size_type& block_index) const;
+
+ /**
+ * Same as above, but try to infer block position from the iterator first
+ * before trying full search.
+ */
+ void get_block_position(iterator pos_hint, size_type pos, size_type& start_pos, size_type& block_index) const;
template<typename _T>
static void create_new_block_with_new_cell(element_block_type*& data, const _T& cell);
template<typename _T>
- void set_cell_to_middle_of_block(
- size_type block_index, size_type pos_in_block, const _T& cell);
+ iterator set_cell_to_middle_of_block(
+ size_type start_row, size_type block_index, size_type pos_in_block, const _T& cell);
template<typename _T>
void append_cell_to_block(size_type block_index, const _T& cell);
template<typename _T>
- void set_cell_to_empty_block(
- size_type block_index, size_type pos_in_block, const _T& cell);
+ iterator set_cell_to_empty_block(
+ size_type start_row, size_type block_index, size_type pos_in_block, const _T& cell);
template<typename _T>
- void set_cell_to_block_of_size_one(
- size_type block_index, const _T& cell);
+ iterator set_cell_to_block_of_size_one(
+ size_type start_row, size_type block_index, const _T& cell);
template<typename _T>
void set_cell_to_top_of_data_block(
@@ -354,50 +615,59 @@ private:
void set_cell_to_bottom_of_data_block(
size_type block_index, const _T& cell);
- void set_empty_in_single_block(
+ iterator set_empty_impl(size_type start_pos, size_type end_pos, size_type start_pos_in_block1, size_type block_index1);
+
+ iterator set_empty_in_single_block(
size_type start_pos, size_type end_pos, size_type block_index, size_type start_pos_in_block);
- void set_empty_in_multi_blocks(
+ iterator set_empty_in_multi_blocks(
size_type start_pos, size_type end_pos,
size_type block_index1, size_type start_pos_in_block1,
size_type block_index2, size_type start_pos_in_block2);
void erase_impl(size_type start_pos, size_type end_pos);
- void insert_empty_impl(size_type row, size_type length);
+ iterator insert_empty_impl(size_type row, size_type start_pos, size_type block_index, size_type length);
+
+ template<typename _T>
+ bool set_cells_precheck(
+ size_type row, const _T& it_begin, const _T& it_end, size_type& end_pos);
template<typename _T>
- void set_cells_impl(size_type row, const _T& it_begin, const _T& it_end);
+ iterator set_cells_impl(
+ size_type row, size_type end_row, size_type start_row1, size_type block_index1, const _T& it_begin, const _T& it_end);
template<typename _T>
- void insert_cells_impl(size_type row, const _T& it_begin, const _T& it_end);
+ iterator insert_cells_impl(size_type row, size_type start_row, size_type block_index, const _T& it_begin, const _T& it_end);
template<typename _T>
- void set_cells_to_single_block(
+ iterator set_cells_to_single_block(
size_type start_pos, size_type end_pos, size_type block_index,
size_type start_pos_in_block, const _T& it_begin, const _T& it_end);
template<typename _T>
- void set_cells_to_multi_blocks(
+ iterator set_cells_to_multi_blocks(
size_type start_pos, size_type end_pos,
size_type block_index1, size_type start_pos_in_block1,
size_type block_index2, size_type start_pos_in_block2,
const _T& it_begin, const _T& it_end);
template<typename _T>
- void set_cells_to_multi_blocks_block1_non_equal(
+ iterator set_cells_to_multi_blocks_block1_non_equal(
size_type start_pos, size_type end_pos,
size_type block_index1, size_type start_pos_in_block1,
size_type block_index2, size_type start_pos_in_block2,
const _T& it_begin, const _T& it_end);
template<typename _T>
- void set_cells_to_multi_blocks_block1_non_empty(
+ iterator set_cells_to_multi_blocks_block1_non_empty(
size_type start_pos, size_type end_pos,
size_type block_index1, size_type start_pos_in_block1,
size_type block_index2, size_type start_pos_in_block2,
const _T& it_begin, const _T& it_end);
+ void merge_with_next_block(size_type block_index);
+
template<typename _T>
bool append_to_prev_block(
size_type block_index, element_category_type cat, size_type length,
@@ -408,6 +678,13 @@ private:
size_type row, size_type block_index, size_type start_pos,
const _T& it_begin, const _T& it_end);
+ inline iterator get_iterator(size_type block_index, size_type start_row)
+ {
+ typename blocks_type::iterator block_pos = m_blocks.begin();
+ std::advance(block_pos, block_index);
+ return iterator(block_pos, m_blocks.end(), start_row, block_index);
+ }
+
private:
blocks_type m_blocks;
size_type m_cur_size;
diff --git a/include/mdds/multi_type_vector_def.inl b/include/mdds/multi_type_vector_def.inl
index fb72070..0fcfc47 100644
--- a/include/mdds/multi_type_vector_def.inl
+++ b/include/mdds/multi_type_vector_def.inl
@@ -1,6 +1,6 @@
/*************************************************************************
*
- * Copyright (c) 2012 Kohei Yoshida
+ * Copyright (c) 2012-2013 Kohei Yoshida
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -68,31 +68,66 @@ multi_type_vector<_CellBlockFunc>::block::~block()
}
template<typename _CellBlockFunc>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::begin()
+{
+ return iterator(m_blocks.begin(), m_blocks.end(), 0, 0);
+}
+
+template<typename _CellBlockFunc>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::end()
+{
+ size_type start_pos = 0, block_index = 0;
+ if (!m_blocks.empty())
+ {
+ // Get the index and the start row position of the imaginary block after the last block.
+ block_index = m_blocks.size();
+ start_pos = m_cur_size;
+ }
+ return iterator(m_blocks.end(), m_blocks.end(), start_pos, block_index);
+}
+
+template<typename _CellBlockFunc>
typename multi_type_vector<_CellBlockFunc>::const_iterator
multi_type_vector<_CellBlockFunc>::begin() const
{
- return const_iterator(m_blocks.begin(), m_blocks.end());
+ return const_iterator(m_blocks.begin(), m_blocks.end(), 0, 0);
}
template<typename _CellBlockFunc>
typename multi_type_vector<_CellBlockFunc>::const_iterator
multi_type_vector<_CellBlockFunc>::end() const
{
- return const_iterator(m_blocks.end(), m_blocks.end());
+ return const_iterator(m_blocks.end(), m_blocks.end(), 0, 0);
+}
+
+template<typename _CellBlockFunc>
+typename multi_type_vector<_CellBlockFunc>::reverse_iterator
+multi_type_vector<_CellBlockFunc>::rbegin()
+{
+ return reverse_iterator(m_blocks.rbegin(), m_blocks.rend(), 0, 0);
+}
+
+template<typename _CellBlockFunc>
+typename multi_type_vector<_CellBlockFunc>::reverse_iterator
+multi_type_vector<_CellBlockFunc>::rend()
+{
+ return reverse_iterator(m_blocks.rend(), m_blocks.rend(), 0, 0);
}
template<typename _CellBlockFunc>
typename multi_type_vector<_CellBlockFunc>::const_reverse_iterator
multi_type_vector<_CellBlockFunc>::rbegin() const
{
- return const_reverse_iterator(m_blocks.rbegin(), m_blocks.rend());
+ return const_reverse_iterator(m_blocks.rbegin(), m_blocks.rend(), 0, 0);
}
template<typename _CellBlockFunc>
typename multi_type_vector<_CellBlockFunc>::const_reverse_iterator
multi_type_vector<_CellBlockFunc>::rend() const
{
- return const_reverse_iterator(m_blocks.rend(), m_blocks.rend());
+ return const_reverse_iterator(m_blocks.rend(), m_blocks.rend(), 0, 0);
}
template<typename _CellBlockFunc>
@@ -140,16 +175,39 @@ multi_type_vector<_CellBlockFunc>::~multi_type_vector()
template<typename _CellBlockFunc>
template<typename _T>
-void multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
{
- element_category_type cat = mdds_mtv_get_element_type(value);
+ size_type start_row = 0;
+ size_type block_index = 0;
+ if (!get_block_position(pos, start_row, block_index))
+ throw std::out_of_range("Block position not found!");
+
+ return set_impl(pos, start_row, block_index, value);
+}
- // Find the right block ID from the row ID.
- size_type start_row = 0; // row ID of the first cell in a block.
+template<typename _CellBlockFunc>
+template<typename _T>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set(iterator pos_hint, size_type pos, const _T& value)
+{
+ size_type start_row = 0;
size_type block_index = 0;
- get_block_position(pos, start_row, block_index);
+ get_block_position(pos_hint, pos, start_row, block_index);
+ return set_impl(pos, start_row, block_index, value);
+}
- block* blk = m_blocks[block_index];
+template<typename _CellBlockFunc>
+template<typename _T>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_impl(
+ size_type pos, size_type start_row, size_type block_index, const _T& value)
+{
+ element_category_type cat = mdds_mtv_get_element_type(value);
+
+ typename blocks_type::iterator block_pos = m_blocks.begin();
+ std::advance(block_pos, block_index);
+ block* blk = *block_pos;
assert(blk->m_size > 0); // block size should never be zero at any time.
assert(pos >= start_row);
@@ -159,8 +217,7 @@ void multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
if (!blk->mp_data)
{
// This is an empty block.
- set_cell_to_empty_block(block_index, pos_in_block, value);
- return;
+ return set_cell_to_empty_block(start_row, block_index, pos_in_block, value);
}
assert(blk->mp_data);
@@ -172,7 +229,7 @@ void multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
size_type i = pos - start_row;
element_block_func::overwrite_values(*blk->mp_data, i, 1);
mdds_mtv_set_value(*blk->mp_data, i, value);
- return;
+ return iterator(block_pos, m_blocks.end(), start_row, block_index);
}
assert(blk_cat != cat);
@@ -181,17 +238,14 @@ void multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
{
// Insertion point is at the start of the block.
if (blk->m_size == 1)
- {
- set_cell_to_block_of_size_one(block_index, value);
- return;
- }
+ return set_cell_to_block_of_size_one(start_row, block_index, value);
assert(blk->m_size > 1);
if (block_index == 0)
{
// No preceding block.
set_cell_to_top_of_data_block(0, value);
- return;
+ return begin();
}
// Append to the previous block if the types match.
@@ -200,29 +254,29 @@ void multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
{
// Previous block is empty.
set_cell_to_top_of_data_block(block_index, value);
- return;
+ return get_iterator(block_index, start_row);
}
element_category_type blk_cat_prev = mdds::mtv::get_block_type(*blk_prev->mp_data);
if (blk_cat_prev == cat)
{
// Append to the previous block.
+ size_type offset = blk_prev->m_size;
blk->m_size -= 1;
element_block_func::erase(*blk->mp_data, 0);
blk_prev->m_size += 1;
mdds_mtv_append_value(*blk_prev->mp_data, value);
- return;
+ return get_iterator(block_index-1, start_row-offset);
}
set_cell_to_top_of_data_block(block_index, value);
- return;
+ return get_iterator(block_index, start_row);
}
if (pos < (start_row + blk->m_size - 1))
{
// Insertion point is somewhere in the middle of the block.
- set_cell_to_middle_of_block(block_index, pos_in_block, value);
- return;
+ return set_cell_to_middle_of_block(start_row, block_index, pos_in_block, value);
}
// Insertion point is at the end of the block.
@@ -238,7 +292,9 @@ void multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
// previous block, and insert a new block for the cell being
// inserted.
set_cell_to_bottom_of_data_block(0, value);
- return;
+ iterator itr = end();
+ --itr;
+ return itr;
}
assert(block_index < m_blocks.size()-1);
@@ -248,7 +304,9 @@ void multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
// Next block is empty. Pop the last cell of the current
// block, and insert a new block with the new cell.
set_cell_to_bottom_of_data_block(0, value);
- return;
+ iterator itr = begin();
+ ++itr;
+ return itr;
}
// Next block is not empty.
@@ -256,7 +314,9 @@ void multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
if (blk_cat_next != cat)
{
set_cell_to_bottom_of_data_block(0, value);
- return;
+ iterator itr = begin();
+ ++itr;
+ return itr;
}
// Pop the last cell off the current block, and prepend the
@@ -264,7 +324,9 @@ void multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
element_block_func::erase(*blk->mp_data, blk->m_size-1);
blk->m_size -= 1;
mdds_mtv_prepend_value(*blk_next->mp_data, value);
- return;
+ blk_next->m_size += 1;
+
+ return get_iterator(block_index+1, start_row+blk->m_size);
}
assert(block_index > 0);
@@ -273,23 +335,17 @@ void multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
{
// This is the last block.
set_cell_to_bottom_of_data_block(block_index, value);
- return;
+ iterator itr = end();
+ --itr;
+ return itr;
}
block* blk_next = m_blocks[block_index+1];
- if (!blk_next->mp_data)
+ if (!blk_next->mp_data || mdds::mtv::get_block_type(*blk_next->mp_data) != cat)
{
- // Next block is empty.
+ // Next block is either empty or of different type than that of the cell being inserted.
set_cell_to_bottom_of_data_block(block_index, value);
- return;
- }
-
- element_category_type cat_blk_next = mdds::mtv::get_block_type(*blk_next->mp_data);
- if (cat_blk_next != cat)
- {
- // Next block is of different type than that of the cell being inserted.
- set_cell_to_bottom_of_data_block(block_index, value);
- return;
+ return get_iterator(block_index+1, start_row+blk->m_size);
}
// Pop the last element from the current block, and prepend the cell
@@ -298,42 +354,111 @@ void multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
blk->m_size -= 1;
mdds_mtv_prepend_value(*blk_next->mp_data, value);
blk_next->m_size += 1;
+
+ return get_iterator(block_index+1, start_row+blk->m_size);
+}
+
+template<typename _CellBlockFunc>
+template<typename _T>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& it_begin, const _T& it_end)
+{
+ size_type end_pos = 0;
+ if (!set_cells_precheck(pos, it_begin, it_end, end_pos))
+ return end();
+
+ size_type block_index1 = 0, start_row1 = 0;
+ if (!get_block_position(pos, start_row1, block_index1))
+ throw std::out_of_range("Block position not found!");
+
+ return set_cells_impl(pos, end_pos, start_row1, block_index1, it_begin, it_end);
+}
+
+template<typename _CellBlockFunc>
+template<typename _T>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set(iterator pos_hint, size_type pos, const _T& it_begin, const _T& it_end)
+{
+ size_type end_pos = 0;
+ if (!set_cells_precheck(pos, it_begin, it_end, end_pos))
+ return end();
+
+ size_type block_index1 = 0, start_row1 = 0;
+ get_block_position(pos_hint, pos, start_row1, block_index1);
+
+ return set_cells_impl(pos, end_pos, start_row1, block_index1, it_begin, it_end);
}
template<typename _CellBlockFunc>
template<typename _T>
-void multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& it_begin, const _T& it_end)
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::insert(size_type pos, const _T& it_begin, const _T& it_end)
{
- set_cells_impl(pos, it_begin, it_end);
+ size_type block_index = 0, start_pos = 0;
+ if (!get_block_position(pos, start_pos, block_index))
+ throw std::out_of_range("Block position not found!");
+
+ return insert_cells_impl(pos, start_pos, block_index, it_begin, it_end);
}
template<typename _CellBlockFunc>
template<typename _T>
-void multi_type_vector<_CellBlockFunc>::insert(size_type pos, const _T& it_begin, const _T& it_end)
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::insert(iterator pos_hint, size_type pos, const _T& it_begin, const _T& it_end)
{
- insert_cells_impl(pos, it_begin, it_end);
+ size_type block_index = 0, start_pos = 0;
+ get_block_position(pos_hint, pos, start_pos, block_index);
+
+ return insert_cells_impl(pos, start_pos, block_index, it_begin, it_end);
}
template<typename _CellBlockFunc>
-void multi_type_vector<_CellBlockFunc>::get_block_position(
- size_type row, size_type& start_row, size_type& block_index, size_type start_block, size_type start_block_row) const
+bool multi_type_vector<_CellBlockFunc>::get_block_position(
+ size_type row, size_type& start_row, size_type& block_index) const
{
- start_row = start_block_row;
- for (size_type i = start_block, n = m_blocks.size(); i < n; ++i)
+ for (size_type i = block_index, n = m_blocks.size(); i < n; ++i)
{
const block& blk = *m_blocks[i];
if (row < start_row + blk.m_size)
{
// Row is in this block.
block_index = i;
- return;
+ return true;
}
// Specified row is not in this block.
start_row += blk.m_size;
}
- assert(!"Block position not found.");
+ return false;
+}
+
+template<typename _CellBlockFunc>
+void multi_type_vector<_CellBlockFunc>::get_block_position(
+ iterator pos_hint, size_type pos, size_type& start_row, size_type& block_index) const
+{
+ start_row = 0;
+ block_index = 0;
+ if (pos_hint.get_end() == m_blocks.end())
+ {
+ // Iterator is valid. Get the block position from it unless it's the
+ // end position.
+ if (pos_hint.get_pos() != pos_hint.get_end())
+ {
+ start_row = pos_hint->__private_data.start_pos;
+ block_index = pos_hint->__private_data.block_index;
+ }
+ }
+
+ if (pos < start_row)
+ {
+ // Position hint is past the insertion position. Reset.
+ start_row = 0;
+ block_index = 0;
+ }
+
+ if (!get_block_position(pos, start_row, block_index))
+ throw std::out_of_range("Block position not found!");
}
template<typename _CellBlockFunc>
@@ -351,8 +476,9 @@ void multi_type_vector<_CellBlockFunc>::create_new_block_with_new_cell(element_b
template<typename _CellBlockFunc>
template<typename _T>
-void multi_type_vector<_CellBlockFunc>::set_cell_to_middle_of_block(
- size_type block_index, size_type pos_in_block, const _T& cell)
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_cell_to_middle_of_block(
+ size_type start_row, size_type block_index, size_type pos_in_block, const _T& cell)
{
block* blk = m_blocks[block_index];
@@ -382,6 +508,9 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_middle_of_block(
blk->m_size = pos_in_block;
create_new_block_with_new_cell(blk_new->mp_data, cell);
+
+ // Return the iterator referencing the inserted block.
+ return get_iterator(block_index+1, start_row+blk->m_size);
}
template<typename _CellBlockFunc>
@@ -395,8 +524,9 @@ void multi_type_vector<_CellBlockFunc>::append_cell_to_block(size_type block_ind
template<typename _CellBlockFunc>
template<typename _T>
-void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
- size_type block_index, size_type pos_in_block, const _T& cell)
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
+ size_type start_row, size_type block_index, size_type pos_in_block, const _T& cell)
{
block* blk = m_blocks[block_index];
@@ -412,6 +542,7 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
// This column is allowed to have only one row!
assert(pos_in_block == 0);
create_new_block_with_new_cell(blk->mp_data, cell);
+ return begin();
}
else
{
@@ -425,6 +556,7 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
m_blocks.insert(m_blocks.begin(), new block(1));
blk = m_blocks[block_index];
create_new_block_with_new_cell(blk->mp_data, cell);
+ return begin();
}
else if (pos_in_block == blk->m_size - 1)
{
@@ -436,17 +568,20 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
blk = m_blocks.back();
create_new_block_with_new_cell(blk->mp_data, cell);
+ iterator ret = end();
+ --ret;
+ return ret;
}
else
{
// Insert into the middle of the block.
- set_cell_to_middle_of_block(block_index, pos_in_block, cell);
+ return set_cell_to_middle_of_block(start_row, block_index, pos_in_block, cell);
}
}
}
else
{
- // this empty block is followed by a non-empty block.
+ // This topmost empty block is followed by a non-empty block.
assert(block_index < m_blocks.size()-1);
if (pos_in_block == 0)
{
@@ -479,6 +614,8 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
blk = m_blocks.front();
create_new_block_with_new_cell(blk->mp_data, cell);
}
+
+ return begin();
}
else if (pos_in_block == blk->m_size - 1)
{
@@ -502,18 +639,20 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
typename blocks_type::iterator it = m_blocks.begin();
std::advance(it, block_index+1);
m_blocks.insert(it, new block(1));
- blk = m_blocks[block_index+1];
- create_new_block_with_new_cell(blk->mp_data, cell);
+ block* blk2 = m_blocks[block_index+1];
+ create_new_block_with_new_cell(blk2->mp_data, cell);
}
+
+ return get_iterator(block_index+1, start_row+blk->m_size);
}
else
{
// Inserting into the middle of an empty block.
- set_cell_to_middle_of_block(block_index, pos_in_block, cell);
+ return set_cell_to_middle_of_block(start_row, block_index, pos_in_block, cell);
}
}
- return;
+ assert(!"this code path should never be reached!");
}
// This empty block is right below a non-empty block.
@@ -527,6 +666,8 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
if (blk_cat_prev == cat)
{
// Extend the previous block by one to insert this cell.
+ size_type offset = m_blocks[block_index-1]->m_size; // for returned iterator
+
if (blk->m_size == 1)
{
// Check if we need to merge with the following block.
@@ -545,6 +686,7 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
element_block_type* data_next = blk_next->mp_data;
assert(data_next); // Empty block must not be followed by another empty block.
element_category_type blk_cat_next = mdds::mtv::get_block_type(*data_next);
+
if (blk_cat_prev == blk_cat_next)
{
// We need to merge the previous and next blocks, then
@@ -578,6 +720,8 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
blk->m_size -= 1;
append_cell_to_block(block_index-1, cell);
}
+
+ return get_iterator(block_index-1, start_row-offset);
}
else
{
@@ -605,7 +749,9 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
m_blocks.erase(m_blocks.begin()+block_index);
}
else
+ {
create_new_block_with_new_cell(blk->mp_data, cell);
+ }
}
}
else
@@ -618,6 +764,8 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
m_blocks.insert(m_blocks.begin()+block_index+1, new block(blk->m_size-1));
blk->m_size = 1;
}
+
+ return get_iterator(block_index, start_row);
}
}
else if (pos_in_block == blk->m_size - 1)
@@ -631,6 +779,9 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
m_blocks.push_back(new block(1));
blk = m_blocks.back();
create_new_block_with_new_cell(blk->mp_data, cell);
+ iterator it = end();
+ --it;
+ return it;
}
else
{
@@ -650,22 +801,25 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_empty_block(
{
// Just insert this new cell.
blk->m_size -= 1;
- m_blocks.insert(m_blocks.begin()+1, new block(1));
- blk = m_blocks[block_index+1];
- create_new_block_with_new_cell(blk->mp_data, cell);
+ m_blocks.insert(m_blocks.begin()+block_index+1, new block(1));
+ block* blk2 = m_blocks[block_index+1];
+ create_new_block_with_new_cell(blk2->mp_data, cell);
}
+
+ size_type offset = blk->m_size;
+ return get_iterator(block_index+1, start_row+offset);
}
}
- else
- {
- // New cell is somewhere in the middle of an empty block.
- set_cell_to_middle_of_block(block_index, pos_in_block, cell);
- }
+
+ // New cell is somewhere in the middle of an empty block.
+ return set_cell_to_middle_of_block(start_row, block_index, pos_in_block, cell);
}
template<typename _CellBlockFunc>
template<typename _T>
-void multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(size_type block_index, const _T& cell)
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(
+ size_type start_row, size_type block_index, const _T& cell)
{
block* blk = m_blocks[block_index];
assert(blk->m_size == 1);
@@ -680,25 +834,16 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(size_type
{
// This is the only block.
create_new_block_with_new_cell(blk->mp_data, cell);
- return;
+ return begin();
}
// There is an existing block below.
block* blk_next = m_blocks[block_index+1];
- if (!blk_next->mp_data)
+ if (!blk_next->mp_data || mdds::mtv::get_block_type(*blk_next->mp_data) != cat)
{
- // Next block is empty.
+ // Next block is empty or of different type.
create_new_block_with_new_cell(blk->mp_data, cell);
- return;
- }
-
- // Next block is not empty.
- element_category_type blk_cat_next = mdds::mtv::get_block_type(*blk_next->mp_data);
- if (blk_cat_next != cat)
- {
- // Cell being inserted is of different type than that of the next block.
- create_new_block_with_new_cell(blk->mp_data, cell);
- return;
+ return begin();
}
// Delete the current block, and prepend the cell to the next block.
@@ -706,7 +851,7 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(size_type
mdds_mtv_prepend_value(*blk_next->mp_data, cell);
delete blk;
m_blocks.erase(m_blocks.begin()+block_index);
- return;
+ return begin();
}
assert(block_index > 0);
@@ -715,15 +860,12 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(size_type
{
// This is the last block, and a block exists above.
block* blk_prev = m_blocks[block_index-1];
- if (!blk_prev->mp_data)
+ if (!blk_prev->mp_data || mdds::mtv::get_block_type(*blk_prev->mp_data) != cat)
{
// Previous block is empty. Replace the current block with a new one.
create_new_block_with_new_cell(blk->mp_data, cell);
- return;
}
-
- element_category_type blk_cat_prev = mdds::mtv::get_block_type(*blk_prev->mp_data);
- if (blk_cat_prev == cat)
+ else
{
// Append the cell to the previos block, and remove the
// current block.
@@ -731,12 +873,11 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(size_type
blk_prev->m_size += 1;
delete blk;
m_blocks.erase(m_blocks.begin()+block_index);
- return;
}
- // Simply replace the current block with a new block of new type.
- create_new_block_with_new_cell(blk->mp_data, cell);
- return;
+ iterator itr = end();
+ --itr;
+ return itr;
}
// Remove the current block, and check if the cell can be append
@@ -752,7 +893,7 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(size_type
{
// Next block is empty too.
create_new_block_with_new_cell(blk->mp_data, cell);
- return;
+ return get_iterator(block_index, start_row);
}
// Previous block is empty, but the next block is not.
@@ -765,12 +906,12 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(size_type
blk = m_blocks[block_index];
blk->m_size += 1;
mdds_mtv_prepend_value(*blk->mp_data, cell);
- return;
+ return get_iterator(block_index, start_row);
}
assert(blk_cat_next != cat);
create_new_block_with_new_cell(blk->mp_data, cell);
- return;
+ return get_iterator(block_index, start_row);
}
if (!blk_next->mp_data)
@@ -781,16 +922,17 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(size_type
if (blk_cat_prev == cat)
{
// Append to the previous block.
+ size_type offset = blk_prev->m_size;
blk_prev->m_size += 1;
mdds_mtv_append_value(*blk_prev->mp_data, cell);
delete blk;
m_blocks.erase(m_blocks.begin()+block_index);
- return;
+ return get_iterator(block_index-1, start_row-offset);
}
// Just overwrite the current block.
create_new_block_with_new_cell(blk->mp_data, cell);
- return;
+ return get_iterator(block_index, start_row);
}
assert(blk_prev && blk_prev->mp_data);
@@ -805,6 +947,7 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(size_type
// Merge the previous block with the cell being inserted and
// the next block. Resize the next block to zero to prevent
// deletion of mananged cells on block deletion.
+ size_type offset = blk_prev->m_size;
blk_prev->m_size += 1 + blk_next->m_size;
mdds_mtv_append_value(*blk_prev->mp_data, cell);
element_block_func::append_values_from_block(*blk_prev->mp_data, *blk_next->mp_data);
@@ -816,12 +959,12 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(size_type
typename blocks_type::iterator it = m_blocks.begin() + block_index;
typename blocks_type::iterator it_last = it + 2;
m_blocks.erase(it, it_last);
- return;
+ return get_iterator(block_index-1, start_row-offset);
}
// Just overwrite the current block.
create_new_block_with_new_cell(blk->mp_data, cell);
- return;
+ return get_iterator(block_index, start_row);
}
assert(blk_cat_prev != blk_cat_next);
@@ -829,11 +972,12 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(size_type
if (blk_cat_prev == cat)
{
// Append to the previous block.
+ size_type offset = blk_prev->m_size;
blk_prev->m_size += 1;
mdds_mtv_append_value(*blk_prev->mp_data, cell);
delete blk;
m_blocks.erase(m_blocks.begin()+block_index);
- return;
+ return get_iterator(block_index-1, start_row-offset);
}
if (blk_cat_next == cat)
@@ -843,11 +987,12 @@ void multi_type_vector<_CellBlockFunc>::set_cell_to_block_of_size_one(size_type
mdds_mtv_prepend_value(*blk_next->mp_data, cell);
delete blk;
m_blocks.erase(m_blocks.begin()+block_index);
- return;
+ return get_iterator(block_index, start_row);
}
// Just overwrite the current block.
create_new_block_with_new_cell(blk->mp_data, cell);
+ return get_iterator(block_index, start_row);
}
template<typename _CellBlockFunc>
@@ -882,8 +1027,10 @@ template<typename _T>
void multi_type_vector<_CellBlockFunc>::get(size_type pos, _T& value) const
{
size_type start_row = 0;
- size_type block_index = static_cast<size_type>(-1);
- get_block_position(pos, start_row, block_index);
+ size_type block_index = 0;
+ if (!get_block_position(pos, start_row, block_index))
+ throw std::out_of_range("Block position not found!");
+
const block* blk = m_blocks[block_index];
assert(blk);
@@ -913,8 +1060,10 @@ template<typename _CellBlockFunc>
mtv::element_t multi_type_vector<_CellBlockFunc>::get_type(size_type pos) const
{
size_type start_row = 0;
- size_type block_index = static_cast<size_type>(-1);
- get_block_position(pos, start_row, block_index);
+ size_type block_index = 0;
+ if (!get_block_position(pos, start_row, block_index))
+ throw std::out_of_range("Block position not found!");
+
const block* blk = m_blocks[block_index];
if (!blk->mp_data)
return mtv::element_type_empty;
@@ -927,30 +1076,52 @@ bool multi_type_vector<_CellBlockFunc>::is_empty(size_type pos) const
{
size_type start_row = 0;
size_type block_index = 0;
- get_block_position(pos, start_row, block_index);
+ if (!get_block_position(pos, start_row, block_index))
+ throw std::out_of_range("Block position not found!");
return m_blocks[block_index]->mp_data == NULL;
}
template<typename _CellBlockFunc>
-void multi_type_vector<_CellBlockFunc>::set_empty(size_type start_pos, size_type end_pos)
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_empty(size_type start_pos, size_type end_pos)
+{
+ size_type start_pos_in_block1 = 0;
+ size_type block_index1 = 0;
+ if (!get_block_position(start_pos, start_pos_in_block1, block_index1))
+ throw std::out_of_range("Block position not found!");
+
+ return set_empty_impl(start_pos, end_pos, start_pos_in_block1, block_index1);
+}
+
+template<typename _CellBlockFunc>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_empty(iterator pos_hint, size_type start_pos, size_type end_pos)
+{
+ size_type start_pos_in_block1 = 0;
+ size_type block_index1 = 0;
+ get_block_position(pos_hint, start_pos, start_pos_in_block1, block_index1);
+ return set_empty_impl(start_pos, end_pos, start_pos_in_block1, block_index1);
+}
+
+template<typename _CellBlockFunc>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_empty_impl(
+ size_type start_pos, size_type end_pos, size_type start_pos_in_block1, size_type block_index1)
{
if (start_pos > end_pos)
throw std::out_of_range("Start row is larger than the end row.");
- size_type start_row_in_block1 = 0, start_row_in_block2 = 0;
- size_type block_pos1 = 0, block_pos2 = 0;
- get_block_position(start_pos, start_row_in_block1, block_pos1);
- get_block_position(end_pos, start_row_in_block2, block_pos2, block_pos1, start_row_in_block1);
+ size_type start_pos_in_block2 = start_pos_in_block1;
+ size_type block_index2 = block_index1;
+ if (!get_block_position(end_pos, start_pos_in_block2, block_index2))
+ throw std::out_of_range("Block position not found!");
- if (block_pos1 == block_pos2)
- {
- set_empty_in_single_block(start_pos, end_pos, block_pos1, start_row_in_block1);
- return;
- }
+ if (block_index1 == block_index2)
+ return set_empty_in_single_block(start_pos, end_pos, block_index1, start_pos_in_block1);
- set_empty_in_multi_blocks(
- start_pos, end_pos, block_pos1, start_row_in_block1, block_pos2, start_row_in_block2);
+ return set_empty_in_multi_blocks(
+ start_pos, end_pos, block_index1, start_pos_in_block1, block_index2, start_pos_in_block2);
}
template<typename _CellBlockFunc>
@@ -969,10 +1140,15 @@ void multi_type_vector<_CellBlockFunc>::erase_impl(size_type start_row, size_typ
// Keep the logic similar to set_empty().
- size_type start_row_in_block1 = 0, start_row_in_block2 = 0;
- size_type block_pos1 = 0, block_pos2 = 0;
- get_block_position(start_row, start_row_in_block1, block_pos1);
- get_block_position(end_row, start_row_in_block2, block_pos2, block_pos1, start_row_in_block1);
+ size_type start_row_in_block1 = 0;
+ size_type block_pos1 = 0;
+ if (!get_block_position(start_row, start_row_in_block1, block_pos1))
+ throw std::out_of_range("Block position not found!");
+
+ size_type start_row_in_block2 = start_row_in_block1;
+ size_type block_pos2 = block_pos1;
+ if (!get_block_position(end_row, start_row_in_block2, block_pos2))
+ throw std::out_of_range("Block position not found!");
if (block_pos1 == block_pos2)
{
@@ -1091,22 +1267,40 @@ void multi_type_vector<_CellBlockFunc>::erase_impl(size_type start_row, size_typ
}
template<typename _CellBlockFunc>
-void multi_type_vector<_CellBlockFunc>::insert_empty(size_type pos, size_type length)
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::insert_empty(size_type pos, size_type length)
{
if (!length)
// Nothing to insert.
- return;
+ return end();
+
+ size_type start_pos = 0, block_index = 0;
+ if (!get_block_position(pos, start_pos, block_index))
+ throw std::out_of_range("Block position not found!");
- insert_empty_impl(pos, length);
+ return insert_empty_impl(pos, start_pos, block_index, length);
}
template<typename _CellBlockFunc>
-void multi_type_vector<_CellBlockFunc>::insert_empty_impl(size_type row, size_type length)
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::insert_empty(iterator pos_hint, size_type pos, size_type length)
{
- assert(row < m_cur_size);
+ if (!length)
+ // Nothing to insert.
+ return end();
- size_type start_row = 0, block_index = 0;
- get_block_position(row, start_row, block_index);
+ size_type start_pos = 0, block_index = 0;
+ get_block_position(pos_hint, pos, start_pos, block_index);
+
+ return insert_empty_impl(pos, start_pos, block_index, length);
+}
+
+template<typename _CellBlockFunc>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::insert_empty_impl(
+ size_type pos, size_type start_pos, size_type block_index, size_type length)
+{
+ assert(pos < m_cur_size);
block* blk = m_blocks[block_index];
if (!blk->mp_data)
@@ -1115,10 +1309,10 @@ void multi_type_vector<_CellBlockFunc>::insert_empty_impl(size_type row, size_ty
// with it.
blk->m_size += length;
m_cur_size += length;
- return;
+ return get_iterator(block_index, start_pos);
}
- if (start_row == row)
+ if (start_pos == pos)
{
// Insertion point is at the top of an existing non-empty block.
if (block_index > 0)
@@ -1128,26 +1322,28 @@ void multi_type_vector<_CellBlockFunc>::insert_empty_impl(size_type row, size_ty
{
// Previous block is empty. Expand the size of the previous
// block and bail out.
+ size_type offset = blk_prev->m_size;
blk_prev->m_size += length;
m_cur_size += length;
- return;
+ return get_iterator(block_index-1, pos-offset);
}
}
// Insert a new empty block.
m_blocks.insert(m_blocks.begin()+block_index, new block(length));
m_cur_size += length;
- return;
+ return get_iterator(block_index, pos);
}
assert(blk->mp_data);
- assert(row > start_row);
+ assert(pos > start_pos);
- size_type size_blk_prev = row - start_row;
+ size_type size_blk_prev = pos - start_pos;
size_type size_blk_next = blk->m_size - size_blk_prev;
- // Insert two new block below the current; one for the empty block being
- // inserted, and one for the lower part of the current non-empty block.
+ // Insert two new blocks below the current; one for the empty block being
+ // inserted, and the other for the lower part of the current non-empty
+ // block.
m_blocks.insert(m_blocks.begin()+block_index+1, 2u, NULL);
m_blocks[block_index+1] = new block(length);
@@ -1161,47 +1357,58 @@ void multi_type_vector<_CellBlockFunc>::insert_empty_impl(size_type row, size_ty
blk->m_size = size_blk_prev;
m_cur_size += length;
+
+ return get_iterator(block_index+1, pos);
}
template<typename _CellBlockFunc>
template<typename _T>
-void multi_type_vector<_CellBlockFunc>::set_cells_impl(size_type row, const _T& it_begin, const _T& it_end)
+bool multi_type_vector<_CellBlockFunc>::set_cells_precheck(
+ size_type pos, const _T& it_begin, const _T& it_end, size_type& end_pos)
{
size_type length = std::distance(it_begin, it_end);
if (!length)
// empty data array. nothing to do.
- return;
+ return false;
- size_type end_row = row + length - 1;
- if (end_row >= m_cur_size)
+ end_pos = pos + length - 1;
+ if (end_pos >= m_cur_size)
throw std::out_of_range("Data array is too long.");
- size_t block_index1 = 0, block_index2 = 0, start_row1 = 0, start_row2 = 0;
- get_block_position(row, start_row1, block_index1);
- get_block_position(end_row, start_row2, block_index2, block_index1, start_row1);
+ return true;
+}
+
+template<typename _CellBlockFunc>
+template<typename _T>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_cells_impl(
+ size_type row, size_type end_row, size_type start_row1, size_type block_index1, const _T& it_begin, const _T& it_end)
+{
+ size_type start_row2 = start_row1;
+ size_type block_index2 = block_index1;
+ if (!get_block_position(end_row, start_row2, block_index2))
+ throw std::out_of_range("Block position not found!");
if (block_index1 == block_index2)
{
// The whole data array will fit in a single block.
- set_cells_to_single_block(row, end_row, block_index1, start_row1, it_begin, it_end);
- return;
+ return set_cells_to_single_block(row, end_row, block_index1, start_row1, it_begin, it_end);
}
- set_cells_to_multi_blocks(
+ return set_cells_to_multi_blocks(
row, end_row, block_index1, start_row1, block_index2, start_row2, it_begin, it_end);
}
template<typename _CellBlockFunc>
template<typename _T>
-void multi_type_vector<_CellBlockFunc>::insert_cells_impl(size_type row, const _T& it_begin, const _T& it_end)
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::insert_cells_impl(
+ size_type row, size_type start_row, size_type block_index, const _T& it_begin, const _T& it_end)
{
size_type length = std::distance(it_begin, it_end);
if (!length)
// empty data array. nothing to do.
- return;
-
- size_type block_index = 0, start_row = 0;
- get_block_position(row, start_row, block_index);
+ return end();
element_category_type cat = mdds_mtv_get_element_type(*it_begin);
block* blk = m_blocks[block_index];
@@ -1221,9 +1428,11 @@ void multi_type_vector<_CellBlockFunc>::insert_cells_impl(size_type row, const _
{
// Append to the previous block.
mdds_mtv_append_values(*blk0->mp_data, *it_begin, it_begin, it_end);
+ size_type offset = blk0->m_size;
blk0->m_size += length;
m_cur_size += length;
- return;
+
+ return get_iterator(block_index-1, start_row-offset);
}
}
@@ -1234,12 +1443,14 @@ void multi_type_vector<_CellBlockFunc>::insert_cells_impl(size_type row, const _
mdds_mtv_assign_values(*blk->mp_data, *it_begin, it_begin, it_end);
blk->m_size = length;
m_cur_size += length;
- return;
+
+ return get_iterator(block_index, start_row);
}
insert_cells_to_middle(row, block_index, start_row, it_begin, it_end);
m_cur_size += length;
- return;
+
+ return get_iterator(block_index+1, row);
}
assert(blk->mp_data);
@@ -1251,7 +1462,7 @@ void multi_type_vector<_CellBlockFunc>::insert_cells_impl(size_type row, const _
mdds_mtv_insert_values(*blk->mp_data, row-start_row, *it_begin, it_begin, it_end);
blk->m_size += length;
m_cur_size += length;
- return;
+ return get_iterator(block_index, start_row);
}
assert(cat != blk_cat);
@@ -1261,17 +1472,14 @@ void multi_type_vector<_CellBlockFunc>::insert_cells_impl(size_type row, const _
{
// Check the previous block to see if we can append the data there.
block* blk0 = m_blocks[block_index-1];
- if (blk0->mp_data)
+ if (blk0->mp_data && cat == mdds::mtv::get_block_type(*blk0->mp_data))
{
- element_category_type blk_cat0 = mdds::mtv::get_block_type(*blk0->mp_data);
- if (cat == blk_cat0)
- {
- // Append to the previous block.
- mdds_mtv_append_values(*blk0->mp_data, *it_begin, it_begin, it_end);
- blk0->m_size += length;
- m_cur_size += length;
- return;
- }
+ // Append to the previous block.
+ size_type offset = blk0->m_size;
+ mdds_mtv_append_values(*blk0->mp_data, *it_begin, it_begin, it_end);
+ blk0->m_size += length;
+ m_cur_size += length;
+ return get_iterator(block_index-1, start_row-offset);
}
}
@@ -1282,11 +1490,14 @@ void multi_type_vector<_CellBlockFunc>::insert_cells_impl(size_type row, const _
mdds_mtv_assign_values(*blk->mp_data, *it_begin, it_begin, it_end);
blk->m_size = length;
m_cur_size += length;
- return;
+
+ return get_iterator(block_index, start_row);
}
insert_cells_to_middle(row, block_index, start_row, it_begin, it_end);
m_cur_size += length;
+
+ return get_iterator(block_index+1, row);
}
template<typename _CellBlockFunc>
@@ -1330,7 +1541,8 @@ void multi_type_vector<_CellBlockFunc>::insert_cells_to_middle(
template<typename _CellBlockFunc>
template<typename _T>
-void multi_type_vector<_CellBlockFunc>::set_cells_to_single_block(
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_cells_to_single_block(
size_type start_row, size_type end_row, size_type block_index,
size_type start_row_in_block, const _T& it_begin, const _T& it_end)
{
@@ -1341,17 +1553,13 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_single_block(
block* blk = m_blocks[block_index];
size_type data_length = std::distance(it_begin, it_end);
- if (blk->mp_data)
+ if (blk->mp_data && mdds::mtv::get_block_type(*blk->mp_data) == cat)
{
- element_category_type blk_cat = mdds::mtv::get_block_type(*blk->mp_data);
- if (cat == blk_cat)
- {
- // simple overwrite.
- size_type offset = start_row - start_row_in_block;
- element_block_func::overwrite_values(*blk->mp_data, offset, data_length);
- mdds_mtv_set_values(*blk->mp_data, offset, *it_begin, it_begin, it_end);
- return;
- }
+ // simple overwrite.
+ size_type offset = start_row - start_row_in_block;
+ element_block_func::overwrite_values(*blk->mp_data, offset, data_length);
+ mdds_mtv_set_values(*blk->mp_data, offset, *it_begin, it_begin, it_end);
+ return get_iterator(block_index, start_row_in_block);
}
size_type end_row_in_block = start_row_in_block + blk->m_size - 1;
@@ -1360,11 +1568,16 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_single_block(
if (end_row == end_row_in_block)
{
// Check if we could append it to the previous block.
+ size_type offset = block_index > 0 ? m_blocks[block_index-1]->m_size : 0;
if (append_to_prev_block(block_index, cat, end_row-start_row+1, it_begin, it_end))
{
delete blk;
m_blocks.erase(m_blocks.begin()+block_index);
- return;
+
+ // Check if we need to merge it with the next block.
+ --block_index;
+ merge_with_next_block(block_index);
+ return get_iterator(block_index, start_row_in_block-offset);
}
// Replace the whole block.
@@ -1373,7 +1586,8 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_single_block(
blk->mp_data = element_block_func::create_new_block(cat, 0);
mdds_mtv_assign_values(*blk->mp_data, *it_begin, it_begin, it_end);
- return;
+ merge_with_next_block(block_index);
+ return get_iterator(block_index, start_row_in_block);
}
// Replace the upper part of the block.
@@ -1402,8 +1616,9 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_single_block(
}
length = end_row - start_row + 1;
+ size_type offset = block_index > 0 ? m_blocks[block_index-1]->m_size : 0;
if (append_to_prev_block(block_index, cat, length, it_begin, it_end))
- return;
+ return get_iterator(block_index-1, start_row_in_block-offset);
// Insert a new block before the current block, and populate it with
// the new data.
@@ -1412,7 +1627,7 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_single_block(
blk->mp_data = element_block_func::create_new_block(cat, 0);
blk->m_size = length;
mdds_mtv_assign_values(*blk->mp_data, *it_begin, it_begin, it_end);
- return;
+ return get_iterator(block_index, start_row_in_block);
}
assert(start_row > start_row_in_block);
@@ -1433,16 +1648,12 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_single_block(
{
// Check the next block.
block* blk_next = m_blocks[block_index+1];
- if (blk_next->mp_data)
+ if (blk_next->mp_data && cat == mdds::mtv::get_block_type(*blk_next->mp_data))
{
- element_category_type blk_cat_next = mdds::mtv::get_block_type(*blk_next->mp_data);
- if (blk_cat_next == cat)
- {
- // Prepend it to the next block.
- mdds_mtv_prepend_values(*blk_next->mp_data, *it_begin, it_begin, it_end);
- blk_next->m_size += end_row - start_row + 1;
- return;
- }
+ // Prepend it to the next block.
+ mdds_mtv_prepend_values(*blk_next->mp_data, *it_begin, it_begin, it_end);
+ blk_next->m_size += end_row - start_row + 1;
+ return get_iterator(block_index+1, start_row);
}
// Next block has a different data type. Do the normal insertion.
@@ -1450,7 +1661,7 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_single_block(
blk = m_blocks[block_index+1];
blk->mp_data = element_block_func::create_new_block(cat, 0);
mdds_mtv_assign_values(*blk->mp_data, *it_begin, it_begin, it_end);
- return;
+ return get_iterator(block_index+1, start_row);
}
// Last block.
@@ -1460,7 +1671,7 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_single_block(
blk = m_blocks.back();
blk->mp_data = element_block_func::create_new_block(cat, 0);
mdds_mtv_assign_values(*blk->mp_data, *it_begin, it_begin, it_end);
- return;
+ return get_iterator(block_index+1, start_row);
}
// new data array will be in the middle of the current block.
@@ -1496,11 +1707,14 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_single_block(
element_block_func::resize_block(*blk->mp_data, new_cur_size);
}
blk->m_size = new_cur_size;
+
+ return get_iterator(block_index+1, start_row);
}
template<typename _CellBlockFunc>
template<typename _T>
-void multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks(
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks(
size_type start_row, size_type end_row,
size_type block_index1, size_type start_row_in_block1,
size_type block_index2, size_type start_row_in_block2,
@@ -1513,24 +1727,23 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks(
block* blk1 = m_blocks[block_index1];
if (blk1->mp_data)
{
- set_cells_to_multi_blocks_block1_non_empty(
+ return set_cells_to_multi_blocks_block1_non_empty(
start_row, end_row, block_index1, start_row_in_block1,
block_index2, start_row_in_block2, it_begin, it_end);
-
- return;
}
// Block 1 is empty.
assert(!blk1->mp_data);
- set_cells_to_multi_blocks_block1_non_equal(
+ return set_cells_to_multi_blocks_block1_non_equal(
start_row, end_row, block_index1, start_row_in_block1,
block_index2, start_row_in_block2, it_begin, it_end);
}
template<typename _CellBlockFunc>
template<typename _T>
-void multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks_block1_non_equal(
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks_block1_non_equal(
size_type start_row, size_type end_row,
size_type block_index1, size_type start_row_in_block1,
size_type block_index2, size_type start_row_in_block2,
@@ -1543,6 +1756,8 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks_block1_non_equ
size_type offset = start_row - start_row_in_block1;
size_type end_row_in_block2 = start_row_in_block2 + blk2->m_size - 1;
+ size_type start_row_itr = start_row_in_block1;
+
// Initially set to erase blocks between block 1 and block 2.
typename blocks_type::iterator it_erase_begin = m_blocks.begin() + block_index1 + 1;
typename blocks_type::iterator it_erase_end = m_blocks.begin() + block_index2;
@@ -1560,18 +1775,16 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks_block1_non_equ
if (block_index1 > 0)
{
block* blk0 = m_blocks[block_index1-1];
- if (blk0->mp_data)
+ if (blk0->mp_data && cat == mdds::mtv::get_block_type(*blk0->mp_data))
{
- if (cat == mdds::mtv::get_block_type(*blk0->mp_data))
- {
- // Transfer the whole data from block 0 to data block.
- data_blk->mp_data = blk0->mp_data;
- blk0->mp_data = NULL;
-
- data_blk->m_size += blk0->m_size;
- --it_erase_begin;
- blk0_copied = true;
- }
+ // Transfer the whole data from block 0 to data block.
+ data_blk->mp_data = blk0->mp_data;
+ blk0->mp_data = NULL;
+
+ start_row_itr -= blk0->m_size;
+ data_blk->m_size += blk0->m_size;
+ --it_erase_begin;
+ blk0_copied = true;
}
}
}
@@ -1585,6 +1798,7 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks_block1_non_equ
element_block_func::resize_block(*blk1->mp_data, offset);
}
blk1->m_size = offset;
+ start_row_itr += offset;
}
if (blk0_copied)
@@ -1658,11 +1872,14 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks_block1_non_equ
// Insert the new data block.
m_blocks.insert(m_blocks.begin()+insert_pos, data_blk.release());
+
+ return get_iterator(insert_pos, start_row_itr);
}
template<typename _CellBlockFunc>
template<typename _T>
-void multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks_block1_non_empty(
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks_block1_non_empty(
size_type start_row, size_type end_row,
size_type block_index1, size_type start_row_in_block1,
size_type block_index2, size_type start_row_in_block2,
@@ -1731,18 +1948,47 @@ void multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks_block1_non_emp
std::for_each(it_erase_begin, it_erase_end, default_deleter<block>());
m_blocks.erase(it_erase_begin, it_erase_end);
- return;
+ return get_iterator(block_index1, start_row_in_block1);
}
// The first block type is different.
assert(blk_cat1 != cat);
- set_cells_to_multi_blocks_block1_non_equal(
+ return set_cells_to_multi_blocks_block1_non_equal(
start_row, end_row, block_index1, start_row_in_block1,
block_index2, start_row_in_block2, it_begin, it_end);
}
template<typename _CellBlockFunc>
+void multi_type_vector<_CellBlockFunc>::merge_with_next_block(size_type block_index)
+{
+ if (block_index >= m_blocks.size()-1)
+ // No more block below this one.
+ return;
+
+ // Block exists below.
+ block* blk = m_blocks[block_index];
+ if (!blk->mp_data)
+ // Don't merge an empty block.
+ return;
+
+ block* blk_next = m_blocks[block_index+1];
+ if (!blk_next->mp_data)
+ return;
+
+ if (mdds::mtv::get_block_type(*blk->mp_data) != mdds::mtv::get_block_type(*blk_next->mp_data))
+ // Block types differ. Don't merge.
+ return;
+
+ // Merge it with the next block.
+ element_block_func::append_values_from_block(*blk->mp_data, *blk_next->mp_data);
+ element_block_func::resize_block(*blk_next->mp_data, 0);
+ blk->m_size += blk_next->m_size;
+ delete m_blocks[block_index+1];
+ m_blocks.erase(m_blocks.begin()+block_index+1);
+}
+
+template<typename _CellBlockFunc>
template<typename _T>
bool multi_type_vector<_CellBlockFunc>::append_to_prev_block(
size_type block_index, element_category_type cat, size_type length,
@@ -1839,7 +2085,8 @@ void multi_type_vector<_CellBlockFunc>::resize(size_type new_size)
// Find out in which block the new end row will be.
size_type new_end_row = new_size - 1;
size_type start_row_in_block = 0, block_index = 0;
- get_block_position(new_end_row, start_row_in_block, block_index);
+ if (!get_block_position(new_end_row, start_row_in_block, block_index))
+ throw std::out_of_range("Block position not found!");
block* blk = m_blocks[block_index];
size_type end_row_in_block = start_row_in_block + blk->m_size - 1;
@@ -1929,14 +2176,15 @@ mtv::element_t multi_type_vector<_CellBlockFunc>::get_element_type(const _T& ele
}
template<typename _CellBlockFunc>
-void multi_type_vector<_CellBlockFunc>::set_empty_in_single_block(
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_empty_in_single_block(
size_type start_row, size_type end_row, size_type block_index, size_type start_row_in_block)
{
// Range is within a single block.
block* blk = m_blocks[block_index];
if (!blk->mp_data)
// This block is already empty. Do nothing.
- return;
+ return get_iterator(block_index, start_row_in_block);
assert(start_row_in_block + blk->m_size >= 1);
size_type end_row_in_block = start_row_in_block + blk->m_size - 1;
@@ -1951,7 +2199,7 @@ void multi_type_vector<_CellBlockFunc>::set_empty_in_single_block(
// Set the whole block empty.
element_block_func::delete_block(blk->mp_data);
blk->mp_data = NULL;
- return;
+ return get_iterator(block_index, start_row_in_block);
}
// Set the upper part of the block empty.
@@ -1961,7 +2209,7 @@ void multi_type_vector<_CellBlockFunc>::set_empty_in_single_block(
// Insert a new empty block before the current one.
m_blocks.insert(m_blocks.begin()+block_index, new block(empty_block_size));
- return;
+ return get_iterator(block_index, start_row_in_block);
}
if (end_row == end_row_in_block)
@@ -1977,7 +2225,7 @@ void multi_type_vector<_CellBlockFunc>::set_empty_in_single_block(
// Insert a new empty block after the current one.
m_blocks.insert(m_blocks.begin()+block_index+1, new block(empty_block_size));
- return;
+ return get_iterator(block_index+1, start_row);
}
// Empty the middle part of a block.
@@ -2008,10 +2256,13 @@ void multi_type_vector<_CellBlockFunc>::set_empty_in_single_block(
element_block_func::erase(
*blk->mp_data, new_cur_size, end_row_in_block-start_row+1);
blk->m_size = new_cur_size;
+
+ return get_iterator(block_index+1, start_row);
}
template<typename _CellBlockFunc>
-void multi_type_vector<_CellBlockFunc>::set_empty_in_multi_blocks(
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::set_empty_in_multi_blocks(
size_type start_row, size_type end_row,
size_type block_index1, size_type start_row_in_block1,
size_type block_index2, size_type start_row_in_block2)
@@ -2089,19 +2340,18 @@ void multi_type_vector<_CellBlockFunc>::set_empty_in_multi_blocks(
m_blocks.erase(it, it_end);
}
- // Insert a single empty block.
block* blk = m_blocks[block_index1];
size_type empty_block_size = end_row - start_row + 1;
if (blk->mp_data)
{
// Insert a new empty block after the first block.
m_blocks.insert(m_blocks.begin()+block_index1+1, new block(empty_block_size));
+ return get_iterator(block_index1+1, start_row);
}
- else
- {
- // Current block is already empty. Just extend its size.
- blk->m_size = empty_block_size;
- }
+
+ // Current block is already empty. Just extend its size.
+ blk->m_size = empty_block_size;
+ return get_iterator(block_index1, start_row);
}
}
diff --git a/include/mdds/multi_type_vector_itr.hpp b/include/mdds/multi_type_vector_itr.hpp
index fa4d218..60e533c 100644
--- a/include/mdds/multi_type_vector_itr.hpp
+++ b/include/mdds/multi_type_vector_itr.hpp
@@ -1,6 +1,6 @@
/*************************************************************************
*
- * Copyright (c) 2012 Kohei Yoshida
+ * Copyright (c) 2012-2013 Kohei Yoshida
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -27,78 +27,150 @@
namespace mdds { namespace __mtv {
-template<typename _ColType, typename _BlksType, typename _ItrType>
-class iterator_base
+/**
+ * Node that represents the content of each iterator. The private data part
+ * is an implementation detail that should never be accessed externally.
+ * What the end position stores in its private data is totally &
+ * intentionally undefined.
+ */
+template<typename _SizeT, typename _ElemBlkT>
+struct iterator_value_node
{
- typedef _ColType parent_type;
- typedef _BlksType blocks_type;
- typedef _ItrType base_iterator_type;
+ typedef _SizeT size_type;
+ typedef _ElemBlkT element_block_type;
- struct node
+ mdds::mtv::element_t type;
+ size_type size;
+ element_block_type* data;
+
+ iterator_value_node(size_type start_pos, size_type block_index) :
+ type(mdds::mtv::element_type_empty), size(0), data(NULL), __private_data(start_pos, block_index) {}
+
+ iterator_value_node(const iterator_value_node& other) :
+ type(other.type), size(other.size), data(other.data), __private_data(other.__private_data) {}
+
+ void swap(iterator_value_node& other)
{
- mdds::mtv::element_t type;
- typename parent_type::size_type size;
- const typename parent_type::element_block_type* data;
+ std::swap(type, other.type);
+ std::swap(size, other.size);
+ std::swap(data, other.data);
- node() : type(mdds::mtv::element_type_empty), size(0), data(NULL) {}
- node(const node& other) : type(other.type), size(other.size), data(other.data) {}
- };
+ __private_data.swap(other.__private_data);
+ }
-public:
+ struct private_data
+ {
+ size_type start_pos;
+ size_type block_index;
- // iterator traits
- typedef node value_type;
- typedef value_type* pointer;
- typedef value_type& reference;
- typedef ptrdiff_t difference_type;
- typedef std::bidirectional_iterator_tag iterator_category;
+ private_data() : start_pos(0), block_index(0) {}
+ private_data(size_type _start_pos, size_type _block_index) :
+ start_pos(_start_pos), block_index(_block_index) {}
+ private_data(const private_data& other) :
+ start_pos(other.start_pos), block_index(other.block_index) {}
-public:
- iterator_base() {}
- iterator_base(const base_iterator_type& pos, const base_iterator_type& end) :
- m_pos(pos), m_end(end)
+ void swap(private_data& other)
+ {
+ std::swap(start_pos, other.start_pos);
+ std::swap(block_index, other.block_index);
+ }
+ };
+ private_data __private_data;
+
+ bool operator== (const iterator_value_node& other) const
{
- if (m_pos != m_end)
- update_node();
+ return type == other.type && size == other.size && data == other.data &&
+ __private_data.start_pos == other.__private_data.start_pos &&
+ __private_data.block_index == other.__private_data.block_index;
}
- iterator_base(const iterator_base& other) :
- m_pos(other.m_pos), m_end(other.m_end)
+ bool operator!= (const iterator_value_node& other) const
{
- if (m_pos != m_end)
- update_node();
+ return !operator== (other);
}
+};
+
+template<typename _NodeT>
+struct private_data_no_update
+{
+ typedef _NodeT node_type;
+
+ static void inc(node_type&) {}
+ static void dec(node_type&) {}
+};
+
+template<typename _NodeT>
+struct private_data_forward_update
+{
+ typedef _NodeT node_type;
- bool operator== (const iterator_base& other) const
+ static void inc(node_type& nd)
{
- return m_pos == other.m_pos && m_end == other.m_end;
+ ++nd.__private_data.block_index;
+ nd.__private_data.start_pos += nd.size;
}
- bool operator!= (const iterator_base& other) const
+ static void dec(node_type& nd)
{
- return !operator==(other);
+ --nd.__private_data.block_index;
+ nd.__private_data.start_pos -= nd.size;
}
+};
+
+/**
+ * Common base for both const and non-const iterators. Its protected inc()
+ * and dec() methods have non-const return type, and the derived classes
+ * wrap them and return values with their respective const modifiers.
+ */
+template<typename _Trait>
+class iterator_common_base
+{
+protected:
+ typedef typename _Trait::parent parent_type;
+ typedef typename _Trait::blocks blocks_type;
+ typedef typename _Trait::base_iterator base_iterator_type;
+
+ typedef typename parent_type::size_type size_type;
+ typedef iterator_value_node<size_type, typename parent_type::element_block_type> node;
+
+ iterator_common_base() : m_cur_node(0, 0) {}
- iterator_base& operator= (const iterator_base& other)
+ iterator_common_base(
+ const base_iterator_type& pos, const base_iterator_type& end,
+ size_type start_pos, size_type block_index) :
+ m_cur_node(start_pos, block_index),
+ m_pos(pos),
+ m_end(end)
{
- m_pos = other.m_pos;
- m_end = other.m_end;
if (m_pos != m_end)
update_node();
- return *this;
}
- const value_type& operator*() const
+ iterator_common_base(const iterator_common_base& other) :
+ m_cur_node(other.m_cur_node),
+ m_pos(other.m_pos),
+ m_end(other.m_end)
{
- return m_cur_node;
}
- const value_type* operator->() const
+ void update_node()
{
- return &m_cur_node;
+#ifdef MDDS_MULTI_TYPE_VECTOR_DEBUG
+ if (m_pos == m_end)
+ throw general_error("Current node position should never equal the end position during node update.");
+#endif
+ // blocks_type::value_type is a pointer to multi_type_vector::block.
+ typename blocks_type::value_type blk = *m_pos;
+ if (blk->mp_data)
+ m_cur_node.type = mdds::mtv::get_block_type(*blk->mp_data);
+ else
+ m_cur_node.type = mdds::mtv::element_type_empty;
+
+ m_cur_node.size = blk->m_size;
+ m_cur_node.data = blk->mp_data;
}
- const value_type* operator++()
+ node* inc()
{
++m_pos;
if (m_pos == m_end)
@@ -108,32 +180,185 @@ public:
return &m_cur_node;
}
- const value_type* operator--()
+ node* dec()
{
--m_pos;
update_node();
return &m_cur_node;
}
-private:
+ node m_cur_node;
+ base_iterator_type m_pos;
+ base_iterator_type m_end;
- void update_node()
+public:
+ bool operator== (const iterator_common_base& other) const
{
- // blocks_type::value_type is a pointer to column_type::block.
- const typename blocks_type::value_type blk = *m_pos;
- if (blk->mp_data)
- m_cur_node.type = mdds::mtv::get_block_type(*blk->mp_data);
- else
- m_cur_node.type = mdds::mtv::element_type_empty;
+ if (m_pos != m_end && other.m_pos != other.m_end)
+ {
+ // TODO: Set hard-coded values to the current node for the end
+ // position nodes to remove this if block.
+ if (m_cur_node != other.m_cur_node)
+ return false;
+ }
+ return m_pos == other.m_pos && m_end == other.m_end;
+ }
- m_cur_node.size = blk->m_size;
- m_cur_node.data = blk->mp_data;
+ bool operator!= (const iterator_common_base& other) const
+ {
+ return !operator==(other);
}
-private:
- node m_cur_node;
- base_iterator_type m_pos;
- base_iterator_type m_end;
+ iterator_common_base& operator= (const iterator_common_base& other)
+ {
+ iterator_common_base assigned(other);
+ swap(assigned);
+ return *this;
+ }
+
+ void swap(iterator_common_base& other)
+ {
+ m_cur_node.swap(other.m_cur_node);
+ std::swap(m_pos, other.m_pos);
+ std::swap(m_end, other.m_end);
+ }
+};
+
+template<typename _Trait, typename _NodeUpdateFunc>
+class iterator_base : public iterator_common_base<_Trait>
+{
+ typedef _Trait trait;
+ typedef _NodeUpdateFunc node_update_func;
+ typedef iterator_common_base<trait> common_base;
+
+ typedef typename trait::base_iterator base_iterator_type;
+ typedef typename common_base::size_type size_type;
+
+ using common_base::inc;
+ using common_base::dec;
+ using common_base::m_cur_node;
+ using common_base::m_pos;
+ using common_base::m_end;
+
+public:
+
+ // iterator traits
+ typedef typename common_base::node value_type;
+ typedef value_type* pointer;
+ typedef value_type& reference;
+ typedef ptrdiff_t difference_type;
+ typedef std::bidirectional_iterator_tag iterator_category;
+
+public:
+ iterator_base() {}
+ iterator_base(
+ const base_iterator_type& pos, const base_iterator_type& end,
+ size_type start_pos, size_type block_index) :
+ common_base(pos, end, start_pos, block_index) {}
+
+ iterator_base(const iterator_base& other) :
+ common_base(other) {}
+
+ value_type& operator*()
+ {
+ return m_cur_node;
+ }
+
+ const value_type& operator*() const
+ {
+ return m_cur_node;
+ }
+
+ value_type* operator->()
+ {
+ return &m_cur_node;
+ }
+
+ const value_type* operator->() const
+ {
+ return &m_cur_node;
+ }
+
+ value_type* operator++()
+ {
+ node_update_func::inc(m_cur_node);
+ return inc();
+ }
+
+ value_type* operator--()
+ {
+ value_type* ret = dec();
+ node_update_func::dec(m_cur_node);
+ return ret;
+ }
+
+ /**
+ * These method are public only to allow const_iterator_base to
+ * instantiate from iterator_base.
+ */
+ const base_iterator_type& get_pos() const { return m_pos; }
+ const base_iterator_type& get_end() const { return m_end; }
+};
+
+template<typename _Trait, typename _NonConstItrBase>
+class const_iterator_base : public iterator_common_base<_Trait>
+{
+ typedef _Trait trait;
+ typedef iterator_common_base<trait> common_base;
+
+ typedef typename trait::base_iterator base_iterator_type;
+ typedef typename common_base::size_type size_type;
+
+ using common_base::inc;
+ using common_base::dec;
+ using common_base::m_cur_node;
+
+public:
+
+ typedef _NonConstItrBase iterator_base;
+
+ // iterator traits
+ typedef typename common_base::node value_type;
+ typedef value_type* pointer;
+ typedef value_type& reference;
+ typedef ptrdiff_t difference_type;
+ typedef std::bidirectional_iterator_tag iterator_category;
+
+public:
+ const_iterator_base() : common_base() {}
+ const_iterator_base(
+ const base_iterator_type& pos, const base_iterator_type& end,
+ size_type start_pos, size_type block_index) :
+ common_base(pos, end, start_pos, block_index) {}
+
+ const_iterator_base(const const_iterator_base& other) :
+ common_base(other) {}
+
+ /**
+ * Take the non-const iterator counterpart to create a const iterator.
+ */
+ const_iterator_base(const iterator_base& other) :
+ common_base(other.get_pos(), other.get_end(), 0, 0) {}
+
+ const value_type& operator*() const
+ {
+ return m_cur_node;
+ }
+
+ const value_type* operator->() const
+ {
+ return &m_cur_node;
+ }
+
+ const value_type* operator++()
+ {
+ return inc();
+ }
+
+ const value_type* operator--()
+ {
+ return dec();
+ }
};
}}
diff --git a/include/mdds/multi_type_vector_types.hpp b/include/mdds/multi_type_vector_types.hpp
index f72b641..5680233 100644
--- a/include/mdds/multi_type_vector_types.hpp
+++ b/include/mdds/multi_type_vector_types.hpp
@@ -94,6 +94,8 @@ protected:
element_block(size_t n, const _Data& val) : base_element_block(_TypeId), m_array(n, val) {}
public:
+ typedef typename store_type::iterator iterator;
+ typedef typename store_type::reverse_iterator reverse_iterator;
typedef typename store_type::const_iterator const_iterator;
typedef typename store_type::const_reverse_iterator const_reverse_iterator;
typedef _Data value_type;
@@ -108,6 +110,16 @@ public:
return !operator==(r);
}
+ static iterator begin(base_element_block& block)
+ {
+ return get(block).m_array.begin();
+ }
+
+ static iterator end(base_element_block& block)
+ {
+ return get(block).m_array.end();
+ }
+
static const_iterator begin(const base_element_block& block)
{
return get(block).m_array.begin();
@@ -118,6 +130,16 @@ public:
return get(block).m_array.end();
}
+ static reverse_iterator rbegin(base_element_block& block)
+ {
+ return get(block).m_array.rbegin();
+ }
+
+ static reverse_iterator rend(base_element_block& block)
+ {
+ return get(block).m_array.rend();
+ }
+
static const_reverse_iterator rbegin(const base_element_block& block)
{
return get(block).m_array.rbegin();
@@ -321,7 +343,8 @@ inline element_t get_block_type(const base_element_block& blk)
}
/**
- * Template for default, unmanaged element block for use in grid_map.
+ * Template for default, unmanaged element block for use in
+ * multi_type_vector.
*/
template<element_t _TypeId, typename _Data>
struct default_element_block : public copyable_element_block<default_element_block<_TypeId,_Data>, _TypeId, _Data>
diff --git a/include/mdds/rectangle_set_def.inl b/include/mdds/rectangle_set_def.inl
index 3aae012..bd0cb7f 100644
--- a/include/mdds/rectangle_set_def.inl
+++ b/include/mdds/rectangle_set_def.inl
@@ -1,7 +1,7 @@
/*************************************************************************
*
- * Copyright (c) 2011 Kohei Yoshida
- *
+ * Copyright (c) 2011-2012 Kohei Yoshida
+ *
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
@@ -10,10 +10,10 @@
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
- *
+ *
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -25,6 +25,8 @@
*
************************************************************************/
+#include <sstream>
+
namespace mdds {
template<typename _Key, typename _Data>
@@ -80,7 +82,11 @@ template<typename _Key, typename _Data>
bool rectangle_set<_Key,_Data>::insert(key_type x1, key_type y1, key_type x2, key_type y2, data_type* data)
{
if (x1 >= x2 || y1 >= y2)
- throw invalid_arg_error("specified range coordinates are invalid.");
+ {
+ std::ostringstream os;
+ os << "specified range coordinates are invalid (x1=" << x1 << ",y1=" << y1 << ",x2=" << x2 << ",y2=" << y2 << ')';
+ throw invalid_arg_error(os.str());
+ }
// Make sure this is not a duplicate.
if (m_dataset.find(data) != m_dataset.end())
@@ -91,7 +97,7 @@ bool rectangle_set<_Key,_Data>::insert(key_type x1, key_type y1, key_type x2, ke
typename inner_segment_map_type::iterator itr = m_inner_map.find(outer_interval);
if (itr == m_inner_map.end())
{
- // this interval has not yet been stored. Create a new inner segment
+ // this interval has not yet been stored. Create a new inner segment
// tree instance for this interval.
::std::pair<typename inner_segment_map_type::iterator, bool> r =
m_inner_map.insert(outer_interval, new inner_type);
@@ -100,7 +106,7 @@ bool rectangle_set<_Key,_Data>::insert(key_type x1, key_type y1, key_type x2, ke
itr = r.first;
- // Register the pointer to this inner segment tree instance with the
+ // Register the pointer to this inner segment tree instance with the
// outer segment tree.
if (!m_outer_segments.insert(x1, x2, itr->second))
// This should never fail if my logic is correct.
@@ -216,7 +222,7 @@ bool rectangle_set<_Key,_Data>::empty() const
template<typename _Key, typename _Data>
void rectangle_set<_Key,_Data>::build_outer_segment_tree()
{
- // Re-construct the outer segment tree from the authoritative inner tree
+ // Re-construct the outer segment tree from the authoritative inner tree
// map.
typename inner_segment_map_type::iterator itr = m_inner_map.begin(), itr_end = m_inner_map.end();
for (; itr != itr_end; ++itr)
@@ -244,7 +250,7 @@ void rectangle_set<_Key,_Data>::dump_rectangles() const
{
const rectangle& rect = itr->second;
cout << itr->first->name << ": (x1,y1,x2,y2) = "
- << "(" << rect.x1 << "," << rect.y1 << "," << rect.x2 << "," << rect.y2 << ")"
+ << "(" << rect.x1 << "," << rect.y1 << "," << rect.x2 << "," << rect.y2 << ")"
<< endl;
}
}
diff --git a/src/flat_segment_tree_test.cpp b/src/flat_segment_tree_test.cpp
index 5dd0504..aec838d 100644
--- a/src/flat_segment_tree_test.cpp
+++ b/src/flat_segment_tree_test.cpp
@@ -1083,12 +1083,6 @@ void fst_test_const_iterator()
}
}
-void fst_test_reverse_iterator()
-{
- stack_printer __stack_printer__("::fst_test_reverse_iterator");
-
-}
-
template<typename key_type, typename value_type>
void fst_test_insert_front_back(key_type start_key, key_type end_key, value_type default_value)
{
diff --git a/src/multi_type_matrix_test.cpp b/src/multi_type_matrix_test.cpp
index 1f51816..7784dda 100644
--- a/src/multi_type_matrix_test.cpp
+++ b/src/multi_type_matrix_test.cpp
@@ -604,7 +604,7 @@ void mtm_test_assignment()
assert(mx_orig == mx_copied);
mx_copied = mx_copied; // self assignment.
- assert(mx_copied == mx_copied);
+ assert(mx_orig == mx_copied);
mx_orig.set(2, 3, true);
mx_orig.set(1, 1, string("foo"));
diff --git a/src/multi_type_vector_test_custom.cpp b/src/multi_type_vector_test_custom.cpp
index f9fda19..dd0bb18 100644
--- a/src/multi_type_vector_test_custom.cpp
+++ b/src/multi_type_vector_test_custom.cpp
@@ -27,6 +27,7 @@
#include "test_global.hpp"
+#define MDDS_MULTI_TYPE_VECTOR_DEBUG 1
#include <mdds/multi_type_vector.hpp>
#include <mdds/multi_type_vector_trait.hpp>
@@ -317,7 +318,7 @@ bool test_cell_insertion(_ColT& col_db, size_t row, _ValT val)
return val == test;
}
-typedef mdds::multi_type_vector<my_cell_block_func> column_type;
+typedef mdds::multi_type_vector<my_cell_block_func> mtv_type;
void mtv_test_types()
{
@@ -326,20 +327,20 @@ void mtv_test_types()
mdds::mtv::element_t ct;
// Basic types
- ct = column_type::get_element_type(double(12.3));
+ ct = mtv_type::get_element_type(double(12.3));
assert(ct == mtv::element_type_numeric);
- ct = column_type::get_element_type(string());
+ ct = mtv_type::get_element_type(string());
assert(ct == mtv::element_type_string);
- ct = column_type::get_element_type(static_cast<unsigned long>(12));
+ ct = mtv_type::get_element_type(static_cast<unsigned long>(12));
assert(ct == mtv::element_type_ulong);
- ct = column_type::get_element_type(true);
+ ct = mtv_type::get_element_type(true);
assert(ct == mtv::element_type_boolean);
- ct = column_type::get_element_type(false);
+ ct = mtv_type::get_element_type(false);
assert(ct == mtv::element_type_boolean);
// Custom cell type
user_cell* p = NULL;
- ct = column_type::get_element_type(p);
+ ct = mtv_type::get_element_type(p);
assert(ct == element_type_user_block && ct >= mtv::element_type_user_start);
}
@@ -354,7 +355,7 @@ void mtv_test_basic()
{
// set_cell()
- column_type db(4);
+ mtv_type db(4);
user_cell* p = pool.construct(1.2);
db.set(0, p);
db.set(1, p);
@@ -373,7 +374,7 @@ void mtv_test_basic()
{
// set_cells(), resize(), insert_cells().
- column_type db(3);
+ mtv_type db(3);
user_cell* p1 = pool.construct(1.1);
user_cell* p2 = pool.construct(2.2);
user_cell* p3 = pool.construct(3.3);
@@ -467,7 +468,7 @@ void mtv_test_basic()
{
// set_cells() to overwrite existing values of type user_cell*.
- column_type db(2);
+ mtv_type db(2);
user_cell* p0 = pool.construct(1.2);
db.set(1, p0);
db.set(0, p0);
@@ -480,7 +481,7 @@ void mtv_test_basic()
}
{
- column_type db(4);
+ mtv_type db(4);
user_cell* p0 = pool.construct(1.1);
db.set(3, p0);
@@ -498,7 +499,7 @@ void mtv_test_basic()
{
// Get empty value.
- column_type db(1);
+ mtv_type db(1);
user_cell* p = db.get<user_cell*>(0);
assert(p == NULL);
}
@@ -510,8 +511,8 @@ void mtv_test_equality()
user_cell_pool pool;
- column_type db1(3);
- column_type db2 = db1;
+ mtv_type db1(3);
+ mtv_type db2 = db1;
assert(db2 == db1);
user_cell* p0 = pool.construct(1.1);
db1.set(0, p0);
@@ -537,7 +538,7 @@ void mtv_test_managed_block()
{
stack_printer __stack_printer__("::mtv_test_managed_block");
{
- column_type db(1);
+ mtv_type db(1);
db.set(0, new muser_cell(1.0));
const muser_cell* p = db.get<muser_cell*>(0);
assert(p->value == 1.0);
@@ -548,7 +549,7 @@ void mtv_test_managed_block()
{
// Overwrite with empty cells.
- column_type db(3);
+ mtv_type db(3);
// Empty the upper part.
db.set(0, new muser_cell(1.0));
@@ -567,7 +568,7 @@ void mtv_test_managed_block()
{
// More overwrite with empty cells.
- column_type db(3);
+ mtv_type db(3);
db.set(0, new muser_cell(1.0));
db.set(1, new muser_cell(2.0));
db.set(2, 3.0);
@@ -585,7 +586,7 @@ void mtv_test_managed_block()
{
// Another case for set_empty().
- column_type db(5);
+ mtv_type db(5);
db.set(0, 1.2);
db.set(1, new muser_cell(2.0));
db.set(2, new muser_cell(3.0));
@@ -605,13 +606,13 @@ void mtv_test_managed_block()
{
// Test for cloning.
- column_type db(3);
+ mtv_type db(3);
db.set(0, new muser_cell(1.0));
db.set(1, new muser_cell(2.0));
db.set(2, new muser_cell(3.0));
// swap
- column_type db2;
+ mtv_type db2;
db2.swap(db);
assert(db.empty());
assert(db2.get<muser_cell*>(0)->value == 1.0);
@@ -624,14 +625,14 @@ void mtv_test_managed_block()
assert(db.get<muser_cell*>(2)->value == 3.0);
// copy constructor
- column_type db_copied(db);
+ mtv_type db_copied(db);
assert(db_copied.size() == 3);
assert(db_copied.get<muser_cell*>(0)->value == 1.0);
assert(db_copied.get<muser_cell*>(1)->value == 2.0);
assert(db_copied.get<muser_cell*>(2)->value == 3.0);
// Assignment.
- column_type db_assigned = db;
+ mtv_type db_assigned = db;
assert(db_assigned.size() == 3);
assert(db_assigned.get<muser_cell*>(0)->value == 1.0);
assert(db_assigned.get<muser_cell*>(1)->value == 2.0);
@@ -640,7 +641,7 @@ void mtv_test_managed_block()
{
// Resize and clear
- column_type db(3);
+ mtv_type db(3);
db.set(0, new muser_cell(1.0));
db.set(1, new muser_cell(2.0));
db.set(2, new muser_cell(3.0));
@@ -652,7 +653,7 @@ void mtv_test_managed_block()
{
// Overwrite with a cell of different type.
- column_type db(3);
+ mtv_type db(3);
db.set(0, new muser_cell(1.0));
db.set(1, new muser_cell(2.0));
db.set(2, new muser_cell(3.0));
@@ -661,7 +662,7 @@ void mtv_test_managed_block()
{
// Erase (single block)
- column_type db(3);
+ mtv_type db(3);
// Erase the whole thing.
db.set(0, new muser_cell(1.0));
@@ -695,7 +696,7 @@ void mtv_test_managed_block()
{
// Erase (single block with preceding block)
- column_type db(4);
+ mtv_type db(4);
// Erase the whole thing.
db.set(0, 1.1);
@@ -730,7 +731,7 @@ void mtv_test_managed_block()
{
// Erase (multi-block 1)
- column_type db(6);
+ mtv_type db(6);
db.set(0, new muser_cell(1.0));
db.set(1, new muser_cell(2.0));
db.set(2, new muser_cell(3.0));
@@ -742,7 +743,7 @@ void mtv_test_managed_block()
{
// Erase (multi-block 2)
- column_type db(6);
+ mtv_type db(6);
db.set(0, 4.1);
db.set(1, 4.2);
db.set(2, 4.3);
@@ -754,7 +755,7 @@ void mtv_test_managed_block()
{
// Erase (multi-block 3)
- column_type db(6);
+ mtv_type db(6);
db.set(0, 1.0);
db.set(1, 2.0);
db.set(2, new muser_cell(3.0));
@@ -767,7 +768,7 @@ void mtv_test_managed_block()
{
// Insert into the middle of block. This one shouldn't overwrite any
// cells, but just to be safe...
- column_type db(2);
+ mtv_type db(2);
db.set(0, new muser_cell(1.0));
db.set(1, new muser_cell(2.0));
db.insert_empty(1, 2);
@@ -778,7 +779,7 @@ void mtv_test_managed_block()
{
// set_cells (simple overwrite)
- column_type db(2);
+ mtv_type db(2);
db.set(0, new muser_cell(1.0));
db.set(1, new muser_cell(2.0));
@@ -792,7 +793,7 @@ void mtv_test_managed_block()
{
// set_cells (overwrite upper)
- column_type db(2);
+ mtv_type db(2);
db.set(0, new muser_cell(1.0));
db.set(1, new muser_cell(2.0));
double vals[] = { 3.0 };
@@ -804,7 +805,7 @@ void mtv_test_managed_block()
{
// set_cells (overwrite lower)
- column_type db(2);
+ mtv_type db(2);
db.set(0, new muser_cell(1.0));
db.set(1, new muser_cell(2.0));
double vals[] = { 3.0 };
@@ -816,7 +817,7 @@ void mtv_test_managed_block()
{
// set_cells (overwrite middle)
- column_type db(4);
+ mtv_type db(4);
db.set(0, 1.1);
db.set(1, new muser_cell(1.0));
db.set(2, new muser_cell(2.0));
@@ -831,7 +832,7 @@ void mtv_test_managed_block()
{
// insert_empty() to split the block into two.
- column_type db(3);
+ mtv_type db(3);
db.set(0, 1.1);
db.set(1, new muser_cell(1.0));
db.set(2, new muser_cell(2.0));
@@ -843,7 +844,7 @@ void mtv_test_managed_block()
{
// erase() to merge two blocks.
- column_type db(4);
+ mtv_type db(4);
db.set(0, 1.1);
db.set(1, new muser_cell(1.0));
db.set(2, static_cast<unsigned long>(2));
@@ -861,7 +862,7 @@ void mtv_test_managed_block()
{
// set_cells() across multiple blocks.
- column_type db(5);
+ mtv_type db(5);
db.set(0, new muser_cell(1.0));
db.set(1, new muser_cell(2.0));
db.set(2, 1.2);
@@ -874,7 +875,7 @@ void mtv_test_managed_block()
{
// set_cells() across multiple blocks, part 2.
- column_type db(6);
+ mtv_type db(6);
db.set(0, static_cast<unsigned long>(12));
db.set(1, new muser_cell(1.0));
db.set(2, new muser_cell(2.0));
@@ -893,7 +894,7 @@ void mtv_test_managed_block()
{
// set_cell() to merge 3 blocks.
- column_type db(6);
+ mtv_type db(6);
db.set(0, static_cast<unsigned long>(12));
db.set(1, new muser_cell(1.0));
db.set(2, new muser_cell(2.0));
@@ -920,7 +921,7 @@ void mtv_test_managed_block()
{
// set_cell() to merge 2 blocks.
- column_type db(3);
+ mtv_type db(3);
db.set(0, static_cast<unsigned long>(23));
db.set(1, new muser_cell(2.1));
db.set(2, new muser_cell(3.1));
@@ -934,7 +935,7 @@ void mtv_test_managed_block()
{
// insert_cells() to split block into two.
- column_type db(2);
+ mtv_type db(2);
db.set(0, new muser_cell(2.1));
db.set(1, new muser_cell(2.2));
double vals[] = { 3.1, 3.2 };
@@ -944,7 +945,7 @@ void mtv_test_managed_block()
{
// set_cells() - merge new data block with existing block below.
- column_type db(6);
+ mtv_type db(6);
db.set(0, string("foo"));
db.set(1, string("baa"));
db.set(2, 1.1);
@@ -971,7 +972,7 @@ void mtv_test_managed_block()
{
// set_cells() - merge new data block with existing block below, but
// it overwrites the upper cell.
- column_type db(6);
+ mtv_type db(6);
db.set(0, string("foo"));
db.set(1, string("baa"));
db.set(2, 1.1);
@@ -994,12 +995,51 @@ void mtv_test_managed_block()
}
{
- column_type db(3);
+ mtv_type db(3);
db.set(0, new muser_cell(1.0));
db.set(2, new muser_cell(1.0));
db.set(1, new muser_cell(1.0));
assert(db.block_size() == 1);
}
+
+ {
+ mtv_type db(10);
+ for (size_t i = 0; i < 10; ++i)
+ db.set(i, new muser_cell(1.1));
+
+ vector<double> doubles(3, 2.2);
+ db.set(3, doubles.begin(), doubles.end());
+ assert(db.block_size() == 3);
+
+ vector<muser_cell*> cells;
+ cells.push_back(new muser_cell(2.1));
+ cells.push_back(new muser_cell(2.2));
+ cells.push_back(new muser_cell(2.3));
+ db.set(3, cells.begin(), cells.end());
+ assert(db.block_size() == 1);
+ assert(db.get<muser_cell*>(0)->value == 1.1);
+ assert(db.get<muser_cell*>(1)->value == 1.1);
+ assert(db.get<muser_cell*>(2)->value == 1.1);
+ assert(db.get<muser_cell*>(3)->value == 2.1);
+ assert(db.get<muser_cell*>(4)->value == 2.2);
+ assert(db.get<muser_cell*>(5)->value == 2.3);
+ assert(db.get<muser_cell*>(6)->value == 1.1);
+ assert(db.get<muser_cell*>(7)->value == 1.1);
+ assert(db.get<muser_cell*>(8)->value == 1.1);
+ assert(db.get<muser_cell*>(9)->value == 1.1);
+ }
+
+ {
+ mtv_type db(3);
+ db.set(0, new muser_cell(1.0));
+ db.set(1, new muser_cell(2.0));
+ db.set(2, new muser_cell(3.0));
+ db.set_empty(1, 1);
+ assert(db.block_size() == 3);
+ assert(db.get<muser_cell*>(0)->value == 1.0);
+ assert(db.is_empty(1));
+ assert(db.get<muser_cell*>(2)->value == 3.0);
+ }
}
}
diff --git a/src/multi_type_vector_test_default.cpp b/src/multi_type_vector_test_default.cpp
index 6aae26b..3b75694 100644
--- a/src/multi_type_vector_test_default.cpp
+++ b/src/multi_type_vector_test_default.cpp
@@ -1,6 +1,6 @@
/*************************************************************************
*
- * Copyright (c) 2011-2012 Kohei Yoshida
+ * Copyright (c) 2011-2013 Kohei Yoshida
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -27,12 +27,14 @@
#include "test_global.hpp"
+#define MDDS_MULTI_TYPE_VECTOR_DEBUG 1
#include <mdds/multi_type_vector.hpp>
#include <mdds/multi_type_vector_trait.hpp>
#include <cassert>
#include <sstream>
#include <vector>
+#include <deque>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/noncopyable.hpp>
@@ -53,7 +55,7 @@ bool test_cell_insertion(_ColT& col_db, size_t row, _ValT val)
return val == test;
}
-typedef mdds::multi_type_vector<mdds::mtv::element_block_func> column_type;
+typedef mdds::multi_type_vector<mdds::mtv::element_block_func> mtv_type;
enum test_mtv_type {
_bool, _short, _ushort, _int, _uint, _long, _ulong, _double, _string
@@ -127,7 +129,7 @@ void mtv_test_construction()
stack_printer __stack_printer__("::mtv_test_construction");
{
// Create with initial value and size.
- column_type db(10, 1.0);
+ mtv_type db(10, 1.0);
assert(db.size() == 10);
assert(db.block_size() == 1);
assert(db.get<double>(0) == 1.0);
@@ -136,7 +138,7 @@ void mtv_test_construction()
{
// Create with initial value and size.
- column_type db(10, string("foo"));
+ mtv_type db(10, string("foo"));
assert(db.size() == 10);
assert(db.block_size() == 1);
assert(db.get<string>(0) == "foo");
@@ -151,7 +153,7 @@ void mtv_test_basic()
{
// Single column instance with only one row.
- column_type col_db(1);
+ mtv_type col_db(1);
double test = -999.0;
@@ -166,7 +168,7 @@ void mtv_test_basic()
{
// Insert first value into the top row.
- column_type col_db(2);
+ mtv_type col_db(2);
double test = -999.0;
// Test empty cell values.
@@ -188,7 +190,7 @@ void mtv_test_basic()
}
{
- column_type col_db(3);
+ mtv_type col_db(3);
res = test_cell_insertion(col_db, 0, 4.5);
assert(res);
res = test_cell_insertion(col_db, 1, 5.1);
@@ -199,7 +201,7 @@ void mtv_test_basic()
{
// Insert first value into the bottom row.
- column_type col_db(3);
+ mtv_type col_db(3);
res = test_cell_insertion(col_db, 2, 5.0); // Insert into the last row.
assert(res);
@@ -220,7 +222,7 @@ void mtv_test_basic()
{
// This time insert from bottom up one by one.
- column_type col_db(3);
+ mtv_type col_db(3);
res = test_cell_insertion(col_db, 2, 1.2);
assert(res);
res = test_cell_insertion(col_db, 1, 0.2);
@@ -230,7 +232,7 @@ void mtv_test_basic()
}
{
- column_type col_db(4);
+ mtv_type col_db(4);
long order[] = { 3, 1, 2, 0 };
double val = 1.0;
for (size_t i = 0; i < 4; ++i, ++val)
@@ -241,7 +243,7 @@ void mtv_test_basic()
}
{
- column_type col_db(4);
+ mtv_type col_db(4);
long order[] = { 0, 3, 1, 2 };
double val = 1.0;
for (size_t i = 0; i < 4; ++i, ++val)
@@ -252,7 +254,7 @@ void mtv_test_basic()
}
{
- column_type col_db(4);
+ mtv_type col_db(4);
long order[] = { 0, 2, 3, 1 };
double val = 1.0;
for (size_t i = 0; i < 4; ++i, ++val)
@@ -263,7 +265,7 @@ void mtv_test_basic()
}
{
- column_type col_db(5);
+ mtv_type col_db(5);
long order[] = { 0, 4, 3, 2, 1 };
double val = 1.0;
for (size_t i = 0; i < 5; ++i, ++val)
@@ -275,7 +277,7 @@ void mtv_test_basic()
{
// Insert first value into a middle row.
- column_type col_db(10);
+ mtv_type col_db(10);
res = test_cell_insertion(col_db, 5, 5.0);
assert(res);
string str = "test";
@@ -284,7 +286,7 @@ void mtv_test_basic()
}
{
- column_type col_db(3);
+ mtv_type col_db(3);
res = test_cell_insertion(col_db, 0, 5.0);
assert(res);
string str = "test";
@@ -295,7 +297,7 @@ void mtv_test_basic()
}
{
- column_type col_db(2);
+ mtv_type col_db(2);
res = test_cell_insertion(col_db, 0, 5.0);
assert(res);
string str = "test";
@@ -304,7 +306,7 @@ void mtv_test_basic()
}
{
- column_type col_db(3);
+ mtv_type col_db(3);
res = test_cell_insertion(col_db, 0, 5.0);
assert(res);
string str = "test";
@@ -316,7 +318,7 @@ void mtv_test_basic()
}
{
- column_type col_db(3);
+ mtv_type col_db(3);
res = test_cell_insertion(col_db, 0, 5.0);
assert(res);
res = test_cell_insertion(col_db, 2, 2.0);
@@ -327,7 +329,7 @@ void mtv_test_basic()
}
{
- column_type col_db(3);
+ mtv_type col_db(3);
res = test_cell_insertion(col_db, 0, 5.0);
assert(res);
string str = "foo";
@@ -339,7 +341,7 @@ void mtv_test_basic()
}
{
- column_type col_db(4);
+ mtv_type col_db(4);
res = test_cell_insertion(col_db, 0, 5.0);
assert(res);
string str = "foo";
@@ -383,7 +385,7 @@ void mtv_test_basic()
}
{
- column_type col_db(1);
+ mtv_type col_db(1);
res = test_cell_insertion(col_db, 0, 2.0);
assert(res);
string str = "foo";
@@ -394,7 +396,7 @@ void mtv_test_basic()
}
{
- column_type col_db(2);
+ mtv_type col_db(2);
res = test_cell_insertion(col_db, 0, 2.0);
assert(res);
string str = "foo";
@@ -413,7 +415,7 @@ void mtv_test_basic()
}
{
- column_type col_db(3);
+ mtv_type col_db(3);
string str = "alpha";
col_db.set(2, str);
res = test_cell_insertion(col_db, 2, 5.0);
@@ -441,7 +443,7 @@ void mtv_test_basic()
}
{
- column_type col_db(3);
+ mtv_type col_db(3);
res = test_cell_insertion(col_db, 1, 5.0);
assert(res);
string str = "alpha";
@@ -484,7 +486,7 @@ void mtv_test_basic()
}
{
- column_type col_db(4);
+ mtv_type col_db(4);
col_db.set(0, 1.0);
string str = "foo";
col_db.set(1, str);
@@ -499,7 +501,7 @@ void mtv_test_basic()
}
{
- column_type col_db(4);
+ mtv_type col_db(4);
col_db.set(0, 1.0);
string str = "foo";
col_db.set(1, str);
@@ -511,7 +513,7 @@ void mtv_test_basic()
}
{
- column_type col_db(4);
+ mtv_type col_db(4);
col_db.set(0, 1.0);
string str = "foo";
col_db.set(1, str);
@@ -530,7 +532,7 @@ void mtv_test_basic()
}
{
- column_type col_db(4);
+ mtv_type col_db(4);
col_db.set(0, 1.0);
col_db.set(1, 1.0);
col_db.set(2, 1.0);
@@ -541,7 +543,7 @@ void mtv_test_basic()
}
{
- column_type col_db(3);
+ mtv_type col_db(3);
col_db.set(0, 1.0);
col_db.set(1, 1.0);
string str = "foo";
@@ -551,7 +553,7 @@ void mtv_test_basic()
}
{
- column_type col_db(3);
+ mtv_type col_db(3);
col_db.set(1, 1.0);
string str = "foo";
col_db.set(2, str);
@@ -593,7 +595,7 @@ void mtv_test_basic()
}
{
- column_type col_db(3);
+ mtv_type col_db(3);
col_db.set(0, 1.0);
string str = "alpha";
col_db.set(1, str);
@@ -608,7 +610,7 @@ void mtv_test_basic()
}
{
- column_type col_db(3);
+ mtv_type col_db(3);
// Insert 3 cells of 3 different types.
res = test_cell_insertion(col_db, 0, true);
@@ -627,7 +629,7 @@ void mtv_test_basic()
{
// set_cell() to merge 3 blocks.
- column_type db(6);
+ mtv_type db(6);
db.set(0, static_cast<unsigned long>(12));
db.set(1, 1.0);
db.set(2, 2.0);
@@ -653,7 +655,7 @@ void mtv_test_basic()
}
{
- column_type db(25);
+ mtv_type db(25);
db.set(0, 1.2);
db.set(5, string("test"));
db.set(1, string("foo"));
@@ -666,7 +668,7 @@ void mtv_test_basic()
{
// Test various integer types.
- column_type db(7);
+ mtv_type db(7);
db.set(0, static_cast<long>(-10));
db.set(1, static_cast<unsigned long>(10));
db.set(2, static_cast<int>(-10));
@@ -683,13 +685,42 @@ void mtv_test_basic()
assert(db.get_type(5) == mtv::element_type_ushort);
assert(db.get_type(6) == mtv::element_type_boolean);
}
+
+ {
+ mtv_type db(10);
+ db.set(0, 1.1);
+ db.set(1, 1.2);
+ db.set(2, true);
+ db.set(3, false);
+ db.set(8, string("A"));
+ db.set(9, string("B"));
+ db.set(7, 2.1);
+ assert(db.block_size() == 5);
+ assert(db.get_type(7) == mtv::element_type_numeric);
+ assert(db.get<double>(7) == 2.1);
+ }
+
+ {
+ mtv_type db(8, true);
+ vector<double> vals(3, 1.2);
+ db.set(4, vals.begin(), vals.end());
+ db.set(3, 4.1);
+ assert(db.get<bool>(0) == true);
+ assert(db.get<bool>(1) == true);
+ assert(db.get<bool>(2) == true);
+ assert(db.get<double>(3) == 4.1);
+ assert(db.get<double>(4) == 1.2);
+ assert(db.get<double>(5) == 1.2);
+ assert(db.get<double>(6) == 1.2);
+ assert(db.get<bool>(7) == true);
+ }
}
void mtv_test_empty_cells()
{
stack_printer __stack_printer__("::mtv_test_empty");
{
- column_type db(3);
+ mtv_type db(3);
assert(db.is_empty(0));
assert(db.is_empty(2));
@@ -763,7 +794,7 @@ void mtv_test_empty_cells()
{
// Empty multiple cells at the middle part of a block.
- column_type db(4);
+ mtv_type db(4);
for (size_t i = 0; i < 4; ++i)
db.set(i, static_cast<double>(i+1));
@@ -787,7 +818,7 @@ void mtv_test_empty_cells()
{
// Empty multiple blocks.
- column_type db(2);
+ mtv_type db(2);
db.set(0, 1.0);
db.set(1, string("foo"));
assert(!db.is_empty(0));
@@ -800,7 +831,7 @@ void mtv_test_empty_cells()
{
// Empty multiple blocks, part 2 - from middle block to middle block.
- column_type db(6);
+ mtv_type db(6);
db.set(0, 1.0);
db.set(1, 2.0);
string str = "foo";
@@ -828,7 +859,7 @@ void mtv_test_empty_cells()
{
// Empty multiple blocks, part 3 - from top block to middle block.
- column_type db(6);
+ mtv_type db(6);
db.set(0, 1.0);
db.set(1, 2.0);
string str = "foo";
@@ -853,7 +884,7 @@ void mtv_test_empty_cells()
{
// Empty multiple blocks, part 4 - from middle block to bottom block.
- column_type db(6);
+ mtv_type db(6);
db.set(0, 1.0);
db.set(1, 2.0);
string str = "foo";
@@ -877,7 +908,7 @@ void mtv_test_empty_cells()
{
// Empty multiple blocks, part 5 - from middle empty block to middle non-empty block.
- column_type db(6);
+ mtv_type db(6);
db.set(2, 1.0);
db.set(3, 2.0);
string str = "foo";
@@ -907,7 +938,7 @@ void mtv_test_empty_cells()
{
// Empty multiple blocks, part 6 - from middle non-empty block to middle empty block.
- column_type db(6);
+ mtv_type db(6);
db.set(0, 1.0);
db.set(1, 2.0);
db.set(2, string("foo"));
@@ -934,7 +965,7 @@ void mtv_test_empty_cells()
{
// Empty multiple blocks, part 7 - from middle empty block to middle empty block.
- column_type db(6);
+ mtv_type db(6);
db.set(2, 1.0);
db.set(3, string("foo"));
assert(db.block_size() == 4);
@@ -959,7 +990,7 @@ void mtv_test_empty_cells()
{
// Set empty on 2nd block. Presence of first block causes an offset
// on index in the 2nd block.
- column_type db(5);
+ mtv_type db(5);
db.set(0, 1.0);
db.set(1, static_cast<unsigned long>(1));
db.set(2, static_cast<unsigned long>(2));
@@ -988,7 +1019,7 @@ void mtv_test_empty_cells()
{
// Set individual single elements empty.
cout << "Setting individual single elements empty..." << endl;
- column_type db(15, 1.2);
+ mtv_type db(15, 1.2);
cout << "setting 1 empty..." << endl;
db.set_empty(1, 1);
cout << "setting 4 empty..." << endl;
@@ -1015,12 +1046,22 @@ void mtv_test_empty_cells()
assert(!db.is_empty(13));
assert(!db.is_empty(14));
}
+
+ {
+ mtv_type db(3, true);
+ assert(db.block_size() == 1);
+ db.set_empty(1, 1);
+ assert(db.get<bool>(0) == true);
+ assert(db.is_empty(1));
+ assert(db.get<bool>(2) == true);
+ assert(db.block_size() == 3);
+ }
}
void mtv_test_swap()
{
stack_printer __stack_printer__("::mtv_test_swap");
- column_type db1(3), db2(5);
+ mtv_type db1(3), db2(5);
db1.set(0, 1.0);
db1.set(1, 2.0);
db1.set(2, 3.0);
@@ -1039,7 +1080,7 @@ void mtv_test_equality()
stack_printer __stack_printer__("::mtv_test_equality");
{
// Two columns of equal size.
- column_type db1(3), db2(3);
+ mtv_type db1(3), db2(3);
assert(db1 == db2);
db1.set(0, 1.0);
assert(db1 != db2);
@@ -1054,7 +1095,7 @@ void mtv_test_equality()
{
// Two columns of different sizes. They are always non-equal no
// matter what.
- column_type db1(3), db2(4);
+ mtv_type db1(3), db2(4);
assert(db1 != db2);
db1.set(0, 1.2);
db2.set(0, 1.2);
@@ -1069,14 +1110,14 @@ void mtv_test_equality()
void mtv_test_clone()
{
stack_printer __stack_printer__("::mtv_test_clone");
- column_type db1(3);
+ mtv_type db1(3);
db1.set(0, 3.4);
db1.set(1, string("foo"));
db1.set(2, true);
// copy construction
- column_type db2(db1);
+ mtv_type db2(db1);
assert(db1.size() == db2.size());
assert(db1.block_size() == db2.block_size());
assert(db1 == db2);
@@ -1103,12 +1144,12 @@ void mtv_test_clone()
// assignment
- column_type db3 = db1;
+ mtv_type db3 = db1;
assert(db3 == db1);
db3.set(0, string("alpha"));
assert(db3 != db1);
- column_type db4, db5;
+ mtv_type db4, db5;
db4 = db5 = db3;
assert(db4 == db5);
assert(db3 == db5);
@@ -1118,7 +1159,7 @@ void mtv_test_clone()
void mtv_test_resize()
{
stack_printer __stack_printer__("::mtv_test_resize");
- column_type db(0);
+ mtv_type db(0);
assert(db.size() == 0);
assert(db.empty());
@@ -1179,7 +1220,7 @@ void mtv_test_erase()
stack_printer __stack_printer__("::mtv_test_erase");
{
// Single empty block.
- column_type db(5);
+ mtv_type db(5);
db.erase(0, 2); // erase rows 0-2.
assert(db.size() == 2);
db.erase(0, 1);
@@ -1189,7 +1230,7 @@ void mtv_test_erase()
{
// Single non-empty block.
- column_type db(5);
+ mtv_type db(5);
for (long i = 0; i < 5; ++i)
db.set(i, static_cast<double>(i+1));
@@ -1211,7 +1252,7 @@ void mtv_test_erase()
{
// Two blocks - non-empty to empty blocks.
- column_type db(8);
+ mtv_type db(8);
for (long i = 0; i < 4; ++i)
db.set(i, static_cast<double>(i+1));
@@ -1240,7 +1281,7 @@ void mtv_test_erase()
{
// Two blocks - non-empty to non-empty blocks.
- column_type db(8);
+ mtv_type db(8);
for (long i = 0; i < 4; ++i)
db.set(i, static_cast<double>(i+1));
@@ -1273,7 +1314,7 @@ void mtv_test_erase()
{
// 3 blocks, all non-empty.
- column_type db(9);
+ mtv_type db(9);
for (long i = 0; i < 3; ++i)
db.set(i, static_cast<double>(i+1));
@@ -1316,7 +1357,7 @@ void mtv_test_erase()
{
// erase() to merge two blocks.
- column_type db(4);
+ mtv_type db(4);
db.set(0, 1.1);
db.set(1, string("foo"));
db.set(2, static_cast<unsigned long>(2));
@@ -1350,7 +1391,7 @@ void mtv_test_insert_empty()
{
stack_printer __stack_printer__("::mtv_test_insert_empty");
{
- column_type db(5);
+ mtv_type db(5);
db.insert_empty(0, 5);
assert(db.size() == 10);
assert(db.block_size() == 1);
@@ -1381,7 +1422,7 @@ void mtv_test_insert_empty()
}
{
- column_type db(5);
+ mtv_type db(5);
for (long i = 0; i < 5; ++i)
db.set(i, static_cast<double>(i+1));
@@ -1411,7 +1452,7 @@ void mtv_test_insert_empty()
}
{
- column_type db(1);
+ mtv_type db(1);
db.set(0, 2.5);
db.insert_empty(0, 2);
assert(db.block_size() == 2);
@@ -1425,7 +1466,7 @@ void mtv_test_insert_empty()
}
{
- column_type db(2);
+ mtv_type db(2);
db.set(0, 1.2);
db.set(1, 2.3);
db.insert_empty(1, 1);
@@ -1444,7 +1485,7 @@ void mtv_test_set_cells()
{
stack_printer __stack_printer__("::mtv_test_set_cells");
{
- column_type db(5);
+ mtv_type db(5);
// Replace the whole block.
@@ -1581,7 +1622,7 @@ void mtv_test_set_cells()
}
{
- column_type db(5);
+ mtv_type db(5);
for (size_t i = 0; i < 5; ++i)
db.set(i, static_cast<double>(i+1));
@@ -1625,7 +1666,7 @@ void mtv_test_set_cells()
}
{
- column_type db(6);
+ mtv_type db(6);
double vals_d[] = { 1.0, 1.1, 1.2, 1.3, 1.4, 1.5 };
unsigned long vals_i[] = { 12, 13, 14, 15 };
string vals_s[] = { "a", "b" };
@@ -1675,7 +1716,7 @@ void mtv_test_set_cells()
}
{
- column_type db(3);
+ mtv_type db(3);
{
double vals[] = { 2.1, 2.2, 2.3 };
double* p = &vals[0];
@@ -1704,7 +1745,7 @@ void mtv_test_set_cells()
{
// Set cells over multiple blocks. Very simple case.
- column_type db(2);
+ mtv_type db(2);
db.set(0, static_cast<double>(1.1));
db.set(1, string("foo"));
assert(db.block_size() == 2);
@@ -1726,7 +1767,7 @@ void mtv_test_set_cells()
{
// Same as above, except that the last block is only partially replaced.
- column_type db(3);
+ mtv_type db(3);
db.set(0, static_cast<double>(1.1));
db.set(1, string("foo"));
db.set(2, string("baa"));
@@ -1750,7 +1791,7 @@ void mtv_test_set_cells()
}
{
- column_type db(3);
+ mtv_type db(3);
db.set(0, static_cast<double>(3.1));
db.set(1, static_cast<double>(3.2));
db.set(2, string("foo"));
@@ -1772,7 +1813,7 @@ void mtv_test_set_cells()
}
{
- column_type db(5);
+ mtv_type db(5);
db.set(0, 1.1);
db.set(1, 1.2);
db.set(2, string("foo"));
@@ -1794,7 +1835,7 @@ void mtv_test_set_cells()
}
{
- column_type db(4);
+ mtv_type db(4);
db.set(0, string("A"));
db.set(1, string("B"));
db.set(2, 1.1);
@@ -1812,7 +1853,7 @@ void mtv_test_set_cells()
}
{
- column_type db(4);
+ mtv_type db(4);
db.set(0, string("A"));
db.set(1, string("B"));
db.set(2, 1.1);
@@ -1830,7 +1871,7 @@ void mtv_test_set_cells()
}
{
- column_type db(5);
+ mtv_type db(5);
db.set(0, string("A"));
db.set(1, string("B"));
db.set(2, 1.1);
@@ -1850,7 +1891,7 @@ void mtv_test_set_cells()
}
{
- column_type db(3);
+ mtv_type db(3);
db.set(0, string("A"));
db.set(1, 1.1);
db.set(2, 1.2);
@@ -1866,7 +1907,7 @@ void mtv_test_set_cells()
}
{
- column_type db(4);
+ mtv_type db(4);
db.set(0, static_cast<unsigned long>(35));
db.set(1, string("A"));
db.set(2, 1.1);
@@ -1886,7 +1927,7 @@ void mtv_test_set_cells()
{
// Block 1 is empty.
- column_type db(2);
+ mtv_type db(2);
db.set(1, 1.2);
assert(db.block_size() == 2);
@@ -1899,7 +1940,7 @@ void mtv_test_set_cells()
}
{
- column_type db(3);
+ mtv_type db(3);
db.set(0, 1.1);
db.set(2, 1.2);
assert(db.block_size() == 3);
@@ -1914,7 +1955,7 @@ void mtv_test_set_cells()
}
{
- column_type db(5);
+ mtv_type db(5);
db.set(2, string("A"));
db.set(3, string("B"));
db.set(4, string("C"));
@@ -1931,6 +1972,59 @@ void mtv_test_set_cells()
assert(db.get<double>(3) == 1.3);
assert(db.get<string>(4) == string("C"));
}
+
+ {
+ mtv_type db(10, true);
+ vector<bool> bools(3, false);
+ db.set(3, 1.1);
+ db.set(4, 1.2);
+ db.set(5, 1.3);
+ assert(db.block_size() == 3);
+
+ // This should replace the middle numeric block and merge with the top
+ // and bottom ones.
+ db.set(3, bools.begin(), bools.end());
+ assert(db.block_size() == 1);
+ assert(db.size() == 10);
+ assert(db.get<bool>(0) == true);
+ assert(db.get<bool>(1) == true);
+ assert(db.get<bool>(2) == true);
+ assert(db.get<bool>(3) == false);
+ assert(db.get<bool>(4) == false);
+ assert(db.get<bool>(5) == false);
+ assert(db.get<bool>(6) == true);
+ assert(db.get<bool>(7) == true);
+ assert(db.get<bool>(8) == true);
+ assert(db.get<bool>(9) == true);
+ }
+
+ {
+ mtv_type db(9);
+ db.set(0, 1.1);
+ db.set(1, 1.2);
+ db.set(2, true);
+ db.set(3, false);
+ db.set(4, true);
+ db.set(5, string("a"));
+ db.set(6, string("b"));
+ db.set(7, string("c"));
+ db.set(8, string("d"));
+ assert(db.block_size() == 3);
+
+ vector<string> strings(3, string("foo"));
+ db.set(2, strings.begin(), strings.end()); // Merge with the next block.
+ assert(db.block_size() == 2);
+ assert(db.size() == 9);
+ assert(db.get<double>(0) == 1.1);
+ assert(db.get<double>(1) == 1.2);
+ assert(db.get<string>(2) == "foo");
+ assert(db.get<string>(3) == "foo");
+ assert(db.get<string>(4) == "foo");
+ assert(db.get<string>(5) == "a");
+ assert(db.get<string>(6) == "b");
+ assert(db.get<string>(7) == "c");
+ assert(db.get<string>(8) == "d");
+ }
}
void mtv_test_insert_cells()
@@ -1938,7 +2032,7 @@ void mtv_test_insert_cells()
stack_printer __stack_printer__("::mtv_test_insert_cells");
{
// Insert into non-empty block of the same type.
- column_type db(1);
+ mtv_type db(1);
db.set(0, 1.1);
assert(db.block_size() == 1);
assert(db.size() == 1);
@@ -1956,7 +2050,7 @@ void mtv_test_insert_cells()
{
// Insert into an existing empty block.
- column_type db(1);
+ mtv_type db(1);
assert(db.block_size() == 1);
assert(db.size() == 1);
@@ -1972,7 +2066,7 @@ void mtv_test_insert_cells()
}
{
- column_type db(2);
+ mtv_type db(2);
db.set(0, 1.1);
assert(db.block_size() == 2);
assert(db.size() == 2);
@@ -1990,7 +2084,7 @@ void mtv_test_insert_cells()
}
{
- column_type db(2);
+ mtv_type db(2);
db.set(0, static_cast<unsigned long>(23));
assert(db.block_size() == 2);
assert(db.size() == 2);
@@ -2008,7 +2102,7 @@ void mtv_test_insert_cells()
}
{
- column_type db(2);
+ mtv_type db(2);
double vals[] = { 2.1, 2.2, 2.3 };
double* p = &vals[0];
db.insert(1, p, p+3);
@@ -2022,7 +2116,7 @@ void mtv_test_insert_cells()
}
{
- column_type db(2);
+ mtv_type db(2);
db.set(0, 1.1);
db.set(1, static_cast<unsigned long>(23));
assert(db.block_size() == 2);
@@ -2041,7 +2135,7 @@ void mtv_test_insert_cells()
}
{
- column_type db(2);
+ mtv_type db(2);
db.set(0, true);
db.set(1, static_cast<unsigned long>(23));
assert(db.block_size() == 2);
@@ -2060,7 +2154,7 @@ void mtv_test_insert_cells()
}
{
- column_type db(2);
+ mtv_type db(2);
db.set(0, static_cast<unsigned long>(12));
db.set(1, static_cast<unsigned long>(23));
assert(db.block_size() == 1);
@@ -2079,7 +2173,7 @@ void mtv_test_insert_cells()
}
{
- column_type db(3);
+ mtv_type db(3);
db.set(0, 1.0);
db.set(1, string("foo"));
db.set(2, string("baa"));
@@ -2093,7 +2187,7 @@ void mtv_test_insert_cells()
}
{
- column_type db(2);
+ mtv_type db(2);
db.set(0, static_cast<unsigned long>(11));
db.set(1, static_cast<unsigned long>(12));
double vals[] = { 1.2 };
@@ -2117,16 +2211,16 @@ void mtv_test_iterators()
{
stack_printer __stack_printer__("::mtv_test_iterators");
{
- column_type db(5);
- column_type::const_iterator it;
+ mtv_type db(5);
+ mtv_type::const_iterator it;
it = db.begin();
- column_type::const_iterator it_end = db.end();
+ mtv_type::const_iterator it_end = db.end();
size_t len = std::distance(it, it_end);
assert(len == 1);
assert(it != it_end);
assert(it->type == mtv::element_type_empty);
assert(it->size == 5);
- const column_type::const_iterator::value_type& val = *it;
+ const mtv_type::const_iterator::value_type& val = *it;
assert(val.type == it->type);
assert(val.size == it->size);
@@ -2135,7 +2229,7 @@ void mtv_test_iterators()
}
{
- column_type db(6);
+ mtv_type db(6);
db.set(0, 1.1);
db.set(1, 2.2);
db.set(4, string("boo"));
@@ -2143,7 +2237,7 @@ void mtv_test_iterators()
assert(db.block_size() == 3);
{
// Forward iterator
- column_type::const_iterator it = db.begin(), it_end = db.end();
+ mtv_type::const_iterator it = db.begin(), it_end = db.end();
size_t len = std::distance(it, it_end);
assert(len == 3);
assert(it != it_end);
@@ -2166,7 +2260,7 @@ void mtv_test_iterators()
{
// Reverse iterator
- column_type::const_reverse_iterator it = db.rbegin(), it_end = db.rend();
+ mtv_type::const_reverse_iterator it = db.rbegin(), it_end = db.rend();
size_t len = std::distance(it, it_end);
assert(len == 3);
assert(it != it_end);
@@ -2193,7 +2287,7 @@ void mtv_test_data_iterators()
{
stack_printer __stack_printer__("::mtv_test_data_iterators");
- column_type db(10);
+ mtv_type db(10);
db.set(0, 1.1);
db.set(1, 1.2);
db.set(2, 1.3);
@@ -2201,7 +2295,7 @@ void mtv_test_data_iterators()
db.set(5, string("B"));
db.set(6, string("C"));
db.set(7, string("D"));
- column_type::const_iterator it_blk = db.begin(), it_blk_end = db.end();
+ mtv_type::const_iterator it_blk = db.begin(), it_blk_end = db.end();
// First block is a numeric block.
assert(it_blk != it_blk_end);
@@ -2257,6 +2351,1514 @@ void mtv_test_data_iterators()
assert(it_blk == it_blk_end);
}
+/**
+ * This function is just to ensure that even the non-const iterator can be
+ * dereferenced via const reference.
+ *
+ * @param it this is passed as a const reference, yet it should still allow
+ * being dereferenced as long as no data is modified.
+ */
+void check_block_iterator(const mtv_type::iterator& it, mtv::element_t expected)
+{
+ mtv::element_t actual = it->type;
+ const mtv_type::element_block_type* data = (*it).data;
+ assert(actual == expected);
+ assert(data != NULL);
+}
+
+void mtv_test_non_const_data_iterators()
+{
+ stack_printer __stack_printer__("::mtv_test_non_const_data_iterators");
+
+ mtv_type db(1);
+ db.set(0, 1.2);
+ mtv_type::iterator it_blk = db.begin(), it_blk_end = db.end();
+ size_t n = std::distance(it_blk, it_blk_end);
+ assert(n == 1);
+ check_block_iterator(it_blk, mtv::element_type_numeric);
+
+ mtv::numeric_element_block::iterator it = mtv::numeric_element_block::begin(*it_blk->data);
+ mtv::numeric_element_block::iterator it_end = mtv::numeric_element_block::end(*it_blk->data);
+ n = std::distance(it, it_end);
+ assert(n == 1);
+ assert(*it == 1.2);
+
+ *it = 2.3; // write via iterator.
+ assert(db.get<double>(0) == 2.3);
+
+ db.resize(3);
+ db.set(1, 2.4);
+ db.set(2, 2.5);
+
+ it_blk = db.begin();
+ it_blk_end = db.end();
+ n = std::distance(it_blk, it_blk_end);
+ assert(n == 1);
+ check_block_iterator(it_blk, mtv::element_type_numeric);
+
+ it = mtv::numeric_element_block::begin(*it_blk->data);
+ it_end = mtv::numeric_element_block::end(*it_blk->data);
+ n = std::distance(it, it_end);
+ assert(n == 3);
+ *it = 3.1;
+ ++it;
+ *it = 3.2;
+ ++it;
+ *it = 3.3;
+
+ assert(db.get<double>(0) == 3.1);
+ assert(db.get<double>(1) == 3.2);
+ assert(db.get<double>(2) == 3.3);
+}
+
+void mtv_test_iterator_private_data()
+{
+ stack_printer __stack_printer__("::mtv_test_iterator_private_data");
+
+ // What the end position iterator stores in the private data area is
+ // intentionally undefined.
+
+ mtv_type db(9);
+
+ // With only a single block
+
+ mtv_type::iterator it = db.begin();
+ assert(it->__private_data.start_pos == 0);
+ assert(it->__private_data.block_index == 0);
+
+ it = db.end();
+ --it;
+ assert(it->__private_data.start_pos == 0);
+ assert(it->__private_data.block_index == 0);
+
+ // With 3 blocks (sizes of 4, 3, and 2 in this order)
+
+ db.set(4, 1.1);
+ db.set(5, 1.1);
+ db.set(6, 1.1);
+
+ it = db.begin();
+ assert(it->size == 4);
+ assert(it->__private_data.start_pos == 0);
+ assert(it->__private_data.block_index == 0);
+ ++it;
+ assert(it->size == 3);
+ assert(it->__private_data.start_pos == 4);
+ assert(it->__private_data.block_index == 1);
+ ++it;
+ assert(it->size == 2);
+ assert(it->__private_data.start_pos == 7);
+ assert(it->__private_data.block_index == 2);
+
+ ++it;
+ assert(it == db.end()); // end position reached.
+
+ // Go in reverse direction.
+ --it;
+ assert(it->size == 2);
+ assert(it->__private_data.start_pos == 7);
+ assert(it->__private_data.block_index == 2);
+ --it;
+ assert(it->size == 3);
+ assert(it->__private_data.start_pos == 4);
+ assert(it->__private_data.block_index == 1);
+ --it;
+ assert(it->size == 4);
+ assert(it->__private_data.start_pos == 0);
+ assert(it->__private_data.block_index == 0);
+ assert(it == db.begin());
+}
+
+void mtv_test_set_return_iterator()
+{
+ stack_printer __stack_printer__("::mtv_test_set_return_iterator");
+
+ // single element only
+ mtv_type db(1);
+ mtv_type::iterator it = db.set(0, 1.1);
+ assert(it == db.begin());
+
+ // Set value to the top of the only block.
+ db.clear();
+ db.resize(3);
+ it = db.set(0, 1.2);
+ assert(it == db.begin());
+
+ // Set value to the bottom of the only block.
+ db.clear();
+ db.resize(3);
+ it = db.set(2, 1.3);
+ mtv_type::iterator check = db.begin();
+ ++check;
+ assert(it == check);
+ check = db.end();
+ --check;
+ assert(it == check);
+
+ // Set value to the middle of the only block.
+ db.clear();
+ db.resize(3);
+ it = db.set(1, 1.4);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ check = db.end();
+ std::advance(check, -2);
+ assert(it == check);
+ assert(it->__private_data.start_pos == 1);
+ assert(it->__private_data.block_index == 1);
+
+ // Set value to the top empty block of size 1 followed by a non-empty block.
+ db.clear();
+ db.resize(2);
+ db.set(1, 2.1);
+ it = db.set(0, 2.2); // same type as that of the following block.
+ assert(it == db.begin());
+ assert(it->size == 2);
+ assert(it->__private_data.start_pos == 0);
+ assert(it->__private_data.block_index == 0);
+ db.set_empty(0, 0);
+ it = db.set(0, true); // different type from that of the following block.
+ assert(it == db.begin());
+ assert(it->size == 1);
+ assert(it->__private_data.start_pos == 0);
+ assert(it->__private_data.block_index == 0);
+
+ // Set value to the top of the top empty block (not size 1) followed by a non-empty block.
+ db.clear();
+ db.resize(3);
+ db.set(2, true);
+ it = db.set(0, 5.1);
+ assert(it == db.begin());
+
+ // Set value to the bottom of the top empty block (not size 1) followed by a non-empty block.
+ db.clear();
+ db.resize(3);
+ db.set(2, 6.1);
+ it = db.set(1, 6.2); // same type as that of the following block.
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ check = db.end();
+ --check;
+ assert(it == check);
+ assert(it->size == 2);
+ assert(it->__private_data.start_pos == 1);
+ assert(it->__private_data.block_index == 1);
+ db.set_empty(0, 1);
+ it = db.set(1, true); // different type from that of the following block.
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ check = db.end();
+ std::advance(check, -2);
+ assert(it == check);
+ assert(it->size == 1);
+ assert(it->__private_data.start_pos == 1);
+ assert(it->__private_data.block_index == 1);
+
+ // Set value to the middle of the top empty block (not size 1) followed by a non-empty block.
+ db.clear();
+ db.resize(6);
+ db.set(5, 1.1);
+ it = db.set(3, 1.2);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->size == 1);
+ assert(it->__private_data.start_pos == 3);
+ assert(it->__private_data.block_index == 1);
+
+ // Set value to an empty block of size 1 immediately below a non-empty block.
+ db.clear();
+ db.resize(2);
+ db.set(0, true);
+ it = db.set(1, false); // same type as that of the previous block.
+ assert(it == db.begin());
+
+ // Set value to an empty block of size 1 between non-empty blocks of the same type.
+ db = mtv_type(3, true);
+ db.set_empty(1, 1);
+ it = db.set(1, false);
+ assert(it == db.begin());
+ assert(it->size == 3);
+ ++it;
+ assert(it == db.end());
+
+ // Set value to an empty block of size 1 between non-empty blocks. The
+ // previous block is of the same type as that of the inserted value.
+ db = mtv_type(3, 1.1);
+ db.set_empty(0, 1);
+ db.set(0, true);
+ it = db.set(1, false);
+ assert(it == db.begin());
+ assert(it->size == 2);
+ std::advance(it, 2);
+ assert(it == db.end());
+
+ // Set value to the top of an empty block (not of size 1) following a
+ // non-empty block of the same type.
+ db.clear();
+ db.resize(3);
+ db.set(0, true);
+ it = db.set(1, false);
+ assert(it == db.begin());
+ assert(it->size == 2);
+
+ // Set value to an empty block of size 1, following a non-empty block of different type.
+ db = mtv_type(2);
+ db.set(0, true);
+ it = db.set(1, 1.1);
+ ++it;
+ assert(it == db.end());
+
+ // Set value to an empty block of size 1, following a non-empty block of
+ // different type and followed by a non-empty block of different type.
+ db = mtv_type(3, true);
+ db.set_empty(1, 1);
+ it = db.set(1, 2.1);
+ std::advance(it, 2);
+ assert(it == db.end());
+
+ // Set value to an empty block of size 1, following a non-empty block of
+ // different type but followed by a non-empty block of the same type.
+ db.clear();
+ db.resize(3);
+ db.set(0, true);
+ it = db.set(2, 2.1);
+ ++it;
+ assert(it == db.end());
+ it = db.set(1, 2.2); // same type as that of the following block.
+ assert(it->size == 2);
+ ++it;
+ assert(it == db.end());
+
+ // Set value to the top of an empty block (not of size 1) between
+ // non-empty blocks. The previous block is of different type.
+ db.clear();
+ db.resize(4);
+ db.set(0, true);
+ db.set(3, false);
+ it = db.set(1, 2.2);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->size == 1);
+ assert(it->__private_data.start_pos == 1);
+
+ // Set value to the bottom of an empty block (not of size 1) between
+ // non-empty blocks.
+ db = mtv_type(7, false);
+ db.set_empty(2, 4);
+ it = db.set(4, true); // Same type as that of the following block.
+ assert(it->size == 3);
+ assert(it->__private_data.start_pos == 4);
+ assert(it->__private_data.block_index == 2);
+ ++it;
+ assert(it == db.end());
+
+ db.set_empty(2, 4);
+ it = db.set(4, 1.1); // Different type from that of the following block.
+ assert(it->size == 1);
+ assert(it->__private_data.start_pos == 4);
+ assert(it->__private_data.block_index == 2);
+ std::advance(it, 2);
+ assert(it == db.end());
+
+ // Set value to the middle of an empty block between non-empty blocks.
+ db = mtv_type(12, true);
+ db.set_empty(3, 7);
+ it = db.set(5, 4.3);
+ assert(it->size == 1);
+ check = db.begin();
+ std::advance(check, 2);
+ assert(check == it);
+ ++it;
+ assert(it->size == 2);
+ assert(it->type == mtv::element_type_empty);
+ ++it;
+ assert(it->size == 4);
+ assert(it->type == mtv::element_type_boolean);
+ ++it;
+ assert(it == db.end());
+
+ // Set value to existing block of the same type.
+ it = db.set(5, 4.5);
+ check = db.begin();
+ std::advance(check, 2);
+ assert(it == check);
+ assert(it->size == 1);
+ std::advance(it, 3);
+ assert(it == db.end());
+
+ // Set value to the top of an existing topmost block of different type.
+ db = mtv_type(5, true);
+ it = db.set(0, 1.1);
+ assert(it == db.begin());
+ std::advance(it, 2);
+ assert(it == db.end());
+
+ // Set value to the top of an existing block of different type. The block
+ // is below an empty block.
+ db = mtv_type(10, true);
+ db.set_empty(0, 4);
+ it = db.set(5, 2.1);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ std::advance(it, 2);
+ assert(it == db.end());
+
+ // Set value to the top of an existing block of different type. The block
+ // is below a non-empty block.
+ db = mtv_type(10, true);
+ vector<double> doubles(3, 1.1);
+ db.set(2, doubles.begin(), doubles.end()); // set double's to 2 thru 4.
+ it = db.set(5, 2.1); // append to the previous block.
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ ++it;
+ assert(it->size == 4);
+ assert(it->type == mtv::element_type_boolean);
+ ++it;
+ assert(it == db.end());
+
+ db = mtv_type(10, true);
+ db.set(2, doubles.begin(), doubles.end()); // set double's to 2 thru 4.
+ it = db.set(5, string("foo")); // type different from that of the previous block.
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_string);
+ check = db.begin();
+ std::advance(check, 2);
+ assert(it == check);
+ std::advance(it, 2);
+ assert(it == db.end());
+
+ // Set value to the middle of an existing non-empty block.
+ db = mtv_type(10, true);
+ doubles.clear();
+ doubles.resize(3, 2.3);
+ db.set(0, doubles.begin(), doubles.end()); // set double's to 0 thru 2.
+ it = db.set(6, string("text"));
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_string);
+ assert(it->__private_data.start_pos = 6);
+ check = db.begin();
+ std::advance(check, 2);
+ assert(it == check);
+ ++it;
+ assert(it->size == 3);
+ assert(it->type == mtv::element_type_boolean);
+ ++it;
+ assert(it == db.end());
+
+ // Set value to the bottom of the only block that's non-empty.
+ db = mtv_type(10, false);
+ it = db.set(9, 2.1);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ ++it;
+ assert(it == db.end());
+
+ // Set value to the bottom of the topmost non-empty block which is
+ // followed by an empty block.
+ db = mtv_type(10, false);
+ db.set_empty(5, 9);
+ it = db.set(4, 1.1);
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->__private_data.start_pos == 4);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ ++it;
+ assert(it->size == 5);
+ assert(it->type == mtv::element_type_empty);
+ ++it;
+ assert(it == db.end());
+
+ // This time the following block is not empty but is of different type
+ // than that of the value being set.
+ db = mtv_type(10, false);
+ doubles.clear();
+ doubles.resize(5, 2.1);
+ db.set(5, doubles.begin(), doubles.end()); // numeric at 5 thru 9
+ it = db.set(4, string("foo"));
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_string);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ ++it;
+ assert(it->size == 5);
+ assert(it->type == mtv::element_type_numeric);
+ ++it;
+ assert(it == db.end());
+
+ // Same as before, but the value being set is of the same type as that of
+ // the following block.
+ db = mtv_type(10, false);
+ doubles.clear();
+ doubles.resize(5, 2.1);
+ db.set(5, doubles.begin(), doubles.end()); // numeric at 5 thru 9
+ it = db.set(4, 4.5); // same type as the following block.
+ assert(it->size == 6);
+ assert(it->type == mtv::element_type_numeric);
+ ++it;
+ assert(it == db.end());
+
+ // Set value to the bottom of the last non-empty block.
+ db = mtv_type(10, false);
+ doubles.clear();
+ doubles.resize(4, 3.1);
+ db.set(6, doubles.begin(), doubles.end()); // numeric at 6 thru 9
+ it = db.set(9, true);
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_boolean);
+ ++it;
+ assert(it == db.end());
+
+ // Set value to the bottom of an non-empty block followed by an empty block.
+ db = mtv_type(10, false);
+ doubles.clear();
+ doubles.resize(3, 3.3);
+ db.set(2, doubles.begin(), doubles.end()); // numeric at 2 thru 4.
+ db.set_empty(5, 9);
+ it = db.set(4, string("foo"));
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_string);
+ assert(it->__private_data.start_pos == 4);
+ assert(it->__private_data.block_index == 2);
+ ++it;
+ assert(it->size == 5);
+ assert(it->type == mtv::element_type_empty);
+ ++it;
+ assert(it == db.end());
+
+ // Same as before, except the following block isn't empty but of different type.
+ db = mtv_type(10, false);
+ db.set(4, doubles.begin(), doubles.end()); // numeric at 4 thru 6.
+ it = db.set(6, string("foo")); // 7 thru 9 is boolean.
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_string);
+ assert(it->__private_data.start_pos == 6);
+ assert(it->__private_data.block_index == 2);
+ ++it;
+ assert(it->size == 3);
+ assert(it->type == mtv::element_type_boolean);
+ assert(it->__private_data.start_pos == 7);
+ ++it;
+ assert(it == db.end());
+
+ // Same as before, except the following block is now of the same type.
+ db = mtv_type(10, false);
+ db.set(4, doubles.begin(), doubles.end()); // numeric at 4 thru 6.
+ it = db.set(6, true); // 7 thru 9 is boolean.
+
+ // Set value to the only block (non-empty) of size 1.
+ db = mtv_type(1, true);
+ it = db.set(0, 1.1);
+ assert(it == db.begin());
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_numeric);
+
+ // Set value to the topmost non-empty block of size 1, followed by an empty block.
+ db.resize(5);
+ it = db.set(0, string("foo"));
+ assert(it == db.begin());
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_string);
+ ++it;
+ assert(it->size == 4);
+ assert(it->type == mtv::element_type_empty);
+ ++it;
+ assert(it == db.end());
+
+ // Set value to the topmost non-empty block of size 1, followed by a non-empty block.
+ db = mtv_type(5, true);
+ db.set(0, 1.1);
+ it = db.set(0, string("foo"));
+ assert(it == db.begin());
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_string);
+ ++it;
+ assert(it->size == 4);
+ assert(it->type == mtv::element_type_boolean);
+ ++it;
+ assert(it == db.end());
+
+ // This time set value whose type is the same as that of the following block.
+ it = db.set(0, false);
+ assert(it == db.begin());
+ assert(it->size == 5);
+ assert(it->type == mtv::element_type_boolean);
+ ++it;
+ assert(it == db.end());
+
+ // Set value to the topmost non-empty block of size 1, preceded by an empty block.
+ db = mtv_type(5);
+ db.set(4, true);
+ it = db.set(4, 1.2);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_numeric);
+ ++it;
+ assert(it == db.end());
+
+ // This time the preceding block is not empty, but of different type.
+ db = mtv_type(5, false);
+ db.set(0, string("baa"));
+ db.set(4, string("foo"));
+ it = db.set(4, 1.2);
+ check = db.begin();
+ std::advance(check, 2);
+ assert(it == check);
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_numeric);
+ ++it;
+ assert(it == db.end());
+
+ it = db.set(4, true); // Now set value whose type is the same as that of the preceding block.
+ check = db.end();
+ --check;
+ assert(it == check);
+ assert(it->size == 4);
+ assert(it->type == mtv::element_type_boolean);
+ --it;
+ assert(it == db.begin());
+
+ // Set value to a non-empty block of size 1 that lies between existing blocks.
+ db = mtv_type(10);
+ db.set(7, true);
+ it = db.set(7, 1.1); // Both preceding and following blocks are empty.
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_numeric);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ ++it;
+ assert(it->size == 2);
+ assert(it->type == mtv::element_type_empty);
+ ++it;
+ assert(it == db.end());
+
+ db = mtv_type(10, true);
+ doubles.clear();
+ doubles.resize(8, 2.1);
+ db.set(2, doubles.begin(), doubles.end()); // Set 2 thru 9 numeric.
+ db.set(6, false);
+ it = db.set(6, string("foo")); // Both preceding and following blocks are non-empty.
+ check = db.end();
+ std::advance(check, -2);
+ assert(it == check);
+ --it;
+ assert(it->size == 4);
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->__private_data.start_pos == 2);
+ --it;
+ assert(it->size == 2);
+ assert(it->type == mtv::element_type_boolean);
+ assert(it->__private_data.start_pos == 0);
+ assert(it == db.begin());
+
+ it = db.set(6, 4.5); // Same type as those of the preceding and following blocks.
+ assert(it->size == 8);
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->__private_data.start_pos == 2);
+ assert(it->__private_data.block_index == 1);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ ++it;
+ assert(it == db.end());
+
+ db = mtv_type(10, true);
+ db.set(4, static_cast<int>(34));
+ doubles.resize(5, 2.3);
+ db.set(5, doubles.begin(), doubles.end());
+ it = db.set(4, false); // Same type as that of the preceding block.
+ assert(it == db.begin());
+ assert(it->size == 5);
+ assert(it->type == mtv::element_type_boolean);
+ std::advance(it, 2);
+ assert(it == db.end());
+
+ db.set(4, static_cast<int>(35)); // Reset to previous state.
+ it = db.set(4, 4.5); // Same type as that of the following block.
+ assert(it->size == 6);
+ assert(it->type == mtv::element_type_numeric);
+ ++it;
+ assert(it == db.end());
+
+ db.set(4, static_cast<int>(36)); // Reset again.
+ it = db.set(4, static_cast<short>(28)); // Different type from either of the blocks.
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_short);
+ assert(it->__private_data.start_pos == 4);
+ assert(it->__private_data.block_index == 1);
+ std::advance(it, 2);
+ assert(it == db.end());
+
+ // Preceding block is empty, and the following block is non-empty.
+ db = mtv_type(10);
+ doubles.resize(3, 1.1);
+ db.set(7, doubles.begin(), doubles.end()); // 7 thru 9 to be numeric.
+ db.set(6, static_cast<int>(23));
+ it = db.set(6, string("foo")); // Type different from that of the following block.
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_string);
+ assert(it->__private_data.start_pos == 6);
+ ++it;
+ assert(it->size == 3);
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->__private_data.start_pos == 7);
+ ++it;
+ assert(it == db.end());
+
+ db.set(6, static_cast<int>(24)); // Reset.
+ it = db.set(6, 4.5); // This time the same type as that of the following block.
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->size == 4);
+ assert(it->type == mtv::element_type_numeric);
+ ++it;
+ assert(it == db.end());
+
+ // Now, the preceding block is not empty while the following block is.
+ db = mtv_type(10, static_cast<unsigned short>(10));
+ db.set_empty(4, 6);
+ db.set(3, 1.2);
+ it = db.set(3, static_cast<unsigned short>(11)); // Same as the previous block.
+ assert(it == db.begin());
+ assert(it->size == 4);
+ assert(it->type == mtv::element_type_ushort);
+ std::advance(it, 3);
+ assert(it == db.end());
+
+ db.set(3, 1.3); // Reset
+ it = db.set(3, string("foo")); // This time, different from the previous block.
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->size == 1);
+ assert(it->type == mtv::element_type_string);
+ std::advance(it, 3);
+ assert(it == db.end());
+}
+
+/**
+ * Test the variant of set() method that takes iterators.
+ */
+void mtv_test_set2_return_iterator()
+{
+ stack_printer __stack_printer__("::mtv_test_set2_return_iterator");
+ mtv_type::iterator it, check;
+ vector<double> doubles(3, 1.1);
+ deque<bool> bools;
+ vector<string> strings;
+
+ // simple overwrite.
+ mtv_type db(10, 2.3);
+ db.set(0, true);
+ db.set(1, string("foo"));
+ it = db.set(2, doubles.begin(), doubles.end());
+ check = db.begin();
+ std::advance(check, 2);
+ assert(it == check);
+ ++it;
+ assert(it == db.end());
+
+ // Insert and merge with previous block.
+ db = mtv_type(10, true);
+ db.set(5, 1.1);
+ db.set(6, 1.2);
+ db.set(7, 1.3);
+ db.set(8, string("foo"));
+ bools.resize(3, false);
+ it = db.set(5, bools.begin(), bools.end());
+ assert(it == db.begin());
+ assert(it->size == 8);
+ assert(it->type == mtv::element_type_boolean);
+ std::advance(it, 3);
+ assert(it == db.end());
+
+ // Insert and merge with previous and next blocks.
+ db = mtv_type(10, true);
+ db.set(0, string("foo"));
+ db.set(5, 1.1);
+ db.set(6, 1.2);
+ db.set(7, 1.3);
+ it = db.set(5, bools.begin(), bools.end());
+ assert(db.block_size() == 2);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->size == 9);
+ assert(it->type == mtv::element_type_boolean);
+ ++it;
+ assert(it == db.end());
+
+ // Insert and merge with next block only.
+ db = mtv_type(10); // start empty.
+ db.set(4, true);
+ db.set(5, true);
+ db.set(6, true);
+ db.set(7, 1.1);
+ db.set(8, 1.2);
+ db.set(9, 1.3);
+ doubles.resize(3, 2.2);
+ it = db.set(4, doubles.begin(), doubles.end());
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->size == 6);
+ assert(it->type == mtv::element_type_numeric);
+ ++it;
+ assert(it == db.end());
+
+ // Replace the upper part of a block and merge with previous block.
+ db = mtv_type(10, false);
+ db.set(3, 1.2);
+ db.set(4, 1.3);
+ db.set(5, 1.4);
+ db.set(6, 1.5);
+ db.set(7, 1.6);
+ bools.resize(3, true);
+ it = db.set(3, bools.begin(), bools.end());
+ assert(it == db.begin());
+ assert(it->size == 6);
+ assert(it->type == mtv::element_type_boolean);
+ std::advance(it, 3);
+ assert(it == db.end());
+
+ // Replace the upper part of a block but don't merge with previous block.
+ db = mtv_type(10, false);
+ db.set(3, string("A"));
+ db.set(4, string("B"));
+ db.set(5, string("C"));
+ db.set(6, string("D"));
+ db.set(7, string("E"));
+ doubles.resize(3, 1.1);
+ it = db.set(3, doubles.begin(), doubles.end());
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->size == 3);
+ assert(it->type == mtv::element_type_numeric);
+ ++it;
+ assert(it->size == 2);
+ assert(it->type == mtv::element_type_string);
+ ++it;
+ assert(it->size == 2);
+ assert(it->type == mtv::element_type_boolean);
+ ++it;
+ assert(it == db.end());
+
+ // Overwrite the lower part of a block and merge it with the next block.
+ db = mtv_type(10, false);
+ db.set(0, 2.2);
+ db.set(4, 1.1);
+ db.set(5, 1.2);
+ db.set(6, 1.3);
+ assert(db.block_size() == 4);
+ bools.resize(2, true);
+ it = db.set(5, bools.begin(), bools.end()); // 5 to 6
+ check = db.begin();
+ std::advance(check, 3);
+ assert(it == check);
+ assert(it->size == 5);
+ assert(it->type == mtv::element_type_boolean);
+ ++it;
+ assert(it == db.end());
+
+ // Overwrite the lower part of a block but don't merge it with the next block.
+ db = mtv_type(10, string("boo"));
+ db.set(0, 1.1);
+ db.set(5, true);
+ db.set(6, true);
+ db.set(7, true);
+ doubles.resize(2, 2.2);
+ it = db.set(6, doubles.begin(), doubles.end());
+ check = db.begin();
+ std::advance(check, 3);
+ assert(it == check);
+ assert(it->size == 2);
+ assert(it->type == mtv::element_type_numeric);
+ std::advance(it, 2);
+ assert(it == db.end());
+
+ // Overwrite the lower part of the last block.
+ db = mtv_type(10, string("boo"));
+ db.set(0, 1.1);
+ doubles.resize(3, 2.2);
+ it = db.set(7, doubles.begin(), doubles.end());
+ check = db.begin();
+ std::advance(check, 2);
+ assert(it == check);
+ ++it;
+ assert(it->size == 3);
+ assert(it->type == mtv::element_type_numeric);
+ assert(it == db.end());
+
+ // Overwrite the middle part of a block.
+ db = mtv_type(10);
+ bools.resize(5, true);
+ it = db.set(3, bools.begin(), bools.end());
+ check = db.begin();
+ ++check;
+ assert(check == it);
+ assert(it->size == 5);
+ assert(it->type == mtv::element_type_boolean);
+ std::advance(it, 2);
+ assert(it == db.end());
+
+ // Overwrite multiple blocks with values whose type matches that of the top block.
+ int int_val = 255;
+ db = mtv_type(10, int_val);
+ bools.resize(6, true);
+ db.set(4, bools.begin(), bools.end()); // set 4 thru 9 to bool.
+ db.set(5, 1.1);
+ db.set(7, string("foo"));
+ assert(db.block_size() == 6);
+ doubles.resize(4, 4.5);
+ it = db.set(5, doubles.begin(), doubles.end()); // 5 thrugh 8.
+ check = db.begin();
+ assert(check->type == mtv::element_type_int);
+ ++check;
+ assert(check->type == mtv::element_type_boolean);
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->size == 4);
+ std::advance(it, 2);
+ assert(it == db.end());
+
+ // The same scenario, except that the values also match that of the bottom block.
+ db = mtv_type(10, 1.1);
+ db.set(5, true);
+ assert(db.block_size() == 3);
+ doubles.resize(3, 2.3);
+ it = db.set(4, doubles.begin(), doubles.end());
+ assert(db.block_size() == 1);
+ assert(it == db.begin());
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->size == 10);
+ ++it;
+ assert(it == db.end());
+
+ // This time, the top block is of different type.
+ db = mtv_type(10, false);
+ doubles.resize(4, 4.5);
+ db.set(3, doubles.begin(), doubles.end()); // 3 thru 6
+ db.set(0, int(1));
+ strings.resize(4, string("test"));
+ it = db.set(4, strings.begin(), strings.end()); // Overwrite the lower part of the top block.
+ check = db.begin();
+ assert(check->type == mtv::element_type_int);
+ ++check;
+ assert(check->type == mtv::element_type_boolean);
+ ++check;
+ assert(check->type == mtv::element_type_numeric);
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_string);
+ assert(it->size == 4);
+ ++it;
+ assert(it->type == mtv::element_type_boolean);
+ ++it;
+ assert(it == db.end());
+
+ db = mtv_type(10, false);
+ db.set(0, 1.1);
+ db.set(4, 1.2);
+ db.set(5, 1.3);
+ db.set(6, string("a"));
+ db.set(7, string("b"));
+ doubles.resize(3, 0.8);
+ it = db.set(6, doubles.begin(), doubles.end()); // Merge with the upper block.
+ check = db.begin();
+ assert(check->type == mtv::element_type_numeric);
+ ++check;
+ assert(check->type == mtv::element_type_boolean);
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->size == 5);
+ ++it;
+ assert(it->type == mtv::element_type_boolean);
+ assert(it->size == 1);
+ ++it;
+ assert(it == db.end());
+
+ // Make sure this also works in scenarios where the values merge with lower block.
+ db = mtv_type(20, false);
+ doubles.resize(4, 3.4);
+ db.set(5, doubles.begin(), doubles.end()); // 5 thru 8
+ strings.resize(5, "expanded");
+ db.set(11, strings.begin(), strings.end()); // 11 thru 15
+ strings.clear();
+ strings.resize(6, "overwriting");
+ it = db.set(7, strings.begin(), strings.end()); // 7 thru 12
+
+ // At this point, 7 thru 15 should be strings.
+ assert(it->type == mtv::element_type_string);
+ assert(it->size == 9);
+ check = db.begin();
+ assert(check->type == mtv::element_type_boolean);
+ assert(check->size == 5); // 0 thru 4
+ ++check;
+ assert(check->type == mtv::element_type_numeric);
+ assert(check->size == 2); // 5 thru 6
+ ++check;
+ assert(it == check);
+ ++it;
+ assert(it->type == mtv::element_type_boolean);
+ assert(it->size == 4); // 16 thru 19
+ ++it;
+ assert(it == db.end());
+}
+
+void mtv_test_insert_cells_return_iterator()
+{
+ stack_printer __stack_printer__("::mtv_test_insert_cells_return_iterator");
+ mtv_type::iterator it, check;
+ vector<double> doubles;
+ vector<bool> bools;
+ vector<string> strings;
+ vector<int> ints;
+
+ // Insert values into empty block. They are to be appended to the previous block.
+ mtv_type db(10); // start with empty set.
+ db.set(0, string("top"));
+ db.set(3, 0.9);
+ doubles.resize(4, 1.1);
+ it = db.insert(4, doubles.begin(), doubles.end());
+ check = db.begin();
+ advance(check, 2);
+ assert(it == check);
+ assert(it->size == 5);
+ assert(it->__private_data.start_pos == 3);
+ ++it;
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 6);
+ ++it;
+ assert(it == db.end());
+
+ // Same as above, except that the values will not be appended to the previous block.
+ db = mtv_type(3);
+ db.set(0, string("top"));
+ doubles.resize(5, 3.3);
+ it = db.insert(1, doubles.begin(), doubles.end());
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->size == 5);
+ assert(it->type == mtv::element_type_numeric);
+ ++it;
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 2);
+ ++it;
+ assert(it == db.end());
+
+ // Insert into the middle of an empty block.
+ db = mtv_type(2);
+ doubles.resize(3, 1.2);
+ it = db.insert(1, doubles.begin(), doubles.end());
+ check = db.begin();
+ assert(check->type == mtv::element_type_empty);
+ assert(check->size == 1);
+ ++check;
+ assert(check == it);
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->size == 3);
+ ++it;
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 1);
+ ++it;
+ assert(it == db.end());
+
+ // Insert into a block of the same type.
+ db = mtv_type(5, false);
+ db.set(0, string("top"));
+ db.set(4, string("bottom"));
+ bools.resize(3, true);
+ it = db.insert(2, bools.begin(), bools.end());
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_boolean);
+ assert(it->size == 6);
+ advance(it, 2);
+ assert(it == db.end());
+
+ // Insert values which will be append to the previous block.
+ db = mtv_type(5, 1.1);
+ strings.resize(3, string("test"));
+ db.set(0, true);
+ db.set(2, strings.begin(), strings.end()); // 2 thru 4
+ doubles.resize(2, 2.2);
+ it = db.insert(2, doubles.begin(), doubles.end());
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->size == 3);
+ ++it;
+ assert(it->type == mtv::element_type_string);
+ assert(it->size == 3);
+ ++it;
+ assert(it == db.end());
+
+ // Insert between blocks without merge.
+ db = mtv_type(3);
+ db.set(0, 1.1);
+ db.set(1, string("middle"));
+ db.set(2, int(50));
+ bools.resize(4, true);
+ it = db.insert(1, bools.begin(), bools.end());
+ check = db.begin();
+ assert(check->type == mtv::element_type_numeric);
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_boolean);
+ assert(it->size == 4);
+ ++it;
+ assert(it->type == mtv::element_type_string);
+ assert(it->size == 1);
+ ++it;
+ assert(it->type == mtv::element_type_int);
+ assert(it->size == 1);
+ ++it;
+ assert(it == db.end());
+
+ // Insert values of differing type into middle of a block.
+ db = mtv_type(4, 0.01);
+ db.set(0, string("top"));
+ ints.resize(3, 55);
+ it = db.insert(2, ints.begin(), ints.end());
+ check = db.begin();
+ assert(check->type == mtv::element_type_string);
+ assert(check->size == 1);
+ ++check;
+ assert(check->type == mtv::element_type_numeric);
+ assert(check->size == 1);
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_int);
+ assert(it->size == 3);
+ ++it;
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->size == 2);
+ ++it;
+ assert(it == db.end());
+}
+
+void mtv_test_set_empty_return_iterator()
+{
+ stack_printer __stack_printer__("::mtv_test_set_empty_return_iterator");
+ mtv_type::iterator it, check;
+
+ // Block is already empty. Calling the method does not do anything.
+ mtv_type db(10);
+ db.set(0, 1.1);
+ it = db.set_empty(6, 8);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+
+ // Empty a whole block.
+ db = mtv_type(10, false);
+ db.set(0, 1.1);
+ db.set(1, string("A"));
+ it = db.set_empty(2, 9);
+ check = db.begin();
+ advance(check, 2);
+ assert(it == check);
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 8);
+ ++it;
+ assert(it == db.end());
+
+ // Empty the upper part of a block.
+ vector<short> shorts(8, 23);
+ db.set(2, shorts.begin(), shorts.end());
+ it = db.set_empty(2, 6);
+ check = db.begin();
+ advance(check, 2);
+ assert(it == check);
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 5);
+ ++it;
+ assert(it->type == mtv::element_type_short);
+ assert(it->size == 3);
+ ++it;
+ assert(it == db.end());
+
+ // Empty the lower part of a block.
+ db = mtv_type(10, string("foo"));
+ it = db.set_empty(3, 9);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 7);
+ ++it;
+ assert(it == db.end());
+
+ // Empty the middle part of a block.
+ db = mtv_type(10, string("baa"));
+ it = db.set_empty(3, 6);
+ check = db.begin();
+ assert(check->type == mtv::element_type_string);
+ assert(check->size == 3);
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 4);
+ ++it;
+ assert(it->type == mtv::element_type_string);
+ assert(it->size == 3);
+ ++it;
+ assert(it == db.end());
+
+ // Empty multiple blocks. The first block is partially emptied.
+ db = mtv_type(10, false);
+ db.set(0, 1.1);
+ shorts.resize(3, 22);
+ db.set(4, shorts.begin(), shorts.end()); // 4 thru 6
+ it = db.set_empty(5, 8);
+ check = db.begin();
+ assert(check->type == mtv::element_type_numeric);
+ assert(check->size == 1);
+ ++check;
+ assert(check->type == mtv::element_type_boolean);
+ assert(check->size == 3);
+ ++check;
+ assert(check->type == mtv::element_type_short);
+ assert(check->size == 1);
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 4);
+ ++it;
+ assert(it->type == mtv::element_type_boolean);
+ assert(it->size == 1);
+ ++it;
+ assert(it == db.end());
+
+ // This time, the first block is completely emptied.
+ db = mtv_type(10, false);
+ db.set(0, 1.2);
+ shorts.resize(3, 42);
+ db.set(4, shorts.begin(), shorts.end()); // 4 thru 6
+ it = db.set_empty(4, 7);
+ check = db.begin();
+ assert(check->type == mtv::element_type_numeric);
+ assert(check->size == 1);
+ ++check;
+ assert(check->type == mtv::element_type_boolean);
+ assert(check->size == 3);
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 4);
+ ++it;
+ assert(it->type == mtv::element_type_boolean);
+ assert(it->size == 2);
+ ++it;
+ assert(it == db.end());
+
+ // And this time, the first block is partially emptied but it's already an
+ // empty block to begin with.
+ db = mtv_type(10);
+ db.set(0, string("top"));
+ vector<double> doubles(5, 1.2);
+ db.set(5, doubles.begin(), doubles.end()); // 5 thru 9
+ it = db.set_empty(3, 7);
+ check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 7);
+ ++it;
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->size == 2);
+ ++it;
+ assert(it == db.end());
+}
+
+void mtv_test_insert_empty_return_iterator()
+{
+ stack_printer __stack_printer__("::mtv_test_insert_empty_return_iterator");
+
+ // Insert into an already empty spot.
+ mtv_type db(2);
+ db.set(1, 1.2);
+ mtv_type::iterator it = db.insert_empty(0, 3);
+ assert(it == db.begin());
+ assert(it->size == 4);
+ assert(it->type == mtv::element_type_empty);
+ ++it;
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->size == 1);
+ ++it;
+ assert(it == db.end());
+
+ // Insert an empty range that will be tucked into the previous empty block.
+ db = mtv_type(4);
+ db.set(0, string("foo"));
+ db.set(2, 1.1);
+ db.set(3, 1.2);
+ it = db.insert_empty(2, 2);
+ mtv_type::iterator check = db.begin();
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 3);
+ ++it;
+ assert(it->type == mtv::element_type_numeric);
+ assert(it->size == 2);
+ ++it;
+ assert(it == db.end());
+
+ // Insert an empty range between non-empty blocks.
+ db = mtv_type(2, false);
+ db.set(0, 1.1);
+ it = db.insert_empty(1, 2);
+ check = db.begin();
+ assert(check->type == mtv::element_type_numeric);
+ assert(check->size == 1);
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 2);
+ ++it;
+ assert(it->type == mtv::element_type_boolean);
+ assert(it->size == 1);
+ ++it;
+ assert(it == db.end());
+
+ // Insert in the middle of a non-empty block.
+ db = mtv_type(3, string("foo"));
+ it = db.insert_empty(2, 4);
+ check = db.begin();
+ assert(check->type == mtv::element_type_string);
+ assert(check->size == 2);
+ ++check;
+ assert(it == check);
+ assert(it->type == mtv::element_type_empty);
+ assert(it->size == 4);
+ ++it;
+ assert(it->type == mtv::element_type_string);
+ assert(it->size == 1);
+ ++it;
+ assert(it == db.end());
+}
+
+void mtv_test_set_with_position()
+{
+ stack_printer __stack_printer__("::mtv_test_set_with_position");
+ mtv_type db(3);
+ db.set(db.begin(), 0, 23.4);
+ assert(db.get<double>(0) == 23.4);
+ db.set(db.end(), 0, string("test")); // passing end position should have no impact.
+ assert(db.get<string>(0) == "test");
+
+ mtv_type::iterator pos_hint = db.set(0, 1.2);
+ pos_hint = db.set(pos_hint, 1, 1.3);
+ pos_hint = db.set(pos_hint, 2, 1.4);
+ assert(db.get<double>(0) == 1.2);
+ assert(db.get<double>(1) == 1.3);
+ assert(db.get<double>(2) == 1.4);
+
+ pos_hint = db.begin();
+ pos_hint = db.set(pos_hint, 0, false);
+ pos_hint = db.set(pos_hint, 1, string("foo"));
+ pos_hint = db.set(pos_hint, 2, 34.5);
+ assert(db.get<bool>(0) == false);
+ assert(db.get<string>(1) == "foo");
+ assert(db.get<double>(2) == 34.5);
+
+ db.set(pos_hint, 0, int(444)); // position hint does not precede the insertion position.
+ assert(db.get<int>(0) == 444); // it should still work.
+}
+
+void mtv_test_set_cells_with_position()
+{
+ stack_printer __stack_printer__("::mtv_test_set_cells_with_position");
+ mtv_type db(9);
+
+ vector<int> ints;
+ ints.push_back(1);
+ ints.push_back(2);
+ ints.push_back(3);
+
+ vector<double> doubles;
+ doubles.push_back(1.1);
+ doubles.push_back(1.2);
+ doubles.push_back(1.3);
+
+ vector<string> strings;
+ strings.push_back(string("A"));
+ strings.push_back(string("B"));
+ strings.push_back(string("C"));
+
+ mtv_type::iterator pos_hint = db.begin();
+ pos_hint = db.set(pos_hint, 0, ints.begin(), ints.end());
+ pos_hint = db.set(pos_hint, 3, doubles.begin(), doubles.end());
+ pos_hint = db.set(pos_hint, 6, strings.begin(), strings.end());
+
+ assert(db.get<int>(0) == 1);
+ assert(db.get<int>(1) == 2);
+ assert(db.get<int>(2) == 3);
+
+ assert(db.get<double>(3) == 1.1);
+ assert(db.get<double>(4) == 1.2);
+ assert(db.get<double>(5) == 1.3);
+
+ assert(db.get<string>(6) == "A");
+ assert(db.get<string>(7) == "B");
+ assert(db.get<string>(8) == "C");
+}
+
+void mtv_test_insert_cells_with_position()
+{
+ stack_printer __stack_printer__("::mtv_test_insert_cells_with_position");
+
+ mtv_type db(1, true); // We need to have at least one element to be able to insert.
+
+ vector<int> ints;
+ ints.push_back(11);
+ ints.push_back(22);
+
+ vector<double> doubles;
+ doubles.push_back(2.1);
+ doubles.push_back(3.2);
+ doubles.push_back(4.3);
+
+ vector<string> strings;
+ strings.push_back(string("Andy"));
+ strings.push_back(string("Bruce"));
+ strings.push_back(string("Charlie"));
+ strings.push_back(string("David"));
+
+ mtv_type::iterator pos_hint = db.insert(0, ints.begin(), ints.end());
+ assert(db.get<int>(0) == 11);
+ assert(db.get<int>(1) == 22);
+ assert(db.get<bool>(2) == true);
+
+ pos_hint = db.insert(pos_hint, 2, doubles.begin(), doubles.end());
+ assert(db.get<int>(0) == 11);
+ assert(db.get<int>(1) == 22);
+ assert(db.get<double>(2) == 2.1);
+ assert(db.get<double>(3) == 3.2);
+ assert(db.get<double>(4) == 4.3);
+ assert(db.get<bool>(5) == true);
+
+ pos_hint = db.insert(pos_hint, 4, strings.begin(), strings.end());
+ assert(db.get<int>(0) == 11);
+ assert(db.get<int>(1) == 22);
+ assert(db.get<double>(2) == 2.1);
+ assert(db.get<double>(3) == 3.2);
+ assert(db.get<string>(4) == "Andy");
+ assert(db.get<string>(5) == "Bruce");
+ assert(db.get<string>(6) == "Charlie");
+ assert(db.get<string>(7) == "David");
+ assert(db.get<double>(8) == 4.3);
+ assert(db.get<bool>(9) == true);
+}
+
+void mtv_test_set_empty_with_position()
+{
+ stack_printer __stack_printer__("::mtv_test_set_empty_with_position");
+ mtv_type db(20, true);
+ mtv_type::iterator pos_hint = db.set_empty(db.begin(), 2, 3);
+ pos_hint = db.set_empty(pos_hint, 5, 7);
+ pos_hint = db.set_empty(pos_hint, 9, 12);
+ pos_hint = db.set_empty(pos_hint, 14, 17);
+
+ // Check the boundaries.
+ assert(!db.is_empty(0));
+ assert(!db.is_empty(4));
+ assert(db.is_empty(5));
+ assert(db.is_empty(7));
+ assert(!db.is_empty(8));
+ assert(db.is_empty(9));
+ assert(db.is_empty(12));
+ assert(!db.is_empty(13));
+ assert(db.is_empty(14));
+ assert(db.is_empty(17));
+ assert(!db.is_empty(18));
+}
+
+void mtv_test_insert_empty_with_position()
+{
+ stack_printer __stack_printer__("::mtv_test_insert_empty_with_position");
+ mtv_type db(2, true);
+ mtv_type::iterator pos_hint = db.begin();
+ pos_hint = db.insert_empty(pos_hint, 1, 3); // the size becomes 5.
+ pos_hint = db.insert_empty(pos_hint, 4, 2); // the size now becomes 7.
+
+ mtv_type::iterator check = db.begin();
+ assert(check->type == mtv::element_type_boolean);
+ assert(check->size == 1);
+ ++check;
+ assert(check->type == mtv::element_type_empty);
+ assert(check->size == 5);
+ ++check;
+ assert(check->type == mtv::element_type_boolean);
+ assert(check->size == 1);
+ ++check;
+ assert(check == db.end());
+}
+
+void mtv_perf_test_block_position_lookup()
+{
+ size_t n = 24000;
+
+ {
+ // Default insertion which always looks up the right element block
+ // from the position of the first block. As such, as the block size
+ // grows, so does the time it takes to search for the right block.
+
+ mtv_type db(n*2);
+ double val1 = 1.1;
+ int val2 = 23;
+ stack_printer __stack_printer__("::mtv_perf_test_block_position_lookup::default insertion");
+ for (size_t i = 0; i < n; ++i)
+ {
+ size_t pos1 = i*2, pos2 = i*2 + 1;
+ db.set(pos1, val1);
+ db.set(pos2, val2);
+ }
+ }
+
+ {
+ // As a solution for this, we can use an iterator to specify the start
+ // position, which eliminates the above scalability problem nicely.
+
+ mtv_type db(n*2);
+ mtv_type::iterator pos_hint = db.begin();
+ double val1 = 1.1;
+ int val2 = 23;
+ stack_printer __stack_printer__("::mtv_perf_test_block_position_lookup::insertion with position hint");
+ for (size_t i = 0; i < n; ++i)
+ {
+ size_t pos1 = i*2, pos2 = i*2 + 1;
+ pos_hint = db.set(pos_hint, pos1, val1);
+ pos_hint = db.set(pos_hint, pos2, val2);
+ }
+ }
+}
+
}
int main (int argc, char **argv)
@@ -2281,10 +3883,23 @@ int main (int argc, char **argv)
mtv_test_insert_cells();
mtv_test_iterators();
mtv_test_data_iterators();
+ mtv_test_non_const_data_iterators();
+ mtv_test_iterator_private_data();
+ mtv_test_set_return_iterator();
+ mtv_test_set2_return_iterator();
+ mtv_test_insert_cells_return_iterator();
+ mtv_test_set_empty_return_iterator();
+ mtv_test_insert_empty_return_iterator();
+ mtv_test_set_with_position();
+ mtv_test_set_cells_with_position();
+ mtv_test_insert_cells_with_position();
+ mtv_test_set_empty_with_position();
+ mtv_test_insert_empty_with_position();
}
if (opt.test_perf)
{
+ mtv_perf_test_block_position_lookup();
}
cout << "Test finished successfully!" << endl;
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-openoffice/mdds.git
Reply to: