[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[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: