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

[mdds] 31/62: Imported Upstream version 0.8.0



This is an automated email from the git hooks/post-receive script.

rene pushed a commit to branch master
in repository mdds.

commit 8d31f677855a16cb1a7a5dac09f3d84dfa038d43
Author: Rene Engelhard <rene@debian.org>
Date:   Thu Apr 21 14:50:50 2016 +0200

    Imported Upstream version 0.8.0
---
 AUTHORS                                         |    1 +
 Makefile.in                                     |   96 +-
 NEWS                                            |   30 +
 README                                          |   10 +
 configure                                       | 1526 ++++++++++++++++++++---
 configure.ac                                    |   15 +-
 include/mdds/flat_segment_tree.hpp              |   16 +-
 include/mdds/flat_segment_tree_def.inl          |   16 +-
 include/mdds/mixed_type_matrix.hpp              |    2 +-
 include/mdds/mixed_type_matrix_def.inl          |    2 +-
 include/mdds/mixed_type_matrix_flag_storage.hpp |    4 +-
 include/mdds/multi_type_vector.hpp              |  156 ++-
 include/mdds/multi_type_vector_custom_func1.hpp |  200 +++
 include/mdds/multi_type_vector_custom_func2.hpp |  241 ++++
 include/mdds/multi_type_vector_def.inl          |  612 ++++++++-
 include/mdds/multi_type_vector_itr.hpp          |   17 +
 include/mdds/multi_type_vector_trait.hpp        |   60 +
 include/mdds/multi_type_vector_types.hpp        |   28 +-
 include/mdds/node.hpp                           |   37 +-
 include/mdds/point_quad_tree.hpp                |    2 +-
 include/mdds/quad_node.hpp                      |    8 +-
 include/mdds/rectangle_set.hpp                  |    4 +-
 include/mdds/rectangle_set_def.inl              |    2 +-
 include/mdds/segment_tree.hpp                   |   14 +-
 misc/mdds.pc.in                                 |    7 +
 src/flat_segment_tree_test.cpp                  |   59 +-
 src/multi_type_vector_test_custom.cpp           |  687 +++++++---
 src/multi_type_vector_test_default.cpp          |  123 +-
 28 files changed, 3445 insertions(+), 530 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index a0ef3db..857c3f7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,5 +1,6 @@
 Kohei Yoshida  <kohei.yoshida@gmail.com> (Maintainer)
 David Tardon  <dtardon@redhat.com>
+Fridrich Štrba <fridrich.strba@bluewin.ch>
 Markus Mohrhard <markus.mohrhard@googlemail.com>
 Petr Mladek <pmladek@suse.cz>
 Caolán McNamara <caolanm@redhat.com>
diff --git a/Makefile.in b/Makefile.in
index 481b84a..116b714 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -5,6 +5,7 @@ PACKAGE_TARNAME=@PACKAGE_TARNAME@
 OBJDIR=@OBJDIR@
 SRCDIR=@SRCDIR@
 INCDIR=@INCDIR@
+MISCDIR=@MISCDIR@
 QUICKCHECKDIR=@QUICKCHECKDIR@
 
 CPPFLAGS=@CPPFLAGS@ -I$(INCDIR)
@@ -21,27 +22,27 @@ EXECS= \
 	multi_type_vector_test_custom
 
 HEADERS= \
-	$(INCDIR)/mdds/compat/unique_ptr.hpp \
-	$(INCDIR)/mdds/flat_segment_tree_def.inl \
-	$(INCDIR)/mdds/flat_segment_tree.hpp \
-	$(INCDIR)/mdds/flat_segment_tree_itr.hpp \
-	$(INCDIR)/mdds/global.hpp \
-	$(INCDIR)/mdds/hash_container/map.hpp \
-	$(INCDIR)/mdds/mixed_type_matrix_def.inl \
-	$(INCDIR)/mdds/mixed_type_matrix_element.hpp \
-	$(INCDIR)/mdds/mixed_type_matrix_flag_storage.hpp \
-	$(INCDIR)/mdds/mixed_type_matrix.hpp \
-	$(INCDIR)/mdds/mixed_type_matrix_storage_filled_linear.inl \
-	$(INCDIR)/mdds/mixed_type_matrix_storage.hpp \
-	$(INCDIR)/mdds/mixed_type_matrix_storage_sparse.inl \
-	$(INCDIR)/mdds/multi_type_matrix.hpp \
-	$(INCDIR)/mdds/multi_type_matrix_def.inl \
-	$(INCDIR)/mdds/node.hpp \
-	$(INCDIR)/mdds/point_quad_tree.hpp \
-	$(INCDIR)/mdds/quad_node.hpp \
-	$(INCDIR)/mdds/rectangle_set_def.inl \
-	$(INCDIR)/mdds/rectangle_set.hpp \
-	$(INCDIR)/mdds/segment_tree.hpp
+	@top_srcdir@/$(INCDIR)/mdds/compat/unique_ptr.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/flat_segment_tree_def.inl \
+	@top_srcdir@/$(INCDIR)/mdds/flat_segment_tree.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/flat_segment_tree_itr.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/global.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/hash_container/map.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/mixed_type_matrix_def.inl \
+	@top_srcdir@/$(INCDIR)/mdds/mixed_type_matrix_element.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/mixed_type_matrix_flag_storage.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/mixed_type_matrix.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/mixed_type_matrix_storage_filled_linear.inl \
+	@top_srcdir@/$(INCDIR)/mdds/mixed_type_matrix_storage.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/mixed_type_matrix_storage_sparse.inl \
+	@top_srcdir@/$(INCDIR)/mdds/multi_type_matrix.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/multi_type_matrix_def.inl \
+	@top_srcdir@/$(INCDIR)/mdds/node.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/point_quad_tree.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/quad_node.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/rectangle_set_def.inl \
+	@top_srcdir@/$(INCDIR)/mdds/rectangle_set.hpp \
+	@top_srcdir@/$(INCDIR)/mdds/segment_tree.hpp
 
 DEPENDS= \
 	$(HEADERS)
@@ -74,29 +75,29 @@ all: $(EXECS)
 pre:
 	mkdir -p $(OBJDIR)
 
-$(OBJDIR)/flat_segment_tree_test.o: $(SRCDIR)/flat_segment_tree_test.cpp $(DEPENDS)
-	$(CXX) $(CPPFLAGS) -c -o $@ $(SRCDIR)/flat_segment_tree_test.cpp
+$(OBJDIR)/flat_segment_tree_test.o: @top_srcdir@/$(SRCDIR)/flat_segment_tree_test.cpp $(DEPENDS)
+	$(CXX) $(CPPFLAGS) -c -o $@ @top_srcdir@/$(SRCDIR)/flat_segment_tree_test.cpp
 
-$(OBJDIR)/segment_tree_test.o: $(SRCDIR)/segment_tree_test.cpp  $(DEPENDS)
-	$(CXX) $(CPPFLAGS) -c -o $@ $(SRCDIR)/segment_tree_test.cpp
+$(OBJDIR)/segment_tree_test.o: @top_srcdir@/$(SRCDIR)/segment_tree_test.cpp  $(DEPENDS)
+	$(CXX) $(CPPFLAGS) -c -o $@ @top_srcdir@/$(SRCDIR)/segment_tree_test.cpp
 
-$(OBJDIR)/rectangle_set_test.o: $(SRCDIR)/rectangle_set_test.cpp  $(DEPENDS)
-	$(CXX) $(CPPFLAGS) -c -o $@ $(SRCDIR)/rectangle_set_test.cpp
+$(OBJDIR)/rectangle_set_test.o: @top_srcdir@/$(SRCDIR)/rectangle_set_test.cpp  $(DEPENDS)
+	$(CXX) $(CPPFLAGS) -c -o $@ @top_srcdir@/$(SRCDIR)/rectangle_set_test.cpp
 
-$(OBJDIR)/point_quad_tree_test.o: $(SRCDIR)/point_quad_tree_test.cpp $(DEPENDS)
-	$(CXX) $(CPPFLAGS) -c -o $@ $(SRCDIR)/point_quad_tree_test.cpp
+$(OBJDIR)/point_quad_tree_test.o: @top_srcdir@/$(SRCDIR)/point_quad_tree_test.cpp $(DEPENDS)
+	$(CXX) $(CPPFLAGS) -c -o $@ @top_srcdir@/$(SRCDIR)/point_quad_tree_test.cpp
 
-$(OBJDIR)/mixed_type_matrix_test.o: $(SRCDIR)/mixed_type_matrix_test.cpp $(DEPENDS)
-	$(CXX) $(CPPFLAGS) -c -o $@ $(SRCDIR)/mixed_type_matrix_test.cpp
+$(OBJDIR)/mixed_type_matrix_test.o: @top_srcdir@/$(SRCDIR)/mixed_type_matrix_test.cpp $(DEPENDS)
+	$(CXX) $(CPPFLAGS) -c -o $@ @top_srcdir@/$(SRCDIR)/mixed_type_matrix_test.cpp
 
-$(OBJDIR)/multi_type_vector_test_default.o: $(SRCDIR)/multi_type_vector_test_default.cpp $(DEPENDS)
-	$(CXX) $(CPPFLAGS) -c -o $@ $(SRCDIR)/multi_type_vector_test_default.cpp
+$(OBJDIR)/multi_type_vector_test_default.o: @top_srcdir@/$(SRCDIR)/multi_type_vector_test_default.cpp $(DEPENDS)
+	$(CXX) $(CPPFLAGS) -c -o $@ @top_srcdir@/$(SRCDIR)/multi_type_vector_test_default.cpp
 
-$(OBJDIR)/multi_type_vector_test_custom.o: $(SRCDIR)/multi_type_vector_test_custom.cpp $(DEPENDS)
-	$(CXX) $(CPPFLAGS) -c -o $@ $(SRCDIR)/multi_type_vector_test_custom.cpp
+$(OBJDIR)/multi_type_vector_test_custom.o: @top_srcdir@/$(SRCDIR)/multi_type_vector_test_custom.cpp $(DEPENDS)
+	$(CXX) $(CPPFLAGS) -c -o $@ @top_srcdir@/$(SRCDIR)/multi_type_vector_test_custom.cpp
 
-$(OBJDIR)/multi_type_matrix_test.o: $(SRCDIR)/multi_type_matrix_test.cpp $(DEPENDS)
-	$(CXX) $(CPPFLAGS) -c -o $@ $(SRCDIR)/multi_type_matrix_test.cpp
+$(OBJDIR)/multi_type_matrix_test.o: @top_srcdir@/$(SRCDIR)/multi_type_matrix_test.cpp $(DEPENDS)
+	$(CXX) $(CPPFLAGS) -c -o $@ @top_srcdir@/$(SRCDIR)/multi_type_matrix_test.cpp
 
 flat_segment_tree_test: pre $(OBJDIR)/flat_segment_tree_test.o
 	$(CXX) $(LDFLAGS) $(OBJDIR)/flat_segment_tree_test.o -o $@
@@ -124,11 +125,11 @@ multi_type_matrix_test: pre $(OBJDIR)/multi_type_matrix_test.o
 
 multi_type_vector_test: multi_type_vector_test_default multi_type_vector_test_custom
 
-stlperf_test: pre $(SRCDIR)/stlperf_test.cpp
-	$(CXX) $(LDFLAGS) $(CPPFLAGS) $(SRCDIR)/stlperf_test.cpp -o $@
+stlperf_test: pre @top_srcdir@/$(SRCDIR)/stlperf_test.cpp
+	$(CXX) $(LDFLAGS) $(CPPFLAGS) @top_srcdir@/$(SRCDIR)/stlperf_test.cpp -o $@
 
-$(OBJDIR)/template_test.o: $(SRCDIR)/template_test.cpp $(DEPENDS)
-	$(CXX) $(CPPFLAGS) -c -o $@ $(SRCDIR)/template_test.cpp
+$(OBJDIR)/template_test.o: @top_srcdir@/$(SRCDIR)/template_test.cpp $(DEPENDS)
+	$(CXX) $(CPPFLAGS) -c -o $@ @top_srcdir@/$(SRCDIR)/template_test.cpp
 
 test.fst: flat_segment_tree_test
 	./flat_segment_tree_test func
@@ -207,11 +208,14 @@ install: $(HEADERS)
 	install -d $(DESTDIR)@includedir@/mdds/hash_container
 	install -d $(DESTDIR)@includedir@/mdds/compat
 	install -d $(DESTDIR)@docdir@
-	install -m 644 -t $(DESTDIR)@includedir@/mdds $(INCDIR)/mdds/*.hpp
-	install -m 644 -t $(DESTDIR)@includedir@/mdds $(INCDIR)/mdds/*.inl
-	install -m 644 -t $(DESTDIR)@includedir@/mdds/compat $(INCDIR)/mdds/compat/*.hpp
-	install -m 644 -t $(DESTDIR)@includedir@/mdds/hash_container $(INCDIR)/mdds/hash_container/*.hpp
-	install -m 644 -t $(DESTDIR)@docdir@ AUTHORS COPYING NEWS README VERSION
+	install -d $(DESTDIR)@datarootdir@
+	install -d $(DESTDIR)@datarootdir@/pkgconfig
+	install -m 644 -t $(DESTDIR)@includedir@/mdds @top_srcdir@/$(INCDIR)/mdds/*.hpp
+	install -m 644 -t $(DESTDIR)@includedir@/mdds @top_srcdir@/$(INCDIR)/mdds/*.inl
+	install -m 644 -t $(DESTDIR)@includedir@/mdds/compat @top_srcdir@/$(INCDIR)/mdds/compat/*.hpp
+	install -m 644 -t $(DESTDIR)@includedir@/mdds/hash_container @top_srcdir@/$(INCDIR)/mdds/hash_container/*.hpp
+	install -m 644 -t $(DESTDIR)@datarootdir@/pkgconfig $(MISCDIR)/mdds.pc
+	install -m 644 -t $(DESTDIR)@docdir@ @top_srcdir@/AUTHORS @top_srcdir@/COPYING @top_srcdir@/NEWS @top_srcdir@/README @top_srcdir@/VERSION
 
 check: $(ALL_TESTS)
 
diff --git a/NEWS b/NEWS
index a0d4491..3863506 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,33 @@
+mdds 0.8.0
+
+* all
+
+  * added .pc file for pkg-config.
+
+* flat_segment_tree
+
+  * changed the return type of search_tree from bool to
+    std::pair<const_iterator,bool>, to make it consistent with the
+    search() method.  Note that this is an API-incompatible change.
+
+* multi_type_vector
+
+  * added char and unsigned char types to the standard types supported
+    by default.
+
+  * added position() member method that takes a logical element
+    position and returns a pair of block iterator where the element
+    resides and its offset within that block.
+
+  * added at() static member method to the data block, which calls the
+    at() method of the underlying std::vector container.
+
+  * added release() member method to allow caller to release an object
+    stored inside a managed block.
+
+  * added two templates to ease creation of custom element block
+    functions when using one or two custom element types.
+
 mdds 0.7.1
 
 * multi_type_vector
diff --git a/README b/README
index 084c55a..4f08fd5 100644
--- a/README
+++ b/README
@@ -68,6 +68,16 @@ directory on how to use these data structures.
 API Incompatibility Note
 ========================
 
+0.7.1 to 0.8.0
+
+flat_segment_tree
+
+* The search_tree() method in 0.8.0 returns std::pair<const_iterator,
+  bool> instead of just returning bool as of 0.7.1.  If you use this
+  method and relies on the return value of the old version, use the
+  second parameter of the new return value which is equivalent of the
+  previous return value.
+
 0.4.0 to 0.5.0
 
 flat_segment_tree
diff --git a/configure b/configure
index 0bb3dcc..97b90dd 100755
--- a/configure
+++ b/configure
@@ -1,11 +1,13 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for mdds 0.7.1.
+# Generated by GNU Autoconf 2.68 for mdds 0.8.0.
 #
 # Report bugs to <kohei.yoshida@gmail.com>.
 #
 #
-# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
 #
 #
 # This configure script is free software; the Free Software Foundation
@@ -134,31 +136,6 @@ export LANGUAGE
 # CDPATH.
 (unset CDPATH) >/dev/null 2>&1 && unset CDPATH
 
-# Use a proper internal environment variable to ensure we don't fall
-  # into an infinite loop, continuously re-executing ourselves.
-  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
-    _as_can_reexec=no; export _as_can_reexec;
-    # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
-  *v*x* | *x*v* ) as_opts=-vx ;;
-  *v* ) as_opts=-v ;;
-  *x* ) as_opts=-x ;;
-  * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-as_fn_exit 255
-  fi
-  # We don't want this to propagate to other subprocesses.
-          { _as_can_reexec=; unset _as_can_reexec;}
 if test "x$CONFIG_SHELL" = x; then
   as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
@@ -192,8 +169,7 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
 else
   exitcode=1; echo positional parameters were not saved.
 fi
-test x\$exitcode = x0 || exit 1
-test -x / || exit 1"
+test x\$exitcode = x0 || exit 1"
   as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
   as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
   eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
@@ -237,25 +213,21 @@ IFS=$as_save_IFS
 
 
       if test "x$CONFIG_SHELL" != x; then :
-  export CONFIG_SHELL
-             # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
-  *v*x* | *x*v* ) as_opts=-vx ;;
-  *v* ) as_opts=-v ;;
-  *x* ) as_opts=-x ;;
-  * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
+  # We cannot yet assume a decent shell, so we have to provide a
+	# neutralization value for shells without unset; and this also
+	# works around shells that cannot unset nonexistent variables.
+	# Preserve -v and -x to the replacement shell.
+	BASH_ENV=/dev/null
+	ENV=/dev/null
+	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+	export CONFIG_SHELL
+	case $- in # ((((
+	  *v*x* | *x*v* ) as_opts=-vx ;;
+	  *v* ) as_opts=-v ;;
+	  *x* ) as_opts=-x ;;
+	  * ) as_opts= ;;
+	esac
+	exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
 fi
 
     if test x$as_have_required = xno; then :
@@ -358,14 +330,6 @@ $as_echo X"$as_dir" |
 
 
 } # as_fn_mkdir_p
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
-  test -f "$1" && test -x "$1"
-} # as_fn_executable_p
 # as_fn_append VAR VALUE
 # ----------------------
 # Append the text in VALUE to the end of the definition contained in VAR. Take
@@ -487,10 +451,6 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
   chmod +x "$as_me.lineno" ||
     { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
 
-  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
-  # already done that, so ensure we don't try to do so again and fall
-  # in an infinite loop.  This has already happened in practice.
-  _as_can_reexec=no; export _as_can_reexec
   # Don't try to exec as it changes $[0], causing all sort of problems
   # (the dirname of $[0] is not the place where we might find the
   # original and so on.  Autoconf is especially sensitive to this).
@@ -525,16 +485,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -pR'.
+    # In both cases, we have to default to `cp -p'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -pR'
+      as_ln_s='cp -p'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -pR'
+    as_ln_s='cp -p'
   fi
 else
-  as_ln_s='cp -pR'
+  as_ln_s='cp -p'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -546,8 +506,28 @@ else
   as_mkdir_p=false
 fi
 
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -579,8 +559,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='mdds'
 PACKAGE_TARNAME='mdds'
-PACKAGE_VERSION='0.7.1'
-PACKAGE_STRING='mdds 0.7.1'
+PACKAGE_VERSION='0.8.0'
+PACKAGE_STRING='mdds 0.8.0'
 PACKAGE_BUGREPORT='kohei.yoshida@gmail.com'
 PACKAGE_URL=''
 
@@ -589,6 +569,7 @@ LIBOBJS
 CPPFLAGS_NODEBUG
 CPPFLAGS
 QUICKCHECKDIR
+MISCDIR
 INCDIR
 SRCDIR
 OBJDIR
@@ -1094,6 +1075,8 @@ target=$target_alias
 if test "x$host_alias" != x; then
   if test "x$build_alias" = x; then
     cross_compiling=maybe
+    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used" >&2
   elif test "x$build_alias" != "x$host_alias"; then
     cross_compiling=yes
   fi
@@ -1179,7 +1162,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures mdds 0.7.1 to adapt to many kinds of systems.
+\`configure' configures mdds 0.8.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1240,7 +1223,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of mdds 0.7.1:";;
+     short | recursive ) echo "Configuration of mdds 0.8.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1324,10 +1307,10 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-mdds configure 0.7.1
-generated by GNU Autoconf 2.69
+mdds configure 0.8.0
+generated by GNU Autoconf 2.68
 
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
 This configure script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it.
 _ACEOF
@@ -1341,8 +1324,8 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by mdds $as_me 0.7.1, which was
-generated by GNU Autoconf 2.69.  Invocation command line was
+It was created by mdds $as_me 0.8.0, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
 
   $ $0 $@
 
@@ -1690,7 +1673,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
 
-VERSION=0.7.1
+VERSION=0.8.0
 
 
 PACKAGE_TARNAME=mdds
@@ -1710,10 +1693,12 @@ $as_echo_n "checking hash container type... " >&6; }
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_hash_container" >&5
 $as_echo "$with_hash_container" >&6; }
 
-OBJDIR=./obj
-SRCDIR=./src
-INCDIR=./include
-QUICKCHECKDIR=./quickcheck
+OBJDIR=obj
+SRCDIR=src
+INCDIR=include
+MISCDIR=misc
+QUICKCHECKDIR=quickcheck
+
 
 
 
@@ -1726,7 +1711,7 @@ elif test $with_hash_container = boost; then
   CPPFLAGS_NODEBUG="$CPPFLAGS_NODEBUG -DMDDS_HASH_CONTAINER_BOOST"
 fi
 
-CPPFLAGS="$CPPFLAGS_NODEBUG -DDEBUG_NODE_BASE -DUNIT_TEST -std=c++0x"
+CPPFLAGS="$CPPFLAGS_NODEBUG -DMDDS_DEBUG_NODE_BASE -DMDDS_UNIT_TEST -std=c++0x"
 
 
 
@@ -2175,16 +2160,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -pR'.
+    # In both cases, we have to default to `cp -p'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -pR'
+      as_ln_s='cp -p'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -pR'
+    as_ln_s='cp -p'
   fi
 else
-  as_ln_s='cp -pR'
+  as_ln_s='cp -p'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -2244,16 +2229,28 @@ else
   as_mkdir_p=false
 fi
 
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
-  test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -2274,8 +2271,8 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by mdds $as_me 0.7.1, which was
-generated by GNU Autoconf 2.69.  Invocation command line was
+This file was extended by mdds $as_me 0.8.0, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -2327,11 +2324,11 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-mdds config.status 0.7.1
-configured by $0, generated by GNU Autoconf 2.69,
+mdds config.status 0.8.0
+configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
@@ -2408,7 +2405,7 @@ fi
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 if \$ac_cs_recheck; then
-  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
   shift
   \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
   CONFIG_SHELL='$SHELL'
@@ -3332,16 +3329,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -pR'.
+    # In both cases, we have to default to `cp -p'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -pR'
+      as_ln_s='cp -p'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -pR'
+    as_ln_s='cp -p'
   fi
 else
-  as_ln_s='cp -pR'
+  as_ln_s='cp -p'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -3401,16 +3398,28 @@ else
   as_mkdir_p=false
 fi
 
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
-  test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -3431,8 +3440,8 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by mdds $as_me 0.7.1, which was
-generated by GNU Autoconf 2.69.  Invocation command line was
+This file was extended by mdds $as_me 0.8.0, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -3484,11 +3493,11 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-mdds config.status 0.7.1
-configured by $0, generated by GNU Autoconf 2.69,
+mdds config.status 0.8.0
+configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
@@ -3565,7 +3574,7 @@ fi
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 if \$ac_cs_recheck; then
-  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
   shift
   \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
   CONFIG_SHELL='$SHELL'
@@ -4490,16 +4499,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -pR'.
+    # In both cases, we have to default to `cp -p'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -pR'
+      as_ln_s='cp -p'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -pR'
+    as_ln_s='cp -p'
   fi
 else
-  as_ln_s='cp -pR'
+  as_ln_s='cp -p'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -4559,16 +4568,28 @@ else
   as_mkdir_p=false
 fi
 
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
-  test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -4589,8 +4610,8 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by mdds $as_me 0.7.1, which was
-generated by GNU Autoconf 2.69.  Invocation command line was
+This file was extended by mdds $as_me 0.8.0, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -4642,11 +4663,11 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-mdds config.status 0.7.1
-configured by $0, generated by GNU Autoconf 2.69,
+mdds config.status 0.8.0
+configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
@@ -4723,7 +4744,7 @@ fi
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 if \$ac_cs_recheck; then
-  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
   shift
   \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
   CONFIG_SHELL='$SHELL'
@@ -5204,7 +5225,7 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
 fi
 
-ac_config_files="$ac_config_files VERSION"
+ac_config_files="$ac_config_files misc/mdds.pc"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -5649,16 +5670,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -pR'.
+    # In both cases, we have to default to `cp -p'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -pR'
+      as_ln_s='cp -p'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -pR'
+    as_ln_s='cp -p'
   fi
 else
-  as_ln_s='cp -pR'
+  as_ln_s='cp -p'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -5718,16 +5739,1200 @@ else
   as_mkdir_p=false
 fi
 
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by mdds $as_me 0.8.0, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to <kohei.yoshida@gmail.com>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+mdds config.status 0.8.0
+configured by $0, generated by GNU Autoconf 2.68,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h |  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "example/Makefile") CONFIG_FILES="$CONFIG_FILES example/Makefile" ;;
+    "misc/mdds.spec") CONFIG_FILES="$CONFIG_FILES misc/mdds.spec" ;;
+    "misc/mdds.pc") CONFIG_FILES="$CONFIG_FILES misc/mdds.pc" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
 
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
 {
-  test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X "  :F $CONFIG_FILES      "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+  esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+ac_config_files="$ac_config_files VERSION"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section.  Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*([^)]*)\)[	 ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[	 `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+	g
+	s/^\n//
+	s/\n/ /g
+	p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -5748,8 +6953,8 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by mdds $as_me 0.7.1, which was
-generated by GNU Autoconf 2.69.  Invocation command line was
+This file was extended by mdds $as_me 0.8.0, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -5801,11 +7006,11 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-mdds config.status 0.7.1
-configured by $0, generated by GNU Autoconf 2.69,
+mdds config.status 0.8.0
+configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
@@ -5882,7 +7087,7 @@ fi
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 if \$ac_cs_recheck; then
-  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
   shift
   \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
   CONFIG_SHELL='$SHELL'
@@ -5914,6 +7119,7 @@ do
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
     "example/Makefile") CONFIG_FILES="$CONFIG_FILES example/Makefile" ;;
     "misc/mdds.spec") CONFIG_FILES="$CONFIG_FILES misc/mdds.spec" ;;
+    "misc/mdds.pc") CONFIG_FILES="$CONFIG_FILES misc/mdds.pc" ;;
     "VERSION") CONFIG_FILES="$CONFIG_FILES VERSION" ;;
 
   *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
diff --git a/configure.ac b/configure.ac
index 0c87941..0458f69 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(mdds, 0.7.1, kohei.yoshida@gmail.com)
+AC_INIT(mdds, 0.8.0, kohei.yoshida@gmail.com)
 
 VERSION=AC_PACKAGE_VERSION
 AC_SUBST(VERSION)
@@ -25,13 +25,15 @@ AC_ARG_WITH(hash-container,
 AC_MSG_CHECKING([hash container type])
 AC_MSG_RESULT([$with_hash_container])
 
-OBJDIR=./obj
-SRCDIR=./src
-INCDIR=./include
-QUICKCHECKDIR=./quickcheck
+OBJDIR=obj
+SRCDIR=src
+INCDIR=include
+MISCDIR=misc
+QUICKCHECKDIR=quickcheck
 AC_SUBST(OBJDIR)
 AC_SUBST(SRCDIR)
 AC_SUBST(INCDIR)
+AC_SUBST(MISCDIR)
 AC_SUBST(QUICKCHECKDIR)
 
 CPPFLAGS_NODEBUG="-Wall -Os -g -pedantic-errors"
@@ -41,11 +43,12 @@ elif test $with_hash_container = boost; then
   CPPFLAGS_NODEBUG="$CPPFLAGS_NODEBUG -DMDDS_HASH_CONTAINER_BOOST"
 fi
 
-CPPFLAGS="$CPPFLAGS_NODEBUG -DDEBUG_NODE_BASE -DUNIT_TEST -std=c++0x"
+CPPFLAGS="$CPPFLAGS_NODEBUG -DMDDS_DEBUG_NODE_BASE -DMDDS_UNIT_TEST -std=c++0x"
 AC_SUBST(CPPFLAGS)
 AC_SUBST(CPPFLAGS_NODEBUG)
 
 AC_OUTPUT(Makefile)
 AC_OUTPUT(example/Makefile)
 AC_OUTPUT(misc/mdds.spec)
+AC_OUTPUT(misc/mdds.pc)
 AC_OUTPUT(VERSION)
diff --git a/include/mdds/flat_segment_tree.hpp b/include/mdds/flat_segment_tree.hpp
index 2b2b937..481b9c0 100644
--- a/include/mdds/flat_segment_tree.hpp
+++ b/include/mdds/flat_segment_tree.hpp
@@ -37,7 +37,7 @@
 #include "node.hpp"
 #include "flat_segment_tree_itr.hpp"
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
 #include <cstdio>
 #include <vector>
 #endif
@@ -344,7 +344,6 @@ public:
      * @return a pair of const_iterator corresponding to the start position of
      *         the segment containing the key, and a boolean value indicating
      *         whether or not the search has been successful.
-     * 
      */
     ::std::pair<const_iterator, bool>
     search(const const_iterator& pos, key_type key, value_type& value, key_type* start_key = NULL, key_type* end_key = NULL) const;
@@ -362,11 +361,12 @@ public:
      * @param end_key pointer to a varaible where the end key value of the
      *                segment that contains the key gets stored upon
      *                successful search.
-     * @return a boolean value indicating whether or not the search has been
-     *         successful.
-     * 
+     * @return a pair of const_iterator corresponding to the start position of
+     *         the segment containing the key, and a boolean value indicating
+     *         whether or not the search has been successful.
      */
-    bool search_tree(key_type key, value_type& value, key_type* start_key = NULL, key_type* end_key = NULL) const;
+    std::pair<const_iterator, bool>
+    search_tree(key_type key, value_type& value, key_type* start_key = NULL, key_type* end_key = NULL) const;
 
     void build_tree();
 
@@ -402,7 +402,7 @@ public:
         return m_init_val;
     }
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
     node_ptr get_root_node() const
     {
         return m_root_node;
@@ -544,7 +544,7 @@ private:
             return;
         }
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
         // The start position must come after the position of the last node 
         // before the right-most node.
         assert(m_right_leaf->left->value_leaf.key < start_key);        
diff --git a/include/mdds/flat_segment_tree_def.inl b/include/mdds/flat_segment_tree_def.inl
index 91add6c..5158c3c 100644
--- a/include/mdds/flat_segment_tree_def.inl
+++ b/include/mdds/flat_segment_tree_def.inl
@@ -565,19 +565,21 @@ flat_segment_tree<_Key, _Value>::search(const const_iterator& pos,
 }
 
 template<typename _Key, typename _Value>
-bool flat_segment_tree<_Key, _Value>::search_tree(
+std::pair<typename flat_segment_tree<_Key, _Value>::const_iterator, bool>
+flat_segment_tree<_Key, _Value>::search_tree(
     key_type key, value_type& value, key_type* start_key, key_type* end_key) const
 {
+    typedef std::pair<const_iterator, bool> ret_type;
     if (!m_root_node || !m_valid_tree)
     {    
         // either tree has not been built, or is in an invalid state.
-        return false;
+        return ret_type(const_iterator(this, true), false);
     }
 
     if (key < m_left_leaf->value_leaf.key || m_right_leaf->value_leaf.key <= key)
     {    
         // key value is out-of-bound.
-        return false;
+        return ret_type(const_iterator(this, true), false);
     }
 
     // Descend down the tree through the last non-leaf layer.
@@ -600,7 +602,7 @@ bool flat_segment_tree<_Key, _Value>::search_tree(
         else
         {    
             // left child node can't be missing !
-            return false;
+            return ret_type(const_iterator(this, true), false);
         }
 
         if (cur_node->right)
@@ -612,7 +614,7 @@ bool flat_segment_tree<_Key, _Value>::search_tree(
                 continue;
             }
         }
-        return false;
+        return ret_type(const_iterator(this, true), false);
     }
 
     assert(cur_node->left->is_leaf && cur_node->right->is_leaf);
@@ -633,7 +635,7 @@ bool flat_segment_tree<_Key, _Value>::search_tree(
 
     if (!cur_node)
     {    
-        return false;
+        return ret_type(const_iterator(this, true), false);
     }
 
     value = cur_node->value_leaf.value;
@@ -650,7 +652,7 @@ bool flat_segment_tree<_Key, _Value>::search_tree(
             *end_key = m_right_leaf->value_leaf.key;
     }
 
-    return true;
+    return ret_type(const_iterator(this, cur_node), true);
 }
 
 template<typename _Key, typename _Value>
diff --git a/include/mdds/mixed_type_matrix.hpp b/include/mdds/mixed_type_matrix.hpp
index e3f2fcd..ca037b8 100644
--- a/include/mdds/mixed_type_matrix.hpp
+++ b/include/mdds/mixed_type_matrix.hpp
@@ -215,7 +215,7 @@ public:
      */
     void swap(mixed_type_matrix& r);
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
     void dump() const;
     void dump_flags() const;
     size_pair_type get_storage_size() const;
diff --git a/include/mdds/mixed_type_matrix_def.inl b/include/mdds/mixed_type_matrix_def.inl
index 2c33799..99c7d18 100644
--- a/include/mdds/mixed_type_matrix_def.inl
+++ b/include/mdds/mixed_type_matrix_def.inl
@@ -262,7 +262,7 @@ void mixed_type_matrix<_String,_Flag>::swap(mixed_type_matrix& r)
     m_cached_size = temp;
 }
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
 template<typename _String, typename _Flag>
 void mixed_type_matrix<_String,_Flag>::dump() const
 {
diff --git a/include/mdds/mixed_type_matrix_flag_storage.hpp b/include/mdds/mixed_type_matrix_flag_storage.hpp
index 3a9f7a1..380557c 100644
--- a/include/mdds/mixed_type_matrix_flag_storage.hpp
+++ b/include/mdds/mixed_type_matrix_flag_storage.hpp
@@ -25,7 +25,7 @@
  *
  ************************************************************************/
 
-#if UNIT_TEST
+#ifdef MDDS_UNIT_TEST
 #include <iostream>
 #endif
 
@@ -74,7 +74,7 @@ public:
             // Flag is stored at this position.  Remove it.
             m_flags.erase(itr);
     }
-#if UNIT_TEST
+#ifdef MDDS_UNIT_TEST
     void dump() const
     {
         using namespace std;
diff --git a/include/mdds/multi_type_vector.hpp b/include/mdds/multi_type_vector.hpp
index 8eb71ed..cefb8c4 100644
--- a/include/mdds/multi_type_vector.hpp
+++ b/include/mdds/multi_type_vector.hpp
@@ -205,7 +205,7 @@ public:
      *         inserted.
      */
     template<typename _T>
-    iterator set(iterator pos_hint, size_type pos, const _T& value);
+    iterator set(const iterator& pos_hint, size_type pos, const _T& value);
 
     /**
      * Set multiple values of identical type to a range of elements starting
@@ -269,7 +269,7 @@ public:
      *         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);
+    iterator set(const iterator& pos_hint, size_type pos, const _T& it_begin, const _T& it_end);
 
     /**
      * Insert multiple values of identical type to a specified position.
@@ -333,7 +333,7 @@ public:
      *         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);
+    iterator insert(const 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
@@ -356,12 +356,116 @@ public:
      * <p>The method will throw an <code>std::out_of_range</code> exception if
      * the specified position is outside the current container range.</p>
      *
-     * @param position position of the element value to retrieve.
+     * @param pos position of the element value to retrieve.
      * @return element value.
      */
     template<typename _T>
     _T get(size_type pos) const;
 
+    /**
+     * Return the value of an element at specified position and set that
+     * position empty.  If the element resides in a managed block, this call
+     * will <i>not</i> delete that element.  If the element is on a
+     * non-managed block, this call is equivalent to set_empty(pos, pos).
+     *
+     * <p>The method will throw an <code>std::out_of_range</code> exception if
+     * the specified position is outside the current container range.</p>
+     *
+     * @param pos position of the element to release.
+     *
+     * @return element value.
+     */
+    template<typename _T>
+    _T release(size_type pos);
+
+    /**
+     * Given the logical position of an element, get the iterator of the block
+     * where the element is located, and its offset from the first element of
+     * that block.
+     *
+     * <p>The method will throw an <code>std::out_of_range</code> exception if
+     * the specified position is outside the current container range.</p>
+     *
+     * @param pos position of the element.
+     * @return iterator referencing the block where the element resides, and
+     *         its offset within the block.
+     */
+    std::pair<iterator, size_type> position(size_type pos);
+
+    /**
+     * Given the logical position of an element, get the iterator of the block
+     * where the element is located, and its offset from the first element of
+     * that block.
+     *
+     * <p>The method will throw an <code>std::out_of_range</code> exception if
+     * the specified position is outside the current container range.</p>
+     *
+     * @param pos position of the element.
+     * @return iterator referencing the block where the element resides, and
+     *         its offset within the block.
+     */
+    std::pair<const_iterator, size_type> position(size_type pos) const;
+
+    /**
+     * Move elements from one container to another. After the move, the
+     * segment where the elements were in the original container becomes
+     * empty.  When transferring managed elements, this call transfers
+     * ownership of the moved elements to the new container.  The moved
+     * elements will overwrite any existing elements in the destination range.
+     * Transfer of elements within the same container is not allowed.
+     *
+     * <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, or the destination container is not large enough to
+     * accommodate the transferred elements.</p>
+     *
+     * @param start_pos starting position
+     * @param end_pos ending position, inclusive.
+     * @param dest destination container to which the elements are to be
+     *             moved.
+     * @param dest_pos position in the destination container to which the
+     *                 elements are to be moved.
+     *
+     * @return iterator referencing the block where the moved elements were
+     *         prior to the transfer.
+     */
+    iterator transfer(size_type start_pos, size_type end_pos, multi_type_vector& dest, size_type dest_pos);
+
+    /**
+     * Move elements from one container to another. After the move, the
+     * segment where the elements were in the original container becomes
+     * empty.  When transferring managed elements, this call transfers
+     * ownership of the moved elements to the new container.  The moved
+     * elements will overwrite any existing elements in the destination range.
+     * Transfer of elements within the same container is not allowed.
+     *
+     * <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, or the destination container is not large enough to
+     * accommodate the transferred elements.</p>
+     *
+     * @param pos_hint iterator used as a block position hint, to specify
+     *                 which block to start when searching for the blocks
+     *                 where the elements to be transferred reside.
+     * @param start_pos starting position
+     * @param end_pos ending position, inclusive.
+     * @param dest destination container to which the elements are to be
+     *             moved.
+     * @param dest_pos position in the destination container to which the
+     *                 elements are to be moved.
+     *
+     * @return iterator referencing the block where the moved elements were
+     *         prior to the transfer.
+     */
+    iterator transfer(const iterator& pos_hint, size_type start_pos, size_type end_pos, multi_type_vector& dest, size_type dest_pos);
+
+    /**
+     * Get the type of an element at specified position.
+     *
+     * @param pos position of the element.
+     *
+     * @return element type.
+     */
     mtv::element_t get_type(size_type pos) const;
 
     /**
@@ -420,7 +524,7 @@ public:
      * @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);
+    iterator set_empty(const iterator& pos_hint, size_type start_pos, size_type end_pos);
 
     /**
      * Erase elements located between specified start and end positions. The
@@ -488,7 +592,7 @@ public:
      *         is inserted. When no insertion occurs because the length is
      *         zero, the end iterator position is returned.
      */
-    iterator insert_empty(iterator pos_hint, size_type pos, size_type length);
+    iterator insert_empty(const iterator& pos_hint, size_type pos, size_type length);
 
     /**
      * Clear the content of the container.  The size of the container will
@@ -557,6 +661,10 @@ public:
     template<typename _T>
     static mtv::element_t get_element_type(const _T& elem);
 
+#ifdef MDDS_UNIT_TEST
+    void dump_blocks() const;
+#endif
+
 private:
 
     template<typename _T>
@@ -587,7 +695,7 @@ private:
      * 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;
+    void get_block_position(const 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);
@@ -615,17 +723,26 @@ private:
     void set_cell_to_bottom_of_data_block(
         size_type block_index, const _T& cell);
 
+    iterator transfer_impl(
+        size_type start_pos, size_type end_pos, size_type start_pos_in_block1, size_type block_index1,
+        multi_type_vector& dest, size_type dest_pos);
+
+    iterator transfer_single_block(
+        size_type start_pos, size_type end_pos, size_type start_pos_in_block1, size_type block_index1,
+        multi_type_vector& dest, size_type dest_pos);
+
     iterator set_empty_impl(size_type start_pos, size_type end_pos, size_type start_pos_in_block1, size_type block_index1);
 
-    iterator set_whole_block_empty(size_type block_index, size_type start_pos_in_block);
+    iterator set_whole_block_empty(size_type block_index, size_type start_pos_in_block, bool overwrite);
 
     iterator set_empty_in_single_block(
-        size_type start_pos, size_type end_pos, size_type block_index, size_type start_pos_in_block);
+        size_type start_pos, size_type end_pos, size_type block_index, size_type start_pos_in_block,
+        bool overwrite);
 
     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);
+        size_type block_index2, size_type start_pos_in_block2, bool overwrite);
 
     void erase_impl(size_type start_pos, size_type end_pos);
 
@@ -668,7 +785,24 @@ private:
         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);
+    /**
+     * Merge with previous or next block as needed.
+     *
+     * @param block_index index of the block that may need merging.
+     *
+     * @return size of previous block if the block is merged with the previous
+     *         block, or 0 if it didn't merge with the previous block.
+     */
+    size_type merge_with_adjacent_blocks(size_type block_index);
+
+    /**
+     * Merge only with the next block if the two are of the same type.
+     *
+     * @param block_index index of the block that may need merging.
+     *
+     * @return true if merge occurs, false otherwise.
+     */
+    bool merge_with_next_block(size_type block_index);
 
     template<typename _T>
     bool append_to_prev_block(
diff --git a/include/mdds/multi_type_vector_custom_func1.hpp b/include/mdds/multi_type_vector_custom_func1.hpp
new file mode 100644
index 0000000..f67c896
--- /dev/null
+++ b/include/mdds/multi_type_vector_custom_func1.hpp
@@ -0,0 +1,200 @@
+/*************************************************************************
+ *
+ * Copyright (c) 2013 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
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * 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
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ************************************************************************/
+
+#ifndef MDDS_MULTI_TYPE_VECTOR_CUSTOM_FUNC1_HPP
+#define MDDS_MULTI_TYPE_VECTOR_CUSTOM_FUNC1_HPP
+
+#include "multi_type_vector_types.hpp"
+#include "multi_type_vector_trait.hpp"
+
+namespace mdds { namespace mtv {
+
+/**
+ * Block function template for multi_type_vector with 1 user-defined block.
+ */
+template<element_t _TypeId, typename _Block>
+struct custom_block_func1
+{
+    static base_element_block* create_new_block(element_t type, size_t init_size)
+    {
+        switch (type)
+        {
+            case _TypeId:
+                return _Block::create_block(init_size);
+            default:
+                ;
+        }
+
+        return element_block_func::create_new_block(type, init_size);
+    }
+
+    static base_element_block* clone_block(const base_element_block& block)
+    {
+        switch (get_block_type(block))
+        {
+            case _TypeId:
+                return _Block::clone_block(block);
+            default:
+                ;
+        }
+
+        return element_block_func::clone_block(block);
+    }
+
+    static void delete_block(base_element_block* p)
+    {
+        if (!p)
+            return;
+
+        switch (get_block_type(*p))
+        {
+            case _TypeId:
+                _Block::delete_block(p);
+            break;
+            default:
+                element_block_func::delete_block(p);
+        }
+    }
+
+    static void resize_block(base_element_block& block, size_t new_size)
+    {
+        switch (get_block_type(block))
+        {
+            case _TypeId:
+                _Block::resize_block(block, new_size);
+            break;
+            default:
+                element_block_func::resize_block(block, new_size);
+        }
+    }
+
+    static void print_block(const base_element_block& block)
+    {
+        switch (get_block_type(block))
+        {
+            case _TypeId:
+                _Block::print_block(block);
+            break;
+            default:
+                element_block_func::print_block(block);
+        }
+    }
+
+    static void erase(base_element_block& block, size_t pos)
+    {
+        switch (get_block_type(block))
+        {
+            case _TypeId:
+                _Block::erase_block(block, pos);
+            break;
+            default:
+                element_block_func::erase(block, pos);
+        }
+    }
+
+    static void erase(base_element_block& block, size_t pos, size_t size)
+    {
+        switch (get_block_type(block))
+        {
+            case _TypeId:
+                _Block::erase_block(block, pos, size);
+            break;
+            default:
+                element_block_func_base::erase(block, pos, size);
+        }
+    }
+
+    static void append_values_from_block(base_element_block& dest, const base_element_block& src)
+    {
+        switch (get_block_type(dest))
+        {
+            case _TypeId:
+                _Block::append_values_from_block(dest, src);
+            break;
+            default:
+                element_block_func_base::append_values_from_block(dest, src);
+        }
+    }
+
+    static void append_values_from_block(
+        base_element_block& dest, const base_element_block& src, size_t begin_pos, size_t len)
+    {
+        switch (get_block_type(dest))
+        {
+            case _TypeId:
+                _Block::append_values_from_block(dest, src, begin_pos, len);
+            break;
+            default:
+                element_block_func_base::append_values_from_block(dest, src, begin_pos, len);
+        }
+    }
+
+    static void assign_values_from_block(
+        base_element_block& dest, const base_element_block& src, size_t begin_pos, size_t len)
+    {
+        switch (get_block_type(dest))
+        {
+            case _TypeId:
+                _Block::assign_values_from_block(dest, src, begin_pos, len);
+            break;
+            default:
+                element_block_func_base::assign_values_from_block(dest, src, begin_pos, len);
+        }
+    }
+
+    static bool equal_block(
+        const base_element_block& left, const base_element_block& right)
+    {
+        if (get_block_type(left) == _TypeId)
+        {
+            if (get_block_type(right) != _TypeId)
+                return false;
+
+            return _Block::get(left) == _Block::get(right);
+        }
+        else if (mtv::get_block_type(right) == _TypeId)
+            return false;
+
+        return element_block_func::equal_block(left, right);
+    }
+
+    static void overwrite_values(base_element_block& block, size_t pos, size_t len)
+    {
+        switch (get_block_type(block))
+        {
+            case _TypeId:
+                _Block::overwrite_values(block, pos, len);
+            break;
+            default:
+                element_block_func::overwrite_values(block, pos, len);
+        }
+    }
+};
+
+}}
+
+#endif
diff --git a/include/mdds/multi_type_vector_custom_func2.hpp b/include/mdds/multi_type_vector_custom_func2.hpp
new file mode 100644
index 0000000..5b2c146
--- /dev/null
+++ b/include/mdds/multi_type_vector_custom_func2.hpp
@@ -0,0 +1,241 @@
+/*************************************************************************
+ *
+ * Copyright (c) 2013 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
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * 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
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ************************************************************************/
+
+#ifndef MDDS_MULTI_TYPE_VECTOR_CUSTOM_FUNC2_HPP
+#define MDDS_MULTI_TYPE_VECTOR_CUSTOM_FUNC2_HPP
+
+#include "multi_type_vector_types.hpp"
+#include "multi_type_vector_trait.hpp"
+
+namespace mdds { namespace mtv {
+
+/**
+ * Block function template for multi_type_vector with 1 user-defined block.
+ */
+template<element_t _TypeId1, typename _Block1, element_t _TypeId2, typename _Block2>
+struct custom_block_func2
+{
+    static base_element_block* create_new_block(element_t type, size_t init_size)
+    {
+        switch (type)
+        {
+            case _TypeId1:
+                return _Block1::create_block(init_size);
+            case _TypeId2:
+                return _Block2::create_block(init_size);
+            default:
+                ;
+        }
+
+        return element_block_func::create_new_block(type, init_size);
+    }
+
+    static base_element_block* clone_block(const base_element_block& block)
+    {
+        switch (get_block_type(block))
+        {
+            case _TypeId1:
+                return _Block1::clone_block(block);
+            case _TypeId2:
+                return _Block2::clone_block(block);
+            default:
+                ;
+        }
+
+        return element_block_func::clone_block(block);
+    }
+
+    static void delete_block(base_element_block* p)
+    {
+        if (!p)
+            return;
+
+        switch (get_block_type(*p))
+        {
+            case _TypeId1:
+                _Block1::delete_block(p);
+            break;
+            case _TypeId2:
+                _Block2::delete_block(p);
+            break;
+            default:
+                element_block_func::delete_block(p);
+        }
+    }
+
+    static void resize_block(base_element_block& block, size_t new_size)
+    {
+        switch (get_block_type(block))
+        {
+            case _TypeId1:
+                _Block1::resize_block(block, new_size);
+            break;
+            case _TypeId2:
+                _Block2::resize_block(block, new_size);
+            break;
+            default:
+                element_block_func::resize_block(block, new_size);
+        }
+    }
+
+    static void print_block(const base_element_block& block)
+    {
+        switch (get_block_type(block))
+        {
+            case _TypeId1:
+                _Block1::print_block(block);
+            break;
+            case _TypeId2:
+                _Block2::print_block(block);
+            break;
+            default:
+                element_block_func::print_block(block);
+        }
+    }
+
+    static void erase(base_element_block& block, size_t pos)
+    {
+        switch (get_block_type(block))
+        {
+            case _TypeId1:
+                _Block1::erase_block(block, pos);
+            break;
+            case _TypeId2:
+                _Block2::erase_block(block, pos);
+            break;
+            default:
+                element_block_func::erase(block, pos);
+        }
+    }
+
+    static void erase(base_element_block& block, size_t pos, size_t size)
+    {
+        switch (get_block_type(block))
+        {
+            case _TypeId1:
+                _Block1::erase_block(block, pos, size);
+            break;
+            case _TypeId2:
+                _Block2::erase_block(block, pos, size);
+            break;
+            default:
+                element_block_func_base::erase(block, pos, size);
+        }
+    }
+
+    static void append_values_from_block(base_element_block& dest, const base_element_block& src)
+    {
+        switch (get_block_type(dest))
+        {
+            case _TypeId1:
+                _Block1::append_values_from_block(dest, src);
+            break;
+            case _TypeId2:
+                _Block2::append_values_from_block(dest, src);
+            break;
+            default:
+                element_block_func_base::append_values_from_block(dest, src);
+        }
+    }
+
+    static void append_values_from_block(
+        base_element_block& dest, const base_element_block& src, size_t begin_pos, size_t len)
+    {
+        switch (get_block_type(dest))
+        {
+            case _TypeId1:
+                _Block1::append_values_from_block(dest, src, begin_pos, len);
+            break;
+            case _TypeId2:
+                _Block2::append_values_from_block(dest, src, begin_pos, len);
+            break;
+            default:
+                element_block_func_base::append_values_from_block(dest, src, begin_pos, len);
+        }
+    }
+
+    static void assign_values_from_block(
+        base_element_block& dest, const base_element_block& src, size_t begin_pos, size_t len)
+    {
+        switch (get_block_type(dest))
+        {
+            case _TypeId1:
+                _Block1::assign_values_from_block(dest, src, begin_pos, len);
+            break;
+            case _TypeId2:
+                _Block2::assign_values_from_block(dest, src, begin_pos, len);
+            break;
+            default:
+                element_block_func_base::assign_values_from_block(dest, src, begin_pos, len);
+        }
+    }
+
+    static bool equal_block(
+        const base_element_block& left, const base_element_block& right)
+    {
+        if (get_block_type(left) == _TypeId1)
+        {
+            if (get_block_type(right) != _TypeId1)
+                return false;
+
+            return _Block1::get(left) == _Block1::get(right);
+        }
+        else if (mtv::get_block_type(right) == _TypeId1)
+            return false;
+
+        if (get_block_type(left) == _TypeId2)
+        {
+            if (get_block_type(right) != _TypeId2)
+                return false;
+
+            return _Block2::get(left) == _Block2::get(right);
+        }
+        else if (mtv::get_block_type(right) == _TypeId2)
+            return false;
+
+        return element_block_func::equal_block(left, right);
+    }
+
+    static void overwrite_values(base_element_block& block, size_t pos, size_t len)
+    {
+        switch (get_block_type(block))
+        {
+            case _TypeId1:
+                _Block1::overwrite_values(block, pos, len);
+            break;
+            case _TypeId2:
+                _Block2::overwrite_values(block, pos, len);
+            break;
+            default:
+                element_block_func::overwrite_values(block, pos, len);
+        }
+    }
+};
+
+}}
+
+#endif
diff --git a/include/mdds/multi_type_vector_def.inl b/include/mdds/multi_type_vector_def.inl
index 32e6c99..2299a7b 100644
--- a/include/mdds/multi_type_vector_def.inl
+++ b/include/mdds/multi_type_vector_def.inl
@@ -29,7 +29,7 @@
 
 #include <stdexcept>
 
-#if UNIT_TEST
+#ifdef MDDS_UNIT_TEST
 #include <iostream>
 using std::cout;
 using std::endl;
@@ -46,6 +46,8 @@ MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(unsigned int, mtv::element_type_uint, 0, mtv::
 MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(long, mtv::element_type_long, 0, mtv::long_element_block)
 MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(unsigned long, mtv::element_type_ulong, 0, mtv::ulong_element_block)
 MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(bool, mtv::element_type_boolean, false, mtv::boolean_element_block)
+MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(char, mtv::element_type_char, 0, mtv::char_element_block)
+MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(unsigned char, mtv::element_type_uchar, 0, mtv::uchar_element_block)
 
 template<typename _CellBlockFunc>
 multi_type_vector<_CellBlockFunc>::block::block() : m_size(0), mp_data(NULL) {}
@@ -189,7 +191,7 @@ multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& value)
 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)
+multi_type_vector<_CellBlockFunc>::set(const iterator& pos_hint, size_type pos, const _T& value)
 {
     size_type start_row = 0;
     size_type block_index = 0;
@@ -377,7 +379,7 @@ multi_type_vector<_CellBlockFunc>::set(size_type pos, const _T& it_begin, const
 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)
+multi_type_vector<_CellBlockFunc>::set(const 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))
@@ -404,7 +406,7 @@ multi_type_vector<_CellBlockFunc>::insert(size_type pos, const _T& it_begin, con
 template<typename _CellBlockFunc>
 template<typename _T>
 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)
+multi_type_vector<_CellBlockFunc>::insert(const iterator& pos_hint, size_type pos, const _T& it_begin, const _T& it_end)
 {
     size_type block_index = 0, start_pos = 0;
     get_block_position(pos_hint, pos, start_pos, block_index);
@@ -435,7 +437,7 @@ bool multi_type_vector<_CellBlockFunc>::get_block_position(
 
 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
+    const iterator& pos_hint, size_type pos, size_type& start_row, size_type& block_index) const
 {
     start_row = 0;
     block_index = 0;
@@ -1057,6 +1059,96 @@ _T multi_type_vector<_CellBlockFunc>::get(size_type pos) const
 }
 
 template<typename _CellBlockFunc>
+template<typename _T>
+_T multi_type_vector<_CellBlockFunc>::release(size_type pos)
+{
+    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!");
+
+    const block* blk = m_blocks[block_index];
+    assert(blk);
+
+    _T value;
+    if (!blk->mp_data)
+    {
+        // Empty cell block.  There is no element to release.
+        mdds_mtv_get_empty_value(value);
+        return value;
+    }
+
+    assert(pos >= start_row);
+    assert(blk->mp_data); // data for non-empty blocks should never be NULL.
+    size_type idx = pos - start_row;
+    mdds_mtv_get_value(*blk->mp_data, idx, value);
+
+    // Set the element slot empty without overwriting it.
+    set_empty_in_single_block(pos, pos, block_index, start_row, false);
+    return value;
+}
+
+template<typename _CellBlockFunc>
+std::pair<typename multi_type_vector<_CellBlockFunc>::iterator, typename multi_type_vector<_CellBlockFunc>::size_type>
+multi_type_vector<_CellBlockFunc>::position(size_type pos)
+{
+    typedef std::pair<iterator, size_type> ret_type;
+
+    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!");
+
+    iterator it = get_iterator(block_index, start_row);
+    return ret_type(it, pos - start_row);
+}
+
+template<typename _CellBlockFunc>
+std::pair<typename multi_type_vector<_CellBlockFunc>::const_iterator, typename multi_type_vector<_CellBlockFunc>::size_type>
+multi_type_vector<_CellBlockFunc>::position(size_type pos) const
+{
+    typedef std::pair<const_iterator, size_type> ret_type;
+
+    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!");
+
+    typename blocks_type::const_iterator block_pos = m_blocks.begin();
+    std::advance(block_pos, block_index);
+    const_iterator it = const_iterator(block_pos, m_blocks.end(), start_row, block_index);
+    return ret_type(it, pos - start_row);
+}
+
+template<typename _CellBlockFunc>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::transfer(
+    size_type start_pos, size_type end_pos, multi_type_vector& dest, size_type dest_pos)
+{
+    if (&dest == this)
+        throw invalid_arg_error("You cannot transfer between the same container.");
+
+    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 transfer_impl(start_pos, end_pos, start_pos_in_block1, block_index1, dest, dest_pos);
+}
+
+template<typename _CellBlockFunc>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::transfer(
+    const iterator& pos_hint, size_type start_pos, size_type end_pos,
+    multi_type_vector& dest, size_type dest_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 transfer_impl(start_pos, end_pos, start_pos_in_block1, block_index1, dest, dest_pos);
+}
+
+template<typename _CellBlockFunc>
 mtv::element_t multi_type_vector<_CellBlockFunc>::get_type(size_type pos) const
 {
     size_type start_row = 0;
@@ -1096,7 +1188,7 @@ multi_type_vector<_CellBlockFunc>::set_empty(size_type start_pos, size_type end_
 
 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)
+multi_type_vector<_CellBlockFunc>::set_empty(const iterator& pos_hint, size_type start_pos, size_type end_pos)
 {
     size_type start_pos_in_block1 = 0;
     size_type block_index1 = 0;
@@ -1106,6 +1198,326 @@ multi_type_vector<_CellBlockFunc>::set_empty(iterator pos_hint, size_type start_
 
 template<typename _CellBlockFunc>
 typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::transfer_impl(
+    size_type start_pos, size_type end_pos, size_type start_pos_in_block1, size_type block_index1,
+    multi_type_vector& dest, size_type dest_pos)
+{
+    if (start_pos > end_pos)
+        throw std::out_of_range("Start row is larger than the end row.");
+
+    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!");
+
+    size_type len = end_pos - start_pos + 1;
+    size_type last_dest_pos = dest_pos + len - 1;
+
+    // Make sure the destination container is large enough.
+    if (last_dest_pos >= dest.size())
+        throw std::out_of_range("Destination vector is too small for the elements being transferred.");
+
+    if (block_index1 == block_index2)
+    {
+        // All elements are in the same block.
+        return transfer_single_block(start_pos, end_pos, start_pos_in_block1, block_index1, dest, dest_pos);
+    }
+
+    assert(block_index1 < block_index2);
+
+    // Empty the region in the destination container where the elements
+    // are to be transferred to. This ensures that the destination region
+    // consists of a single block.
+    iterator it_dest_blk = dest.set_empty(dest_pos, last_dest_pos);
+
+    size_type dest_block_index = it_dest_blk->__private_data.block_index;
+    size_type dest_pos_in_block = dest_pos - it_dest_blk->__private_data.start_pos;
+    block* blk_dest = dest.m_blocks[dest_block_index];
+    assert(!blk_dest->mp_data); // should be already emptied.
+
+    size_type block_len = block_index2 - block_index1 + 1;
+
+    // Create slots for new blocks in the destination.
+
+    size_type dest_block_index1 = dest_block_index;
+    if (dest_pos_in_block == 0)
+    {
+        // Copy to the top part of destination block.
+        if (len < blk_dest->m_size)
+        {
+            // Shrink the existing block and insert slots for new blocks before it.
+            assert(len < blk_dest->m_size);
+            blk_dest->m_size -= len;
+            dest.m_blocks.insert(dest.m_blocks.begin()+dest_block_index, block_len, NULL);
+        }
+        else
+        {
+            // Destination block is exactly of the length of the elements being transferred.
+            delete dest.m_blocks[dest_block_index];
+            dest.m_blocks[dest_block_index] = NULL;
+            if (block_len > 1)
+                dest.m_blocks.insert(dest.m_blocks.begin()+dest_block_index, block_len-1, NULL);
+        }
+    }
+    else if (dest_pos_in_block + len - 1 == it_dest_blk->size - 1)
+    {
+        // Copy to the bottom part of destination block. Insert slots for new
+        // blocks below current, and shrink the current block.
+        dest.m_blocks.insert(dest.m_blocks.begin()+dest_block_index+1, block_len, NULL);
+        blk_dest->m_size -= len;
+
+        ++dest_block_index1;
+    }
+    else
+    {
+        // Copy to the middle of destination block. Insert slots for new
+        // blocks (plus one for the empty block) below current.
+        size_type blk2_size = blk_dest->m_size - dest_pos_in_block - len;
+        dest.m_blocks.insert(dest.m_blocks.begin()+dest_block_index+1, block_len+1, NULL);
+        dest.m_blocks[dest_block_index+block_len+1] = new block(blk2_size);
+        blk_dest->m_size = dest_pos_in_block;
+
+        ++dest_block_index1;
+    }
+
+    size_type del_index1 = block_index1, del_index2 = block_index2;
+    size_type ret_block_index = block_index1, ret_start_pos = start_pos_in_block1;
+
+    // Now that the new slots have been created, start transferring the blocks.
+
+    // Transfer the first block.
+    size_type offset = start_pos - start_pos_in_block1;
+    if (offset)
+    {
+        // Transfer the lower part of the first block.
+        block* blk = m_blocks[block_index1];
+        assert(!dest.m_blocks[dest_block_index1]);
+        dest.m_blocks[dest_block_index1] = new block(blk->m_size - offset);
+        if (blk->mp_data)
+        {
+            element_category_type cat = mtv::get_block_type(*blk->mp_data);
+            blk_dest = dest.m_blocks[dest_block_index1];
+            blk_dest->mp_data = element_block_func::create_new_block(cat, 0);
+            assert(blk_dest->mp_data);
+
+            // Shallow-copy the elements to the destination block, and shrink
+            // the source block to remove the transferred elements.
+            element_block_func::assign_values_from_block(*blk_dest->mp_data, *blk->mp_data, offset, blk->m_size-offset);
+            element_block_func::resize_block(*blk->mp_data, offset);
+        }
+
+        blk->m_size = offset;
+        ++del_index1; // Retain this block.
+
+        // Move the return block position to the next block.
+        ++ret_block_index;
+        ret_start_pos += blk->m_size;
+    }
+    else
+    {
+        // Just move the whole block over.
+        dest.m_blocks[dest_block_index1] = m_blocks[block_index1];
+        m_blocks[block_index1] = NULL;
+    }
+
+    if (block_len > 2)
+    {
+        // Transfer all blocks in between.
+        for (size_type i = 0; i < block_len - 2; ++i)
+        {
+            size_type src_block_pos = block_index1 + 1 + i;
+            size_type dest_block_pos = dest_block_index1 + 1 + i;
+            assert(!dest.m_blocks[dest_block_pos]);
+            dest.m_blocks[dest_block_pos] = m_blocks[src_block_pos];
+            m_blocks[src_block_pos] = NULL;
+        }
+    }
+
+    // Transfer the last block.
+    if (block_len > 1)
+    {
+        size_type size_to_trans = end_pos - start_pos_in_block2 + 1;
+        size_type dest_block_pos = dest_block_index1 + block_len - 1;
+        assert(!dest.m_blocks[dest_block_pos]);
+
+        block* blk = m_blocks[block_index2];
+        if (size_to_trans < blk->m_size)
+        {
+            // Transfer the upper part of this block.
+            dest.m_blocks[dest_block_pos] = new block(size_to_trans);
+            blk_dest = dest.m_blocks[dest_block_pos];
+            if (blk->mp_data)
+            {
+                element_category_type cat = mtv::get_block_type(*blk->mp_data);
+                blk_dest->mp_data = element_block_func::create_new_block(cat, 0);
+
+                element_block_func::assign_values_from_block(*blk_dest->mp_data, *blk->mp_data, 0, size_to_trans);
+                element_block_func::erase(*blk->mp_data, 0, size_to_trans);
+            }
+            blk->m_size -= size_to_trans;
+            --del_index2; // Retain this block.
+        }
+        else
+        {
+            // Just move the whole block over.
+            dest.m_blocks[dest_block_pos] = m_blocks[block_index2];
+            m_blocks[block_index2] = NULL;
+        }
+    }
+
+    // Now that all the elements have been transferred, check the bordering
+    // blocks in the destination and merge them as needed.
+    if (block_len > 1)
+        dest.merge_with_adjacent_blocks(dest_block_index1+block_len-1);
+    dest.merge_with_adjacent_blocks(dest_block_index1);
+
+    // Delete all transferred blocks, and replace it with one empty block.
+    assert(del_index2 >= del_index1);
+    if (del_index1 > 0 && !m_blocks[del_index1-1]->mp_data)
+    {
+        // The block before the first block to be deleted is empty.  Simply
+        // extend that block to cover the deleted block segment.
+        block* blk_prev = m_blocks[del_index1-1];
+
+        // This previous empty block will be returned.  Adjust the return block position.
+        --ret_block_index;
+        ret_start_pos -= blk_prev->m_size;
+
+        // Extend the previous block.
+        blk_prev->m_size += len;
+    }
+    else
+    {
+        // Block before is not empty (or doesn't exist).  Keep the first slot,
+        // and erase the rest.
+        m_blocks[del_index1] = new block(len); // Insert an empty
+        ++del_index1;
+    }
+
+    if (del_index2 >= del_index1)
+    {
+        typename blocks_type::iterator it_blk = m_blocks.begin();
+        typename blocks_type::iterator it_blk_end = m_blocks.begin();
+        std::advance(it_blk, del_index1);
+        std::advance(it_blk_end, del_index2+1);
+
+#ifdef MDDS_MULTI_TYPE_VECTOR_DEBUG
+        typename blocks_type::iterator it_test = it_blk;
+        for (; it_test != it_blk_end; ++it_test)
+        {
+            // All slots to be erased should be NULL.
+            assert(!*it_test);
+        }
+#endif
+        m_blocks.erase(it_blk, it_blk_end);
+    }
+
+    size_type start_pos_offset = merge_with_adjacent_blocks(ret_block_index);
+    if (start_pos_offset)
+    {
+        // Merged with the previous block. Adjust the return block position.
+        --ret_block_index;
+        ret_start_pos -= start_pos_offset;
+    }
+
+    return get_iterator(ret_block_index, ret_start_pos);
+}
+
+template<typename _CellBlockFunc>
+typename multi_type_vector<_CellBlockFunc>::iterator
+multi_type_vector<_CellBlockFunc>::transfer_single_block(
+    size_type start_pos, size_type end_pos, size_type start_pos_in_block1, size_type block_index1,
+    multi_type_vector& dest, size_type dest_pos)
+{
+    size_type len = end_pos - start_pos + 1;
+    size_type last_dest_pos = dest_pos + len - 1;
+
+    // All elements are in the same block.
+    block* blk = m_blocks[block_index1];
+
+    // Empty the region in the destination container where the elements
+    // are to be transferred to. This ensures that the destination region
+    // consists of a single block.
+    iterator it_dest_blk = dest.set_empty(dest_pos, last_dest_pos);
+
+    if (!blk->mp_data)
+        return get_iterator(block_index1, start_pos_in_block1);
+
+    element_category_type cat = get_block_type(*blk->mp_data);
+
+    size_type dest_block_index = it_dest_blk->__private_data.block_index;
+    block* blk_dest = dest.m_blocks[dest_block_index];
+
+    size_type dest_pos_in_block = dest_pos - it_dest_blk->__private_data.start_pos;
+    if (dest_pos_in_block == 0)
+    {
+        // Copy to the top part of destination block.
+
+        assert(!blk_dest->mp_data); // should be already emptied.
+
+        if (len < blk_dest->m_size)
+        {
+            // Shrink the existing block and insert a new block before it.
+            assert(len < blk_dest->m_size);
+            blk_dest->m_size -= len;
+            dest.m_blocks.insert(dest.m_blocks.begin()+dest_block_index, new block(len));
+            blk_dest = dest.m_blocks[dest_block_index];
+        }
+    }
+    else if (dest_pos_in_block + len - 1 == it_dest_blk->size - 1)
+    {
+        // Copy to the bottom part of destination block.
+
+        // Insert a new block below current, and shrink the current block.
+        dest.m_blocks.insert(dest.m_blocks.begin()+dest_block_index+1, new block(len));
+        blk_dest->m_size -= len;
+        blk_dest = dest.m_blocks[dest_block_index+1];
+    }
+    else
+    {
+        // Copy to the middle of destination block.
+
+        // Insert two new blocks below current.
+        size_type blk2_size = blk_dest->m_size - dest_pos_in_block - len;
+        dest.m_blocks.insert(dest.m_blocks.begin()+dest_block_index+1, 2, NULL);
+        dest.m_blocks[dest_block_index+1] = new block(len);
+        dest.m_blocks[dest_block_index+2] = new block(blk2_size);
+        blk_dest->m_size = dest_pos_in_block;
+
+        blk_dest = dest.m_blocks[dest_block_index+1];
+    }
+
+    assert(blk_dest->m_size == len);
+    size_type offset = start_pos - start_pos_in_block1;
+    if (offset == 0 && len == blk->m_size)
+    {
+        // Just move the whole data array.
+        blk_dest->mp_data = blk->mp_data;
+        blk->mp_data = NULL;
+        dest.merge_with_adjacent_blocks(dest_block_index);
+        size_type start_pos_offset = merge_with_adjacent_blocks(block_index1);
+        if (start_pos_offset)
+        {
+            // Merged with the previous block. Adjust the return block position.
+            --block_index1;
+            start_pos_in_block1 -= start_pos_offset;
+        }
+        return get_iterator(block_index1, start_pos_in_block1);
+    }
+
+    blk_dest->mp_data = element_block_func::create_new_block(cat, 0);
+    assert(blk_dest->mp_data);
+
+    // Shallow-copy the elements to the destination block.
+    element_block_func::assign_values_from_block(*blk_dest->mp_data, *blk->mp_data, offset, len);
+    dest.merge_with_adjacent_blocks(dest_block_index);
+
+    // Set the source range empty without overwriting the elements.
+    return set_empty_in_single_block(start_pos, end_pos, block_index1, start_pos_in_block1, false);
+}
+
+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)
 {
@@ -1118,10 +1530,10 @@ multi_type_vector<_CellBlockFunc>::set_empty_impl(
         throw std::out_of_range("Block position not found!");
 
     if (block_index1 == block_index2)
-        return set_empty_in_single_block(start_pos, end_pos, block_index1, start_pos_in_block1);
+        return set_empty_in_single_block(start_pos, end_pos, block_index1, start_pos_in_block1, true);
 
     return set_empty_in_multi_blocks(
-        start_pos, end_pos, block_index1, start_pos_in_block1, block_index2, start_pos_in_block2);
+        start_pos, end_pos, block_index1, start_pos_in_block1, block_index2, start_pos_in_block2, true);
 }
 
 template<typename _CellBlockFunc>
@@ -1283,7 +1695,7 @@ multi_type_vector<_CellBlockFunc>::insert_empty(size_type pos, size_type length)
 
 template<typename _CellBlockFunc>
 typename multi_type_vector<_CellBlockFunc>::iterator
-multi_type_vector<_CellBlockFunc>::insert_empty(iterator pos_hint, size_type pos, size_type length)
+multi_type_vector<_CellBlockFunc>::insert_empty(const iterator& pos_hint, size_type pos, size_type length)
 {
     if (!length)
         // Nothing to insert.
@@ -1960,25 +2372,129 @@ multi_type_vector<_CellBlockFunc>::set_cells_to_multi_blocks_block1_non_empty(
 }
 
 template<typename _CellBlockFunc>
-void multi_type_vector<_CellBlockFunc>::merge_with_next_block(size_type block_index)
+typename multi_type_vector<_CellBlockFunc>::size_type
+multi_type_vector<_CellBlockFunc>::merge_with_adjacent_blocks(size_type block_index)
 {
+    assert(!m_blocks.empty());
+    assert(block_index < m_blocks.size());
+    block* blk_prev = block_index > 0 ? m_blocks[block_index-1] : NULL;
+
+    if (!blk_prev)
+    {
+        // No previous block.
+        merge_with_next_block(block_index);
+        return 0;
+    }
+
+    size_type size_prev = blk_prev->m_size; // size of previous block.
+    block* blk = m_blocks[block_index];
+    block* blk_next = block_index < (m_blocks.size()-1) ? m_blocks[block_index+1] : NULL;
+
+    // Check the previous block.
+    if (blk_prev->mp_data)
+    {
+        // Previous block has data.
+        element_category_type cat_prev = mtv::get_block_type(*blk_prev->mp_data);
+        if (!blk->mp_data || cat_prev != mtv::get_block_type(*blk->mp_data))
+        {
+            // Current block is empty or is of different type from the previous one.
+            merge_with_next_block(block_index);
+            return 0;
+        }
+
+        // Previous and current blocks are of the same type.
+        if (blk_next && blk_next->mp_data && cat_prev == get_block_type(*blk_next->mp_data))
+        {
+            // Merge all three blocks.
+            blk_prev->m_size += blk->m_size + blk_next->m_size;
+            element_block_func::append_values_from_block(*blk_prev->mp_data, *blk->mp_data);
+            element_block_func::append_values_from_block(*blk_prev->mp_data, *blk_next->mp_data);
+            // Avoid overwriting the transferred elements.
+            element_block_func::resize_block(*blk->mp_data, 0);
+            element_block_func::resize_block(*blk_next->mp_data, 0);
+
+            delete blk;
+            delete blk_next;
+            typename blocks_type::iterator it = m_blocks.begin();
+            std::advance(it, block_index);
+            typename blocks_type::iterator it_end = it;
+            std::advance(it_end, 2);
+            m_blocks.erase(it, it_end);
+            return size_prev;
+        }
+
+        // Merge only the previous and current blocks.
+        bool merged = merge_with_next_block(block_index-1);
+        if (!merged)
+            assert(!"Blocks were not merged!");
+
+        return size_prev;
+    }
+
+    // Previous block is empty.
+    if (blk->mp_data)
+    {
+        // Current block is not empty. Check with the next block.
+        merge_with_next_block(block_index);
+        return 0;
+    }
+
+    // Previous and current blocks are both empty.
+    if (blk_next && !blk_next->mp_data)
+    {
+        // Next block is empty too. Merge all three.
+        blk_prev->m_size += blk->m_size + blk_next->m_size;
+        delete blk;
+        delete blk_next;
+        typename blocks_type::iterator it = m_blocks.begin();
+        std::advance(it, block_index);
+        typename blocks_type::iterator it_end = it;
+        std::advance(it_end, 2);
+        m_blocks.erase(it, it_end);
+        return size_prev;
+    }
+
+    // Next block is not empty, or does not exist. Merge the current block with the previous one.
+    bool merged = merge_with_next_block(block_index-1);
+    if (!merged)
+        assert(!"Blocks were not merged!");
+
+    return size_prev;
+}
+
+template<typename _CellBlockFunc>
+bool multi_type_vector<_CellBlockFunc>::merge_with_next_block(size_type block_index)
+{
+    assert(!m_blocks.empty());
+    assert(block_index < m_blocks.size());
+
     if (block_index >= m_blocks.size()-1)
         // No more block below this one.
-        return;
+        return false;
 
     // Block exists below.
     block* blk = m_blocks[block_index];
+    block* blk_next = m_blocks[block_index+1];
     if (!blk->mp_data)
-        // Don't merge an empty block.
-        return;
+    {
+        // Empty block. Merge only if the next block is also empty.
+        if (blk_next->mp_data)
+            // Next block is not empty.
+            return false;
+
+        // Merge the two blocks.
+        blk->m_size += blk_next->m_size;
+        delete m_blocks[block_index+1];
+        m_blocks.erase(m_blocks.begin()+block_index+1);
+        return true;
+    }
 
-    block* blk_next = m_blocks[block_index+1];
     if (!blk_next->mp_data)
-        return;
+        return false;
 
     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;
+        return false;
 
     // Merge it with the next block.
     element_block_func::append_values_from_block(*blk->mp_data, *blk_next->mp_data);
@@ -1986,6 +2502,7 @@ void multi_type_vector<_CellBlockFunc>::merge_with_next_block(size_type block_in
     blk->m_size += blk_next->m_size;
     delete m_blocks[block_index+1];
     m_blocks.erase(m_blocks.begin()+block_index+1);
+    return true;
 }
 
 template<typename _CellBlockFunc>
@@ -2177,9 +2694,14 @@ mtv::element_t multi_type_vector<_CellBlockFunc>::get_element_type(const _T& ele
 
 template<typename _CellBlockFunc>
 typename multi_type_vector<_CellBlockFunc>::iterator
-multi_type_vector<_CellBlockFunc>::set_whole_block_empty(size_type block_index, size_type start_pos_in_block)
+multi_type_vector<_CellBlockFunc>::set_whole_block_empty(
+    size_type block_index, size_type start_pos_in_block, bool overwrite)
 {
     block* blk = m_blocks[block_index];
+    if (!overwrite)
+        // Resize block to 0 before deleting, to prevent its elements from getting deleted.
+        element_block_func::resize_block(*blk->mp_data, 0);
+
     element_block_func::delete_block(blk->mp_data);
     blk->mp_data = NULL;
 
@@ -2252,7 +2774,7 @@ multi_type_vector<_CellBlockFunc>::set_whole_block_empty(size_type block_index,
 template<typename _CellBlockFunc>
 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)
+    size_type start_row, size_type end_row, size_type block_index, size_type start_row_in_block, bool overwrite)
 {
     // Range is within a single block.
     block* blk = m_blocks[block_index];
@@ -2269,10 +2791,11 @@ multi_type_vector<_CellBlockFunc>::set_empty_in_single_block(
         // start row coincides with the start of a block.
 
         if (end_row == end_row_in_block)
-            return set_whole_block_empty(block_index, start_row_in_block);
+            return set_whole_block_empty(block_index, start_row_in_block, overwrite);
 
         // Set the upper part of the block empty.
-        element_block_func::overwrite_values(*blk->mp_data, 0, empty_block_size);
+        if (overwrite)
+            element_block_func::overwrite_values(*blk->mp_data, 0, empty_block_size);
         element_block_func::erase(*blk->mp_data, 0, empty_block_size);
         blk->m_size -= empty_block_size;
 
@@ -2306,7 +2829,8 @@ multi_type_vector<_CellBlockFunc>::set_empty_in_single_block(
 
         // Set the lower part of the block empty.
         size_type start_pos = start_row - start_row_in_block;
-        element_block_func::overwrite_values(*blk->mp_data, start_pos, empty_block_size);
+        if (overwrite)
+            element_block_func::overwrite_values(*blk->mp_data, start_pos, empty_block_size);
         element_block_func::erase(*blk->mp_data, start_pos, empty_block_size);
         blk->m_size -= empty_block_size;
 
@@ -2349,10 +2873,13 @@ multi_type_vector<_CellBlockFunc>::set_empty_in_single_block(
         end_row_in_block-start_row_in_block-lower_block_size+1,
         lower_block_size);
 
-    // Overwrite cells that will become empty.
     size_type new_cur_size = start_row - start_row_in_block;
-    element_block_func::overwrite_values(
-        *blk->mp_data, new_cur_size, empty_block_size);
+    if (overwrite)
+    {
+        // Overwrite cells that will become empty.
+        element_block_func::overwrite_values(
+            *blk->mp_data, new_cur_size, empty_block_size);
+    }
 
     // Shrink the current data block.
     element_block_func::erase(
@@ -2367,7 +2894,7 @@ 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)
+    size_type block_index2, size_type start_row_in_block2, bool overwrite)
 {
     assert(block_index1 < block_index2);
 
@@ -2401,6 +2928,9 @@ multi_type_vector<_CellBlockFunc>::set_empty_in_multi_blocks(
                 else
                 {
                     // Make block 1 empty.
+                    if (!overwrite)
+                        element_block_func::resize_block(*blk->mp_data, 0);
+
                     element_block_func::delete_block(blk->mp_data);
                     blk->mp_data = NULL;
                 }
@@ -2409,7 +2939,9 @@ multi_type_vector<_CellBlockFunc>::set_empty_in_multi_blocks(
             {
                 // Empty the lower part.
                 size_type new_size = start_row - start_row_in_block1;
-                element_block_func::overwrite_values(*blk->mp_data, new_size, blk->m_size-new_size);
+                if (overwrite)
+                    element_block_func::overwrite_values(*blk->mp_data, new_size, blk->m_size-new_size);
+
                 element_block_func::resize_block(*blk->mp_data, new_size);
                 blk->m_size = new_size;
             }
@@ -2456,7 +2988,9 @@ multi_type_vector<_CellBlockFunc>::set_empty_in_multi_blocks(
             {
                 // Empty the upper part.
                 size_type size_to_erase = end_row - start_row_in_block2 + 1;
-                element_block_func::overwrite_values(*blk->mp_data, 0, size_to_erase);
+                if (overwrite)
+                    element_block_func::overwrite_values(*blk->mp_data, 0, size_to_erase);
+
                 element_block_func::erase(*blk->mp_data, 0, size_to_erase);
                 blk->m_size -= size_to_erase;
             }
@@ -2475,7 +3009,13 @@ multi_type_vector<_CellBlockFunc>::set_empty_in_multi_blocks(
         // Remove all blocks in-between, from block_index1+1 to end_block_to_erase-1.
 
         for (size_type i = block_index1 + 1; i < end_block_to_erase; ++i)
-            delete m_blocks[i];
+        {
+            block* blk = m_blocks[i];
+            if (!overwrite && blk->mp_data)
+                element_block_func::resize_block(*blk->mp_data, 0);
+
+            delete blk;
+        }
 
         typename blocks_type::iterator it = m_blocks.begin() + block_index1 + 1;
         typename blocks_type::iterator it_end = m_blocks.begin() + end_block_to_erase;
@@ -2496,4 +3036,20 @@ multi_type_vector<_CellBlockFunc>::set_empty_in_multi_blocks(
     return get_iterator(block_index1, start_row);
 }
 
+#ifdef MDDS_UNIT_TEST
+template<typename _CellBlockFunc>
+void multi_type_vector<_CellBlockFunc>::dump_blocks() const
+{
+    cout << "--- blocks" << endl;
+    for (size_type i = 0, n = m_blocks.size(); i < n; ++i)
+    {
+        block* blk = m_blocks[i];
+        element_category_type cat = mtv::element_type_empty;
+        if (blk->mp_data)
+            cat = mtv::get_block_type(*blk->mp_data);
+        cout << "  block " << i << ": size=" << blk->m_size << " type=" << cat << endl;
+    }
+}
+#endif
+
 }
diff --git a/include/mdds/multi_type_vector_itr.hpp b/include/mdds/multi_type_vector_itr.hpp
index 60e533c..a7954d2 100644
--- a/include/mdds/multi_type_vector_itr.hpp
+++ b/include/mdds/multi_type_vector_itr.hpp
@@ -25,6 +25,11 @@
  *
  ************************************************************************/
 
+#ifndef MDDS_MULTI_TYPE_VECTOR_ITR_HPP
+#define MDDS_MULTI_TYPE_VECTOR_ITR_HPP
+
+#include "multi_type_vector_types.hpp"
+
 namespace mdds { namespace __mtv {
 
 /**
@@ -359,6 +364,18 @@ public:
     {
         return dec();
     }
+
+    bool operator== (const const_iterator_base& other) const
+    {
+        return iterator_common_base<_Trait>::operator==(other);
+    }
+
+    bool operator!= (const const_iterator_base& other) const
+    {
+        return iterator_common_base<_Trait>::operator!=(other);
+    }
 };
 
 }}
+
+#endif
diff --git a/include/mdds/multi_type_vector_trait.hpp b/include/mdds/multi_type_vector_trait.hpp
index 466ed8f..19807ba 100644
--- a/include/mdds/multi_type_vector_trait.hpp
+++ b/include/mdds/multi_type_vector_trait.hpp
@@ -92,6 +92,10 @@ base_element_block* element_block_func_base::create_new_block(element_t type, si
             return ulong_element_block::create_block(init_size);
         case element_type_boolean:
             return boolean_element_block::create_block(init_size);
+        case element_type_char:
+            return char_element_block::create_block(init_size);
+        case element_type_uchar:
+            return uchar_element_block::create_block(init_size);
         default:
             throw general_error("create_new_block: failed to create a new block of unknown type.");
     }
@@ -119,6 +123,10 @@ base_element_block* element_block_func_base::clone_block(const base_element_bloc
             return ulong_element_block::clone_block(block);
         case element_type_boolean:
             return boolean_element_block::clone_block(block);
+        case element_type_char:
+            return char_element_block::clone_block(block);
+        case element_type_uchar:
+            return uchar_element_block::clone_block(block);
         default:
             throw general_error("clone_block: failed to clone a block of unknown type.");
     }
@@ -158,6 +166,12 @@ void element_block_func_base::delete_block(base_element_block* p)
         case element_type_boolean:
             boolean_element_block::delete_block(p);
         break;
+        case element_type_char:
+            char_element_block::delete_block(p);
+        break;
+        case element_type_uchar:
+            uchar_element_block::delete_block(p);
+        break;
         default:
             throw general_error("delete_block: failed to delete a block of unknown type.");
     }
@@ -194,6 +208,12 @@ void element_block_func_base::resize_block(base_element_block& block, size_t new
         case element_type_boolean:
             boolean_element_block::resize_block(block, new_size);
         break;
+        case element_type_char:
+            char_element_block::resize_block(block, new_size);
+        break;
+        case element_type_uchar:
+            uchar_element_block::resize_block(block, new_size);
+        break;
         default:
             throw general_error("resize_block: failed to resize a block of unknown type.");
     }
@@ -230,6 +250,12 @@ void element_block_func_base::print_block(const base_element_block& block)
         case element_type_boolean:
             boolean_element_block::print_block(block);
         break;
+        case element_type_char:
+            char_element_block::print_block(block);
+        break;
+        case element_type_uchar:
+            uchar_element_block::print_block(block);
+        break;
         default:
             throw general_error("print_block: failed to print a block of unknown type.");
     }
@@ -266,6 +292,12 @@ void element_block_func_base::erase(base_element_block& block, size_t pos)
         case element_type_boolean:
             boolean_element_block::erase_block(block, pos);
         break;
+        case element_type_char:
+            char_element_block::erase_block(block, pos);
+        break;
+        case element_type_uchar:
+            uchar_element_block::erase_block(block, pos);
+        break;
         default:
             throw general_error("erase: failed to erase an element from a block of unknown type.");
     }
@@ -302,6 +334,12 @@ void element_block_func_base::erase(base_element_block& block, size_t pos, size_
         case element_type_boolean:
             boolean_element_block::erase_block(block, pos, size);
         break;
+        case element_type_char:
+            char_element_block::erase_block(block, pos, size);
+        break;
+        case element_type_uchar:
+            uchar_element_block::erase_block(block, pos, size);
+        break;
         default:
             throw general_error("erase: failed to erase elements from a block of unknown type.");
     }
@@ -338,6 +376,12 @@ void element_block_func_base::append_values_from_block(base_element_block& dest,
         case element_type_boolean:
             boolean_element_block::append_values_from_block(dest, src);
         break;
+        case element_type_char:
+            char_element_block::append_values_from_block(dest, src);
+        break;
+        case element_type_uchar:
+            uchar_element_block::append_values_from_block(dest, src);
+        break;
         default:
             throw general_error("append_values: failed to append values to a block of unknown type.");
     }
@@ -375,6 +419,12 @@ void element_block_func_base::append_values_from_block(
         case element_type_boolean:
             boolean_element_block::append_values_from_block(dest, src, begin_pos, len);
         break;
+        case element_type_char:
+            char_element_block::append_values_from_block(dest, src, begin_pos, len);
+        break;
+        case element_type_uchar:
+            uchar_element_block::append_values_from_block(dest, src, begin_pos, len);
+        break;
         default:
             throw general_error("append_values: failed to append values to a block of unknown type.");
     }
@@ -412,6 +462,12 @@ void element_block_func_base::assign_values_from_block(
         case element_type_boolean:
             boolean_element_block::assign_values_from_block(dest, src, begin_pos, len);
         break;
+        case element_type_char:
+            char_element_block::assign_values_from_block(dest, src, begin_pos, len);
+        break;
+        case element_type_uchar:
+            uchar_element_block::assign_values_from_block(dest, src, begin_pos, len);
+        break;
         default:
             throw general_error("assign_values: failed to assign values to a block of unknown type.");
     }
@@ -443,6 +499,10 @@ bool element_block_func_base::equal_block(const base_element_block& left, const
             return ulong_element_block::get(left) == ulong_element_block::get(right);
         case element_type_boolean:
             return boolean_element_block::get(left) == boolean_element_block::get(right);
+        case element_type_char:
+            return char_element_block::get(left) == char_element_block::get(right);
+        case element_type_uchar:
+            return uchar_element_block::get(left) == uchar_element_block::get(right);
         default:
             ;
     }
diff --git a/include/mdds/multi_type_vector_types.hpp b/include/mdds/multi_type_vector_types.hpp
index 5680233..327e7b7 100644
--- a/include/mdds/multi_type_vector_types.hpp
+++ b/include/mdds/multi_type_vector_types.hpp
@@ -33,9 +33,15 @@
 #include "global.hpp"
 
 #include <vector>
-#include <iostream>
 #include <boost/noncopyable.hpp>
 
+#ifdef MDDS_UNIT_TEST
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+#endif
+
 namespace mdds { namespace mtv {
 
 typedef int element_t;
@@ -51,6 +57,8 @@ const element_t element_type_uint    = 5;
 const element_t element_type_long    = 6;
 const element_t element_type_ulong   = 7;
 const element_t element_type_boolean = 8;
+const element_t element_type_char    = 9;
+const element_t element_type_uchar   = 10;
 
 const element_t element_type_user_start = 50;
 
@@ -77,6 +85,7 @@ protected:
 template<typename _Self, element_t _TypeId, typename _Data>
 class element_block : public base_element_block
 {
+#ifdef MDDS_UNIT_TEST
     struct print_block_array
     {
         void operator() (const _Data& val) const
@@ -84,6 +93,7 @@ class element_block : public base_element_block
             std::cout << val << " ";
         }
     };
+#endif
 
 protected:
     typedef std::vector<_Data> store_type;
@@ -110,6 +120,16 @@ public:
         return !operator==(r);
     }
 
+    static const value_type& at(const base_element_block& block, typename store_type::size_type pos)
+    {
+        return get(block).m_array.at(pos);
+    }
+
+    static value_type& at(base_element_block& block, typename store_type::size_type pos)
+    {
+        return get(block).m_array.at(pos);
+    }
+
     static iterator begin(base_element_block& block)
     {
         return get(block).m_array.begin();
@@ -204,12 +224,16 @@ public:
         static_cast<_Self&>(blk).m_array.resize(new_size);
     }
 
+#ifdef MDDS_UNIT_TEST
     static void print_block(const base_element_block& blk)
     {
         const store_type& blk2 = get(blk).m_array;
         std::for_each(blk2.begin(), blk2.end(), print_block_array());
         std::cout << std::endl;
     }
+#else
+    static void print_block(const base_element_block&) {}
+#endif
 
     static void erase_block(base_element_block& blk, size_t pos)
     {
@@ -467,6 +491,8 @@ typedef default_element_block<mtv::element_type_uint, unsigned int>     uint_ele
 typedef default_element_block<mtv::element_type_long, long>             long_element_block;
 typedef default_element_block<mtv::element_type_ulong, unsigned long>   ulong_element_block;
 typedef default_element_block<mtv::element_type_boolean, bool>          boolean_element_block;
+typedef default_element_block<mtv::element_type_char, char>             char_element_block;
+typedef default_element_block<mtv::element_type_uchar, unsigned char>   uchar_element_block;
 
 }}
 
diff --git a/include/mdds/node.hpp b/include/mdds/node.hpp
index 6791363..585c342 100644
--- a/include/mdds/node.hpp
+++ b/include/mdds/node.hpp
@@ -36,36 +36,25 @@
 
 namespace mdds {
 
-#ifdef DEBUG_NODE_BASE
+#ifdef MDDS_DEBUG_NODE_BASE
 size_t node_instance_count = 0;
 #endif
 
 template<typename T>
-struct node_traits
-{
-    typedef typename T::nonleaf_value_type          nonleaf_value_type;
-    typedef typename T::leaf_value_type             leaf_value_type;
-    typedef typename T::fill_nonleaf_value_handler  fill_nonleaf_value_handler;
-    typedef typename T::to_string_handler           to_string_handler;
-    typedef typename T::init_handler                init_handler;
-    typedef typename T::dispose_handler             dispose_handler;
-};
-
-template<typename T>
 struct node
 {
     typedef ::boost::intrusive_ptr<node>  node_ptr;
 
-    typedef typename node_traits<T>::nonleaf_value_type nonleaf_value_type;
-    typedef typename node_traits<T>::leaf_value_type leaf_value_type;
-    typedef typename node_traits<T>::fill_nonleaf_value_handler fill_nonleaf_value_handler;
-    typedef typename node_traits<T>::to_string_handler to_string_handler;
-    typedef typename node_traits<T>::init_handler init_handler;
-    typedef typename node_traits<T>::dispose_handler dispose_handler;
+    typedef typename T::nonleaf_value_type nonleaf_value_type;
+    typedef typename T::leaf_value_type leaf_value_type;
+    typedef typename T::fill_nonleaf_value_handler fill_nonleaf_value_handler;
+    typedef typename T::to_string_handler to_string_handler;
+    typedef typename T::init_handler init_handler;
+    typedef typename T::dispose_handler dispose_handler;
 
     static size_t get_instance_count()
     {
-#ifdef DEBUG_NODE_BASE
+#ifdef MDDS_DEBUG_NODE_BASE
         return node_instance_count;
 #else
         return 0;
@@ -95,7 +84,7 @@ public:
         is_leaf(_is_leaf),
         refcount(0)
     {
-#ifdef DEBUG_NODE_BASE
+#ifdef MDDS_DEBUG_NODE_BASE
         ++node_instance_count;
 #endif
         _hdl_init(*this);
@@ -109,7 +98,7 @@ public:
         is_leaf(r.is_leaf),
         refcount(0)
     {
-#ifdef DEBUG_NODE_BASE
+#ifdef MDDS_DEBUG_NODE_BASE
         ++node_instance_count;
 #endif
         if (is_leaf)
@@ -137,7 +126,7 @@ public:
 
     ~node()
     {
-#ifdef DEBUG_NODE_BASE
+#ifdef MDDS_DEBUG_NODE_BASE
         --node_instance_count;
 #endif
         dispose();
@@ -166,7 +155,7 @@ public:
         _hdl_fill_nonleaf(*this, left_node, right_node);
     }
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
     void dump_value() const
     {
         ::std::cout << _hdl_to_string(*this);
@@ -335,7 +324,7 @@ _NodePtr build_tree(const _NodePtr& left_leaf_node)
     return build_tree_non_leaf<_NodePtr, _NodeType>(node_list);
 }
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
 template<typename _NodePtr>
 size_t dump_tree_layer(const ::std::list<_NodePtr>& node_list, unsigned int level)
 {
diff --git a/include/mdds/point_quad_tree.hpp b/include/mdds/point_quad_tree.hpp
index aac1b02..4ac8f61 100644
--- a/include/mdds/point_quad_tree.hpp
+++ b/include/mdds/point_quad_tree.hpp
@@ -475,7 +475,7 @@ public:
 
     bool operator!= (const point_quad_tree& r) const { return !operator== (r); }
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
 public:
 #else
 private:
diff --git a/include/mdds/quad_node.hpp b/include/mdds/quad_node.hpp
index b632868..30cd9f4 100644
--- a/include/mdds/quad_node.hpp
+++ b/include/mdds/quad_node.hpp
@@ -34,7 +34,7 @@
 
 namespace mdds {
 
-#ifdef DEBUG_NODE_BASE
+#ifdef MDDS_DEBUG_NODE_BASE
 size_t node_instance_count = 0;
 inline size_t get_node_instance_count()
 {
@@ -140,7 +140,7 @@ struct quad_node_base
         x(_x), 
         y(_y)
     {
-#ifdef DEBUG_NODE_BASE
+#ifdef MDDS_DEBUG_NODE_BASE
         ++node_instance_count;
 #endif
     }
@@ -159,7 +159,7 @@ struct quad_node_base
         x(r.x), 
         y(r.y)
     {
-#ifdef DEBUG_NODE_BASE
+#ifdef MDDS_DEBUG_NODE_BASE
         ++node_instance_count;
 #endif
     }
@@ -190,7 +190,7 @@ struct quad_node_base
 
     ~quad_node_base()
     {
-#ifdef DEBUG_NODE_BASE
+#ifdef MDDS_DEBUG_NODE_BASE
         --node_instance_count;
 #endif
         static_cast<node_type*>(this)->dispose();
diff --git a/include/mdds/rectangle_set.hpp b/include/mdds/rectangle_set.hpp
index 82269a3..c898953 100644
--- a/include/mdds/rectangle_set.hpp
+++ b/include/mdds/rectangle_set.hpp
@@ -44,7 +44,7 @@ public:
     typedef _Key    key_type;
     typedef _Data   data_type;
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
 public:
 #else
 private:
@@ -221,7 +221,7 @@ public:
 private:
     void build_outer_segment_tree();
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
 public:
     void dump_rectangles() const;
     bool verify_rectangles(const dataset_type& expected) const;
diff --git a/include/mdds/rectangle_set_def.inl b/include/mdds/rectangle_set_def.inl
index bd0cb7f..3d074ed 100644
--- a/include/mdds/rectangle_set_def.inl
+++ b/include/mdds/rectangle_set_def.inl
@@ -233,7 +233,7 @@ void rectangle_set<_Key,_Data>::build_outer_segment_tree()
     }
 }
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
 template<typename _Key, typename _Data>
 void rectangle_set<_Key,_Data>::dump_rectangles() const
 {
diff --git a/include/mdds/segment_tree.hpp b/include/mdds/segment_tree.hpp
index 9ece0c5..292d048 100644
--- a/include/mdds/segment_tree.hpp
+++ b/include/mdds/segment_tree.hpp
@@ -39,7 +39,7 @@
 #include <boost/shared_ptr.hpp>
 #include <boost/ptr_container/ptr_map.hpp>
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
 #include <sstream>
 #endif
 
@@ -125,7 +125,7 @@ public:
     typedef size_t      size_type;
     typedef ::std::vector<data_type*> search_result_type;
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
     struct segment_data
     {
         key_type    begin_key;
@@ -230,7 +230,7 @@ public:
     {
         ::std::string operator() (const node& _self) const
         {
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
             ::std::ostringstream os;
             if (_self.is_leaf)
             {
@@ -285,7 +285,7 @@ public:
         }
     };
 
-#if UNIT_TEST
+#ifdef MDDS_UNIT_TEST
     struct node_printer : public ::std::unary_function<const node*, void>
     {
         void operator() (const node* p) const
@@ -650,7 +650,7 @@ public:
      */
     bool empty() const;
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
     void dump_tree() const;
     void dump_leaf_nodes() const;
     void dump_segment_data() const;
@@ -702,7 +702,7 @@ private:
 
     void clear_all_nodes();
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
     static bool has_data_pointer(const node_list_type& node_list, const data_type* pdata);
     static void print_leaf_value(const leaf_value_type& v);
 #endif
@@ -1058,7 +1058,7 @@ void segment_tree<_Key, _Data>::clear_all_nodes()
     m_root_node.reset();
 }
 
-#ifdef UNIT_TEST
+#ifdef MDDS_UNIT_TEST
 template<typename _Key, typename _Data>
 void segment_tree<_Key, _Data>::dump_tree() const
 {
diff --git a/misc/mdds.pc.in b/misc/mdds.pc.in
new file mode 100644
index 0000000..47caf03
--- /dev/null
+++ b/misc/mdds.pc.in
@@ -0,0 +1,7 @@
+prefix=@prefix@
+includedir=@includedir@
+
+Name: mdds
+Description: A collection of multi-dimensional data structure and indexing algorithm
+Version: @VERSION@
+Cflags: -I${includedir}
diff --git a/src/flat_segment_tree_test.cpp b/src/flat_segment_tree_test.cpp
index aec838d..3106745 100644
--- a/src/flat_segment_tree_test.cpp
+++ b/src/flat_segment_tree_test.cpp
@@ -40,7 +40,7 @@
 using namespace std;
 using namespace mdds;
 
-void printTitle(const char* msg)
+void print_title(const char* msg)
 {
     cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
     cout << " " << msg << endl;
@@ -50,7 +50,7 @@ void printTitle(const char* msg)
 void fst_test_leaf_search()
 {
     {
-        printTitle("Simple insert test");
+        print_title("Simple insert test");
         flat_segment_tree<int, int> int_ranges(0, 100, -1);
         for (int i = 0; i < 20; ++i)
         {
@@ -62,7 +62,7 @@ void fst_test_leaf_search()
     }
 
     {
-        printTitle("Merge test 1");
+        print_title("Merge test 1");
         flat_segment_tree<int, int> merge_test(0, 100, -1);
         merge_test.insert_front(10, 20, 5);
         merge_test.dump_leaf_nodes();
@@ -77,7 +77,7 @@ void fst_test_leaf_search()
     }
 
     {
-        printTitle("Merge test 2");
+        print_title("Merge test 2");
         flat_segment_tree<int, int> merge_test(0, 100, -1);
 
         // This should not change the node configuration.
@@ -104,7 +104,7 @@ void fst_test_leaf_search()
     }
 
     {
-        printTitle("Search test");
+        print_title("Search test");
         flat_segment_tree<int, int> db(0, 100, -1);
         for (int i = 0; i < 10; ++i)
         {
@@ -179,7 +179,7 @@ void fst_perf_test_search(bool tree_search)
         int val;
         for (int i = lower; i < upper; ++i)
         {
-            if (db.search_tree(i, val))
+            if (db.search_tree(i, val).second)
                 ++success;
             else
                 ++failure;
@@ -193,7 +193,7 @@ void fst_perf_test_search(bool tree_search)
         {
             if (tree_search)
             {
-                if (db.search_tree(i, val))
+                if (db.search_tree(i, val).second)
                     ++success;
                 else
                     ++failure;
@@ -213,8 +213,9 @@ void fst_perf_test_search(bool tree_search)
 void fst_test_tree_search()
 {
     stack_printer __stack_printer__("::fst_test_tree_search");
+    typedef flat_segment_tree<int, int> fst_type;
     int lower = 0, upper = 200, delta = 5;
-    flat_segment_tree<int, int> db(lower, upper, 0);
+    fst_type db(lower, upper, 0);
     for (int i = lower; i < upper; i += delta)
         db.insert_front(i, i+delta, i);
 
@@ -226,7 +227,7 @@ void fst_test_tree_search()
     int success = 0, failure = 0;
     for (int i = lower-10; i < upper+10; ++i)
     {
-        if (db.search_tree(i, val, &start, &end))
+        if (db.search_tree(i, val, &start, &end).second)
         {
             cout << "key = " << i << "; value = " << val << " (" << start << "-" << end << ")" << endl;
             ++success;
@@ -238,12 +239,48 @@ void fst_test_tree_search()
         }
     }
     cout << "search: success (" << success << ")  failure (" << failure << ")" << endl;
+
+    // Make sure search_tree() returns correct iterator position.
+    db.clear();
+    db.insert_back(5, 10, 2);
+    db.insert_back(15, 18, 3);
+    db.insert_back(23, 28, 4);
+    db.build_tree();
+
+    typedef pair<fst_type::const_iterator,bool> ret_type;
+    ret_type ret = db.search_tree(0, val, &start, &end);
+    assert(ret.second);
+    assert(start == 0 && end == 5 && val == 0);
+    assert(ret.first == db.begin());
+
+    ret = db.search_tree(6, val, &start, &end);
+    assert(ret.second);
+    assert(start == 5 && end == 10 && val == 2);
+    fst_type::const_iterator check = db.begin();
+    ++check; // 5-10 is the 2nd segment from the top.
+    assert(ret.first == check);
+
+    ret = db.search_tree(17, val, &start, &end);
+    assert(ret.second);
+    assert(start == 15 && end == 18 && val == 3);
+    std::advance(check, 2);
+    assert(ret.first == check);
+
+    ret = db.search_tree(55, val, &start, &end);
+    assert(ret.second);
+    assert(start == 28 && end == upper && val == 0);
+    std::advance(check, 3);
+    assert(ret.first == check);
+
+    ret = db.search_tree(upper+10, val, &start, &end);
+    assert(!ret.second); // This search should fail.
+    assert(ret.first == db.end());
 }
 
 void test_single_tree_search(const flat_segment_tree<int, int>& db, int key, int val, int start, int end)
 {
     int r_val, r_start, r_end;
-    if (db.search_tree(key, r_val, &r_start, &r_end))
+    if (db.search_tree(key, r_val, &r_start, &r_end).second)
         assert(r_val == val && r_start == start && r_end == end);
     else
         assert(!"tree search failed!");
@@ -1764,7 +1801,7 @@ void fst_test_swap()
 
     // Tree search should work on db2.
     db_type::value_type val;
-    assert(db2.search_tree(35, val));
+    assert(db2.search_tree(35, val).second);
     assert(val == 2);
 }
 
diff --git a/src/multi_type_vector_test_custom.cpp b/src/multi_type_vector_test_custom.cpp
index a0b877d..0700b2a 100644
--- a/src/multi_type_vector_test_custom.cpp
+++ b/src/multi_type_vector_test_custom.cpp
@@ -30,6 +30,8 @@
 #define MDDS_MULTI_TYPE_VECTOR_DEBUG 1
 #include <mdds/multi_type_vector.hpp>
 #include <mdds/multi_type_vector_trait.hpp>
+#include <mdds/multi_type_vector_custom_func1.hpp>
+#include <mdds/multi_type_vector_custom_func2.hpp>
 
 #include <cassert>
 #include <sstream>
@@ -48,6 +50,9 @@ namespace {
 /** custom cell type definition. */
 const mtv::element_t element_type_user_block  = mtv::element_type_user_start;
 const mtv::element_t element_type_muser_block = mtv::element_type_user_start+1;
+const mtv::element_t element_type_fruit_block = mtv::element_type_user_start+2;
+
+enum my_fruit_type { unknown_fruit = 0, apple, orange, mango, peach };
 
 /** Caller manages the life cycle of these cells. */
 struct user_cell
@@ -71,9 +76,6 @@ struct muser_cell
     muser_cell(double _v) : value(_v) {}
 };
 
-typedef mdds::mtv::default_element_block<element_type_user_block, user_cell*> user_cell_block;
-typedef mdds::mtv::managed_element_block<element_type_muser_block, muser_cell> muser_cell_block;
-
 template<typename T>
 class cell_pool : boost::noncopyable
 {
@@ -99,216 +101,21 @@ public:
     }
 };
 
+typedef mdds::mtv::default_element_block<element_type_user_block, user_cell*> user_cell_block;
+typedef mdds::mtv::managed_element_block<element_type_muser_block, muser_cell> muser_cell_block;
+typedef mdds::mtv::default_element_block<element_type_fruit_block, my_fruit_type> fruit_block;
+
 MDDS_MTV_DEFINE_ELEMENT_CALLBACKS_PTR(user_cell, element_type_user_block, NULL, user_cell_block)
 MDDS_MTV_DEFINE_ELEMENT_CALLBACKS_PTR(muser_cell, element_type_muser_block, NULL, muser_cell_block)
+MDDS_MTV_DEFINE_ELEMENT_CALLBACKS(my_fruit_type, element_type_fruit_block, unknown_fruit, fruit_block)
 
 }
 
-struct my_cell_block_func
-{
-    static mdds::mtv::base_element_block* create_new_block(
-        mdds::mtv::element_t type, size_t init_size)
-    {
-        switch (type)
-        {
-            case element_type_user_block:
-                return user_cell_block::create_block(init_size);
-            case element_type_muser_block:
-                return muser_cell_block::create_block(init_size);
-            default:
-                ;
-        }
-
-        return mtv::element_block_func_base::create_new_block(type, init_size);
-    }
-
-    static mdds::mtv::base_element_block* clone_block(const mdds::mtv::base_element_block& block)
-    {
-        switch (mtv::get_block_type(block))
-        {
-            case element_type_user_block:
-                return user_cell_block::clone_block(block);
-            case element_type_muser_block:
-                return muser_cell_block::clone_block(block);
-            default:
-                ;
-        }
-
-        return mtv::element_block_func_base::clone_block(block);
-    }
-
-    static void delete_block(mdds::mtv::base_element_block* p)
-    {
-        if (!p)
-            return;
-
-        switch (mtv::get_block_type(*p))
-        {
-            case element_type_user_block:
-                user_cell_block::delete_block(p);
-            break;
-            case element_type_muser_block:
-                muser_cell_block::delete_block(p);
-            break;
-            default:
-                mtv::element_block_func_base::delete_block(p);
-        }
-    }
-
-    static void resize_block(mdds::mtv::base_element_block& block, size_t new_size)
-    {
-        switch (mtv::get_block_type(block))
-        {
-            case element_type_user_block:
-                user_cell_block::resize_block(block, new_size);
-            break;
-            case element_type_muser_block:
-                muser_cell_block::resize_block(block, new_size);
-            break;
-            default:
-                mtv::element_block_func_base::resize_block(block, new_size);
-        }
-    }
-
-    static void print_block(const mdds::mtv::base_element_block& block)
-    {
-        switch (mtv::get_block_type(block))
-        {
-            case element_type_user_block:
-                user_cell_block::print_block(block);
-            break;
-            case element_type_muser_block:
-                muser_cell_block::print_block(block);
-            break;
-            default:
-                mtv::element_block_func_base::print_block(block);
-        }
-    }
-
-    static void erase(mdds::mtv::base_element_block& block, size_t pos)
-    {
-        switch (mtv::get_block_type(block))
-        {
-            case element_type_user_block:
-                user_cell_block::erase_block(block, pos);
-            break;
-            case element_type_muser_block:
-                muser_cell_block::erase_block(block, pos);
-            break;
-            default:
-                mtv::element_block_func_base::erase(block, pos);
-        }
-    }
-
-    static void erase(mdds::mtv::base_element_block& block, size_t pos, size_t size)
-    {
-        switch (mtv::get_block_type(block))
-        {
-            case element_type_user_block:
-                user_cell_block::erase_block(block, pos, size);
-            break;
-            case element_type_muser_block:
-                muser_cell_block::erase_block(block, pos, size);
-            break;
-            default:
-                mtv::element_block_func_base::erase(block, pos, size);
-        }
-    }
-
-    static void append_values_from_block(
-        mdds::mtv::base_element_block& dest, const mdds::mtv::base_element_block& src)
-    {
-        switch (mtv::get_block_type(dest))
-        {
-            case element_type_user_block:
-                user_cell_block::append_values_from_block(dest, src);
-            break;
-            case element_type_muser_block:
-                muser_cell_block::append_values_from_block(dest, src);
-            break;
-            default:
-                mtv::element_block_func_base::append_values_from_block(dest, src);
-        }
-    }
-
-    static void append_values_from_block(
-        mdds::mtv::base_element_block& dest, const mdds::mtv::base_element_block& src,
-        size_t begin_pos, size_t len)
-    {
-        switch (mtv::get_block_type(dest))
-        {
-            case element_type_user_block:
-                user_cell_block::append_values_from_block(dest, src, begin_pos, len);
-            break;
-            case element_type_muser_block:
-                muser_cell_block::append_values_from_block(dest, src, begin_pos, len);
-            break;
-            default:
-                mtv::element_block_func_base::append_values_from_block(dest, src, begin_pos, len);
-        }
-    }
-
-    static void assign_values_from_block(
-        mdds::mtv::base_element_block& dest, const mdds::mtv::base_element_block& src,
-        size_t begin_pos, size_t len)
-    {
-        switch (mtv::get_block_type(dest))
-        {
-            case element_type_user_block:
-                user_cell_block::assign_values_from_block(dest, src, begin_pos, len);
-            break;
-            case element_type_muser_block:
-                muser_cell_block::assign_values_from_block(dest, src, begin_pos, len);
-            break;
-            default:
-                mtv::element_block_func_base::assign_values_from_block(dest, src, begin_pos, len);
-        }
-    }
-
-    static bool equal_block(
-        const mdds::mtv::base_element_block& left, const mdds::mtv::base_element_block& right)
-    {
-        if (mtv::get_block_type(left) == element_type_user_block)
-        {
-            if (mtv::get_block_type(right) != element_type_user_block)
-                return false;
-
-            return user_cell_block::get(left) == user_cell_block::get(right);
-        }
-        else if (mtv::get_block_type(right) == element_type_user_block)
-            return false;
-
-        if (mtv::get_block_type(left) == element_type_muser_block)
-        {
-            if (mtv::get_block_type(right) != element_type_muser_block)
-                return false;
-
-            return muser_cell_block::get(left) == muser_cell_block::get(right);
-        }
-        else if (mtv::get_block_type(right) == element_type_muser_block)
-            return false;
-
-        return mtv::element_block_func_base::equal_block(left, right);
-    }
-
-    static void overwrite_values(mdds::mtv::base_element_block& block, size_t pos, size_t len)
-    {
-        switch (mtv::get_block_type(block))
-        {
-            case element_type_user_block:
-                // Do nothing.  The client code manages the life cycle of these cells.
-            break;
-            case element_type_muser_block:
-                muser_cell_block::overwrite_values(block, pos, len);
-            break;
-            default:
-                mtv::element_block_func_base::overwrite_values(block, pos, len);
-        }
-    }
-};
-
 namespace {
 
+typedef multi_type_vector<mtv::custom_block_func2<element_type_user_block, user_cell_block, element_type_muser_block, muser_cell_block> > mtv_type;
+typedef multi_type_vector<mtv::custom_block_func1<element_type_fruit_block, fruit_block> > mtv_fruit_type;
+
 template<typename _ColT, typename _ValT>
 bool test_cell_insertion(_ColT& col_db, size_t row, _ValT val)
 {
@@ -318,8 +125,6 @@ bool test_cell_insertion(_ColT& col_db, size_t row, _ValT val)
     return val == test;
 }
 
-typedef mdds::multi_type_vector<my_cell_block_func> mtv_type;
-
 void mtv_test_types()
 {
     stack_printer __stack_printer__("::mtv_test_types");
@@ -342,6 +147,10 @@ void mtv_test_types()
     user_cell* p = NULL;
     ct = mtv_type::get_element_type(p);
     assert(ct == element_type_user_block && ct >= mtv::element_type_user_start);
+    ct = mtv_type::get_element_type(static_cast<muser_cell*>(NULL));
+    assert(ct == element_type_muser_block && ct >= mtv::element_type_user_start);
+    ct = mtv_fruit_type::get_element_type(unknown_fruit);
+    assert(ct == element_type_fruit_block && ct >= mtv::element_type_user_start);
 }
 
 void mtv_test_basic()
@@ -1048,6 +857,466 @@ void mtv_test_managed_block()
         db.set_empty(1, 1);
         assert(db.block_size() == 1);
     }
+
+    {
+        // Release an element.
+        mtv_type db(1);
+        muser_cell* p = new muser_cell(4.5);
+        db.set(0, p);
+        muser_cell* p2 = db.release<muser_cell*>(0);
+        assert(p == p2);
+        assert(p2->value == 4.5);
+        assert(db.is_empty(0));
+        delete p2;
+
+        db = mtv_type(2);
+        db.set(0, new muser_cell(23.3));
+        assert(db.block_size() == 2);
+        p2 = db.release<muser_cell*>(0);
+        assert(db.is_empty(0));
+        assert(db.is_empty(1));
+        assert(db.block_size() == 1);
+        delete p2;
+
+        db = mtv_type(2);
+        db.set(0, new muser_cell(1.2));
+        db.set(1, new muser_cell(1.3));
+
+        p2 = db.release<muser_cell*>(0);
+        assert(db.is_empty(0));
+        assert(!db.is_empty(1));
+        assert(p2->value == 1.2);
+        delete p2;
+
+        db.set(0, new muser_cell(1.4));
+        p2 = db.release<muser_cell*>(1);
+        assert(!db.is_empty(0));
+        assert(db.is_empty(1));
+        assert(p2->value == 1.3);
+        delete p2;
+
+        db = mtv_type(3);
+        db.set(0, new muser_cell(2.1));
+        db.set(1, new muser_cell(2.2));
+        db.set(2, new muser_cell(2.3));
+
+        p2 = db.release<muser_cell*>(1);
+        assert(p2->value == 2.2);
+        assert(!db.is_empty(0));
+        assert(db.is_empty(1));
+        assert(!db.is_empty(2));
+
+        delete p2;
+
+        db = mtv_type(3);
+        db.set(0, new muser_cell(2.1));
+        db.set(1, new muser_cell(2.2));
+        db.set(2, new muser_cell(2.3));
+        db.set_empty(0, 2); // Make sure this doesn't release anything.
+    }
+}
+
+void mtv_test_custom_block_func1()
+{
+    stack_printer __stack_printer__("::mtv_test_custom_block_func1");
+    mtv_fruit_type db(10);
+    db.set(0, apple);
+    db.set(1, orange);
+    db.set(2, mango);
+    db.set(3, peach);
+    assert(db.block_size() == 2);
+    assert(db.get_type(0) == element_type_fruit_block);
+    assert(db.get<my_fruit_type>(0) == apple);
+    assert(db.get<my_fruit_type>(1) == orange);
+    assert(db.get<my_fruit_type>(2) == mango);
+    assert(db.get<my_fruit_type>(3) == peach);
+    db.set<int>(1, 234);
+    assert(db.block_size() == 4);
+    db.set(1, apple);
+    assert(db.block_size() == 2);
+}
+
+void mtv_test_transfer()
+{
+    stack_printer __stack_printer__("::mtv_test_transfer");
+    mtv_type db1(3), db2(4); // db2 is larger than db1.
+    db1.set(0, new muser_cell(1.1));
+    db1.set(1, new muser_cell(1.2));
+    db1.set(2, new muser_cell(1.3));
+    assert(db1.block_size() == 1);
+
+    try
+    {
+        db1.transfer(0, 1, db1, 0);
+        assert(!"Exception should have been thrown");
+    }
+    catch (const invalid_arg_error&)
+    {
+        // Good.
+    }
+
+    // Do the transfer.
+    db1.transfer(0, 2, db2, 0);
+
+    // Now db1 should be totally empty.
+    assert(db1.block_size() == 1);
+    mtv_type::iterator check = db1.begin();
+    assert(check != db1.end());
+    assert(check->type == mtv::element_type_empty);
+    assert(check->size == 3);
+
+    assert(db2.block_size() == 2);
+    assert(db2.get<muser_cell*>(0)->value == 1.1);
+    assert(db2.get<muser_cell*>(1)->value == 1.2);
+    assert(db2.get<muser_cell*>(2)->value == 1.3);
+    assert(db2.is_empty(3));
+
+    // Transfer back to db1. This should make db2 to be totally empty again.
+    db2.transfer(0, 2, db1, 0);
+    assert(db2.block_size() == 1);
+    check = db2.begin();
+    assert(check != db2.end());
+    assert(check->size == 4);
+    assert(check->type == mtv::element_type_empty);
+
+    assert(db1.block_size() == 1);
+    assert(db1.get<muser_cell*>(0)->value == 1.1);
+    assert(db1.get<muser_cell*>(1)->value == 1.2);
+    assert(db1.get<muser_cell*>(2)->value == 1.3);
+
+    // Now, transfer only the top 2 elements.
+    db1.transfer(0, 1, db2, 0);
+    assert(db1.is_empty(0));
+    assert(db1.is_empty(1));
+    assert(db1.get<muser_cell*>(2)->value == 1.3);
+
+    assert(db2.get<muser_cell*>(0)->value == 1.1);
+    assert(db2.get<muser_cell*>(1)->value == 1.2);
+    assert(db2.is_empty(2));
+    assert(db2.is_empty(3));
+
+    // .. and back.
+    db2.transfer(0, 1, db1, 0);
+    assert(db1.block_size() == 1);
+    assert(db1.get<muser_cell*>(0)->value == 1.1);
+    assert(db1.get<muser_cell*>(1)->value == 1.2);
+    assert(db1.get<muser_cell*>(2)->value == 1.3);
+
+    assert(db2.block_size() == 1);
+    check = db2.begin();
+    assert(check != db2.end());
+    assert(check->size == 4);
+    assert(check->type == mtv::element_type_empty);
+
+    db1 = mtv_type(4);
+    db2 = mtv_type(4);
+    db2.set(1, new muser_cell(2.1));
+    db2.set(2, new muser_cell(2.2));
+    assert(db2.block_size() == 3);
+    db1.transfer(0, 1, db2, 1); // This causes db2's 3 blocks to merge into one.
+    assert(db2.block_size() == 1);
+    check = db2.begin();
+    assert(check != db2.end());
+    assert(check->size == 4);
+    assert(check->type == mtv::element_type_empty);
+    assert(db1.block_size() == 1);
+    check = db1.begin();
+    assert(check != db1.end());
+    assert(check->size == 4);
+    assert(check->type == mtv::element_type_empty);
+
+    db2.set(0, new muser_cell(3.1));
+    assert(db2.block_size() == 2);
+
+    db1.set(1, new muser_cell(3.2));
+    db1.set(2, new muser_cell(3.3));
+    db1.set(3, new muser_cell(3.4));
+    assert(db1.block_size() == 2);
+
+    db1.transfer(1, 2, db2, 1);
+    assert(db1.block_size() == 2);
+    assert(db1.is_empty(0));
+    assert(db1.is_empty(1));
+    assert(db1.is_empty(2));
+    assert(db1.get<muser_cell*>(3)->value == 3.4);
+    assert(db2.block_size() == 2);
+    assert(db2.get<muser_cell*>(0)->value == 3.1);
+    assert(db2.get<muser_cell*>(1)->value == 3.2);
+    assert(db2.get<muser_cell*>(2)->value == 3.3);
+    assert(db2.is_empty(3));
+
+    db1 = mtv_type(3);
+    db2 = mtv_type(3);
+    db1.set(1, new muser_cell(4.2));
+    db2.set(0, new muser_cell(4.1));
+    db2.set(2, new muser_cell(4.3));
+
+    db1.transfer(1, 1, db2, 1);
+    assert(db1.block_size() == 1);
+    check = db1.begin();
+    assert(check != db1.end());
+    assert(check->size == 3);
+    assert(check->type == mtv::element_type_empty);
+    assert(db2.block_size() == 1);
+    assert(db2.get<muser_cell*>(0)->value == 4.1);
+    assert(db2.get<muser_cell*>(1)->value == 4.2);
+    assert(db2.get<muser_cell*>(2)->value == 4.3);
+
+    // Transfer to middle of block.
+    db1 = mtv_type(3);
+    db2 = mtv_type(3);
+    db1.set(0, new muser_cell(5.2));
+    assert(db1.block_size() == 2);
+    db1.transfer(0, 0, db2, 1);
+    assert(db1.block_size() == 1);
+    check = db1.begin();
+    assert(check != db1.end());
+    assert(check->size == 3);
+    assert(check->type == mtv::element_type_empty);
+    assert(db2.block_size() == 3);
+    assert(db2.is_empty(0));
+    assert(db2.get<muser_cell*>(1)->value == 5.2);
+    assert(db2.is_empty(2));
+
+    db1 = mtv_type(2);
+    db2 = mtv_type(3);
+    db1.set(0, new muser_cell(11.1));
+    db1.set(1, new muser_cell(11.2));
+    db1.transfer(1, 1, db2, 1);
+    assert(db1.block_size() == 2);
+    assert(db1.get<muser_cell*>(0)->value == 11.1);
+    assert(db1.is_empty(1));
+    assert(db2.block_size() == 3);
+    assert(db2.is_empty(0));
+    assert(db2.get<muser_cell*>(1)->value == 11.2);
+    assert(db2.is_empty(2));
+
+    // Transfer to bottom of block.
+    db1 = mtv_type(4);
+    db2 = mtv_type(5);
+    db1.set(0, new muser_cell(6.1));
+    db1.set(1, new muser_cell(6.2));
+    db1.transfer(0, 1, db2, 3);
+    assert(db1.block_size() == 1);
+    check = db1.begin();
+    assert(check != db1.end());
+    assert(check->size == 4);
+    assert(check->type == mtv::element_type_empty);
+    assert(db2.block_size() == 2);
+    assert(db2.is_empty(0));
+    assert(db2.is_empty(1));
+    assert(db2.is_empty(2));
+    assert(db2.get<muser_cell*>(3)->value == 6.1);
+    assert(db2.get<muser_cell*>(4)->value == 6.2);
+
+    // Transfer multiple blocks.  Very simple use case.
+    db1 = mtv_type(4);
+    db2 = mtv_type(3);
+    db1.set(1, new muser_cell(10.1));
+    db1.set(3, new muser_cell(10.2));
+    db1.transfer(1, 3, db2, 0);
+
+    // db1 should be completely empty.
+    assert(db1.block_size() == 1);
+    check = db1.begin();
+    assert(check != db1.end());
+    assert(check->size == 4);
+    assert(check->type == mtv::element_type_empty);
+
+    assert(db2.block_size() == 3);
+    assert(db2.get<muser_cell*>(0)->value == 10.1);
+    assert(db2.is_empty(1));
+    assert(db2.get<muser_cell*>(2)->value == 10.2);
+
+    // Multiple-block transfer that involves merging.
+    db1 = mtv_type(5);
+    db2 = mtv_type(5);
+    db1.set(0, new muser_cell(0.1));
+    db1.set(1, new muser_cell(0.2));
+    db1.set(3, new muser_cell(0.3));
+    db1.set(4, new muser_cell(0.4));
+
+    db2.set(0, new muser_cell(1.1));
+    db2.set(4, new muser_cell(1.2));
+
+    mtv_type::iterator it = db1.transfer(1, 3, db2, 1);
+    assert(db1.block_size() == 3);
+    assert(db1.get<muser_cell*>(0)->value == 0.1);
+    assert(db1.is_empty(1));
+    assert(db1.is_empty(2));
+    assert(db1.is_empty(3));
+    assert(db1.get<muser_cell*>(4)->value == 0.4);
+
+    assert(db2.block_size() == 3);
+    assert(db2.get<muser_cell*>(0)->value == 1.1);
+    assert(db2.get<muser_cell*>(1)->value == 0.2);
+    assert(db2.is_empty(2));
+    assert(db2.get<muser_cell*>(3)->value == 0.3);
+    assert(db2.get<muser_cell*>(4)->value == 1.2);
+
+    assert(it != db1.end());
+    assert(it->size == 3);
+    assert(it->type == mtv::element_type_empty);
+    it = db1.transfer(it, 4, 4, db2, 2); // Transfer single element at 4.
+    assert(db1.block_size() == 2);
+    assert(db1.get<muser_cell*>(0)->value == 0.1);
+    assert(db1.is_empty(1));
+    assert(db1.is_empty(2));
+    assert(db1.is_empty(3));
+    assert(db1.is_empty(4));
+
+    assert(db2.block_size() == 1);
+    assert(db2.get<muser_cell*>(0)->value == 1.1);
+    assert(db2.get<muser_cell*>(1)->value == 0.2);
+    assert(db2.get<muser_cell*>(2)->value == 0.4);
+    assert(db2.get<muser_cell*>(3)->value == 0.3);
+    assert(db2.get<muser_cell*>(4)->value == 1.2);
+
+    assert(it != db1.end());
+    assert(it->size == 4);
+    assert(it->type == mtv::element_type_empty);
+    ++it;
+    assert(it == db1.end());
+
+    // Multi-block transfer to the top part of destination block.
+    db1 = mtv_type(5);
+    db2 = mtv_type(5);
+    db1.set(0, new muser_cell(-1.1));
+    db1.set(1, new muser_cell(-2.1));
+    db1.set(2, new muser_cell(-3.1));
+    db1.set(3, string("foo"));
+    db1.set(4, new muser_cell(-5.1));
+    db2.set(1, true);
+    db2.set(2, false);
+    db2.set(3, true);
+    it = db1.transfer(2, 3, db2, 2);
+    assert(it != db1.end());
+    assert(it->size == 2);
+    assert(it->type == mtv::element_type_empty);
+    std::advance(it, 2);
+    assert(it == db1.end());
+    assert(db1.block_size() == 3);
+    assert(db1.get<muser_cell*>(0)->value == -1.1);
+    assert(db1.get<muser_cell*>(1)->value == -2.1);
+    assert(db1.is_empty(2));
+    assert(db1.is_empty(3));
+    assert(db1.get<muser_cell*>(4)->value == -5.1);
+
+    assert(db2.block_size() == 5);
+    assert(db2.is_empty(0));
+    assert(db2.get<bool>(1) == true);
+    assert(db2.get<muser_cell*>(2)->value == -3.1);
+    assert(db2.get<string>(3) == "foo");
+    assert(db2.is_empty(4));
+
+    // Multi-block transfer to the bottom part of destination block.
+    db1 = mtv_type(10);
+    db2 = mtv_type(10);
+    db1.set(0, new muser_cell(2.1));
+    db1.set(1, new muser_cell(2.2));
+    db1.set(2, char('a'));
+    db1.set(3, char('b'));
+    db2.set(0, true);
+    db2.set(1, false);
+
+    it = db1.transfer(0, 2, db2, 7);
+    assert(it != db1.end());
+    assert(it->size == 3);
+    assert(it->type == mtv::element_type_empty);
+    ++it;
+    assert(it != db1.end());
+    assert(it->size == 1);
+    assert(it->type == mtv::element_type_char);
+    ++it;
+    assert(it != db1.end());
+    assert(it->size == 6);
+    assert(it->type == mtv::element_type_empty);
+    ++it;
+    assert(it == db1.end());
+    assert(db1.block_size() == 3);
+    assert(db1.get<char>(3) == 'b');
+
+    assert(db2.block_size() == 4);
+    assert(db2.get<bool>(0) == true);
+    assert(db2.get<bool>(1) == false);
+    assert(db2.is_empty(2));
+    assert(db2.is_empty(3));
+    assert(db2.is_empty(4));
+    assert(db2.is_empty(5));
+    assert(db2.is_empty(6));
+    assert(db2.get<muser_cell*>(7)->value == 2.1);
+    assert(db2.get<muser_cell*>(8)->value == 2.2);
+    assert(db2.get<char>(9) == 'a');
+
+    // Multi-block transfer to the middle part of destination block.
+    db1 = mtv_type(10);
+    db2 = mtv_type(10);
+    db2.set(0, true);
+    db2.set(9, true);
+    db1.set(3, new muser_cell(2.4));
+    db1.set(4, new muser_cell(2.5));
+    db1.set(5, string("abc"));
+    db1.set(6, new muser_cell(2.6));
+    db1.set(7, new muser_cell(2.7));
+    db1.set(8, true);
+    it = db1.transfer(3, 6, db2, 2);
+    assert(it != db1.end());
+    assert(it->size == 7);
+    assert(it->type == mtv::element_type_empty);
+    ++it;
+    assert(it != db1.end());
+    assert(it->size == 1);
+    assert(it->type == element_type_muser_block);
+    ++it;
+    assert(it->size == 1);
+    assert(it->type == mtv::element_type_boolean);
+    ++it;
+    assert(it->size == 1);
+    assert(it->type == mtv::element_type_empty);
+    ++it;
+    assert(it == db1.end());
+
+    assert(db1.block_size() == 4);
+    assert(db1.is_empty(6));
+    assert(db1.get<muser_cell*>(7)->value == 2.7);
+    assert(db1.get<bool>(8) == true);
+    assert(db1.is_empty(9));
+
+    assert(db2.block_size() == 7);
+    assert(db2.get<bool>(0) == true);
+    assert(db2.is_empty(1));
+    assert(db2.get<muser_cell*>(2)->value == 2.4);
+    assert(db2.get<muser_cell*>(3)->value == 2.5);
+    assert(db2.get<string>(4) == "abc");
+    assert(db2.get<muser_cell*>(5)->value == 2.6);
+    assert(db2.is_empty(6));
+    assert(db2.is_empty(7));
+    assert(db2.is_empty(8));
+    assert(db2.get<bool>(9) == true);
+
+    db1 = mtv_type(10);
+    db2 = mtv_type(10);
+    db1.set(3, true);
+    db2.set(3, string("test"));
+    db1.transfer(0, 6, db2, 0);
+    assert(db1.block_size() == 1);
+    check = db1.begin();
+    assert(check != db1.end());
+    assert(check->size == 10);
+    assert(check->type == mtv::element_type_empty);
+    ++check;
+    assert(check == db1.end());
+    assert(db2.block_size() == 3);
+    assert(db2.is_empty(0));
+    assert(db2.is_empty(1));
+    assert(db2.is_empty(2));
+    assert(db2.get<bool>(3) == true);
+    assert(db2.is_empty(4));
+    assert(db2.is_empty(5));
+    assert(db2.is_empty(6));
+    assert(db2.is_empty(7));
+    assert(db2.is_empty(8));
+    assert(db2.is_empty(9));
 }
 
 }
@@ -1064,6 +1333,8 @@ int main (int argc, char **argv)
         mtv_test_basic();
         mtv_test_equality();
         mtv_test_managed_block();
+        mtv_test_custom_block_func1();
+        mtv_test_transfer();
     }
 
     if (opt.test_perf)
diff --git a/src/multi_type_vector_test_default.cpp b/src/multi_type_vector_test_default.cpp
index 1a18dcc..31d43ec 100644
--- a/src/multi_type_vector_test_default.cpp
+++ b/src/multi_type_vector_test_default.cpp
@@ -58,7 +58,7 @@ bool test_cell_insertion(_ColT& col_db, size_t row, _ValT val)
 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
+    _bool, _short, _ushort, _int, _uint, _long, _ulong, _double, _string, _char, _uchar
 };
 
 #define TEST_TYPE(_type_,_type_enum_) test_mtv_type test_type(_type_) { return _type_enum_; }
@@ -71,6 +71,8 @@ TEST_TYPE(long,_long)
 TEST_TYPE(unsigned long,_ulong)
 TEST_TYPE(double,_double)
 TEST_TYPE(string,_string)
+TEST_TYPE(char,_char)
+TEST_TYPE(unsigned char,_uchar)
 
 void mtv_test_types()
 {
@@ -122,6 +124,16 @@ void mtv_test_types()
         assert(test_type(val) == _string);
         cout << "string is good" << endl;
     }
+    {
+        char val = 0;
+        assert(test_type(val) == _char);
+        cout << "char is good" << endl;
+    }
+    {
+        unsigned char val = 0;
+        assert(test_type(val) == _uchar);
+        cout << "unsigned char is good" << endl;
+    }
 }
 
 void mtv_test_construction()
@@ -714,6 +726,46 @@ void mtv_test_basic()
         assert(db.get<double>(6) == 1.2);
         assert(db.get<bool>(7) == true);
     }
+
+    {
+        mtv_type db(10, false);
+        db.set<char>(0, 'a');
+        db.set<char>(1, 'b');
+        db.set<char>(2, 'c');
+
+        db.set<unsigned char>(3, 'd');
+        db.set<unsigned char>(4, 'e');
+        db.set<unsigned char>(5, 'f');
+
+        assert(db.block_size() == 3);
+        db.set<char>(0, 'r'); // overwrite.
+        db.set<unsigned char>(5, 'z'); // overwrite
+
+        assert(db.block_size() == 3);
+        mtv_type::const_iterator it = db.begin();
+        assert(it != db.end());
+        assert(it->type == mtv::element_type_char);
+        {
+            const char* p = &mtv::char_element_block::at(*it->data, 0);
+            assert(*p == 'r');
+            ++p;
+            assert(*p == 'b');
+            ++p;
+            assert(*p == 'c');
+        }
+
+        ++it;
+        assert(it != db.end());
+        assert(it->type == mtv::element_type_uchar);
+        {
+            const unsigned char* p = &mtv::uchar_element_block::at(*it->data, 0);
+            assert(*p == 'd');
+            ++p;
+            assert(*p == 'e');
+            ++p;
+            assert(*p == 'z');
+        }
+    }
 }
 
 void mtv_test_empty_cells()
@@ -2388,6 +2440,18 @@ void mtv_test_data_iterators()
         assert(*it_data == 1.3);
         ++it_data;
         assert(it_data == it_data_end);
+
+        assert(mtv::numeric_element_block::at(*it_blk->data, 0) == 1.1);
+        assert(mtv::numeric_element_block::at(*it_blk->data, 1) == 1.2);
+        assert(mtv::numeric_element_block::at(*it_blk->data, 2) == 1.3);
+
+        // Access the underlying data array directly.
+        const double* array = &mtv::numeric_element_block::at(*it_blk->data, 0);
+        assert(*array == 1.1);
+        ++array;
+        assert(*array == 1.2);
+        ++array;
+        assert(*array == 1.3);
     }
 
     // Next block is empty.
@@ -3947,6 +4011,62 @@ void mtv_test_insert_empty_with_position()
     assert(check == db.end());
 }
 
+void mtv_test_position()
+{
+    stack_printer __stack_printer__("::mtv_test_position");
+    mtv_type db(10, false);
+    mtv_type::iterator check;
+    db.set(6, 1.1);
+    db.set(7, 1.2);
+    db.set(8, 1.3);
+    db.set(9, 1.4);
+
+    pair<mtv_type::iterator,mtv_type::size_type> pos = db.position(0);
+    assert(pos.first == db.begin());
+    assert(pos.second == 0);
+
+    pos = db.position(1);
+    assert(pos.first == db.begin());
+    assert(pos.second == 1);
+
+    pos = db.position(5);
+    assert(pos.first == db.begin());
+    assert(pos.second == 5);
+
+    check = db.begin();
+    ++check;
+
+    // These positions should be on the 2nd block.
+
+    pos = db.position(6);
+    assert(pos.first == check);
+    assert(pos.second == 0);
+
+    pos = db.position(7);
+    assert(pos.first == check);
+    assert(pos.second == 1);
+
+    pos = db.position(9);
+    assert(pos.first == check);
+    assert(pos.second == 3);
+
+    {
+        // Make sure you get the right element.
+        mtv_type::iterator it = pos.first;
+        assert(it->type == mtv::element_type_numeric);
+        assert(it->data);
+        mtv::numeric_element_block::iterator it_elem = mtv::numeric_element_block::begin(*it->data);
+        advance(it_elem, pos.second);
+        assert(*it_elem == 1.4);
+    }
+
+    // Quick check for the const variant.
+    const mtv_type& db_ref = db;
+    pair<mtv_type::const_iterator,mtv_type::size_type> const_pos = db_ref.position(3);
+    assert(const_pos.first == db_ref.begin());
+    assert(const_pos.second == 3);
+}
+
 void mtv_perf_test_block_position_lookup()
 {
     size_t n = 24000;
@@ -4022,6 +4142,7 @@ int main (int argc, char **argv)
         mtv_test_insert_cells_with_position();
         mtv_test_set_empty_with_position();
         mtv_test_insert_empty_with_position();
+        mtv_test_position();
     }
 
     if (opt.test_perf)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-openoffice/mdds.git


Reply to: