Containers (STL-compatible) StateMachines MessageBus and more for Embedded Systems. See www.etlcpp.com

Files at this revision

API Documentation at this revision

Comitter:
bobbery
Date:
Fri Mar 16 16:34:18 2018 +0000
Commit message:
Works after using gcc_generic undef CAPACITY and replacing nullptr by std::nullptr

Changed in this revision

algorithm.h Show annotated file Show diff for this revision Revisions of this file
alignment.h Show annotated file Show diff for this revision Revisions of this file
array.h Show annotated file Show diff for this revision Revisions of this file
array_view.h Show annotated file Show diff for this revision Revisions of this file
array_wrapper.h Show annotated file Show diff for this revision Revisions of this file
atomic.h Show annotated file Show diff for this revision Revisions of this file
atomic/atomic_arm.h Show annotated file Show diff for this revision Revisions of this file
atomic/atomic_gcc.h Show annotated file Show diff for this revision Revisions of this file
atomic/atomic_windows.h Show annotated file Show diff for this revision Revisions of this file
basic_string.h Show annotated file Show diff for this revision Revisions of this file
binary.cpp Show annotated file Show diff for this revision Revisions of this file
binary.h Show annotated file Show diff for this revision Revisions of this file
bitset.h Show annotated file Show diff for this revision Revisions of this file
bloom_filter.h Show annotated file Show diff for this revision Revisions of this file
c/ecl_timer.c Show annotated file Show diff for this revision Revisions of this file
c/ecl_timer.h Show annotated file Show diff for this revision Revisions of this file
callback.h Show annotated file Show diff for this revision Revisions of this file
callback_timer.h Show annotated file Show diff for this revision Revisions of this file
char_traits.h Show annotated file Show diff for this revision Revisions of this file
checksum.h Show annotated file Show diff for this revision Revisions of this file
compare.h Show annotated file Show diff for this revision Revisions of this file
constant.h Show annotated file Show diff for this revision Revisions of this file
container.h Show annotated file Show diff for this revision Revisions of this file
crc16.cpp Show annotated file Show diff for this revision Revisions of this file
crc16.h Show annotated file Show diff for this revision Revisions of this file
crc16_ccitt.cpp Show annotated file Show diff for this revision Revisions of this file
crc16_ccitt.h Show annotated file Show diff for this revision Revisions of this file
crc16_kermit.cpp Show annotated file Show diff for this revision Revisions of this file
crc16_kermit.h Show annotated file Show diff for this revision Revisions of this file
crc32.cpp Show annotated file Show diff for this revision Revisions of this file
crc32.h Show annotated file Show diff for this revision Revisions of this file
crc64_ecma.cpp Show annotated file Show diff for this revision Revisions of this file
crc64_ecma.h Show annotated file Show diff for this revision Revisions of this file
crc8_ccitt.cpp Show annotated file Show diff for this revision Revisions of this file
crc8_ccitt.h Show annotated file Show diff for this revision Revisions of this file
cstring.h Show annotated file Show diff for this revision Revisions of this file
cyclic_value.h Show annotated file Show diff for this revision Revisions of this file
debounce.h Show annotated file Show diff for this revision Revisions of this file
debug_count.h Show annotated file Show diff for this revision Revisions of this file
deque.h Show annotated file Show diff for this revision Revisions of this file
doxygen.h Show annotated file Show diff for this revision Revisions of this file
ecl_user.h Show annotated file Show diff for this revision Revisions of this file
endianness.h Show annotated file Show diff for this revision Revisions of this file
enum_type.h Show annotated file Show diff for this revision Revisions of this file
error_handler.cpp Show annotated file Show diff for this revision Revisions of this file
error_handler.h Show annotated file Show diff for this revision Revisions of this file
etl_profile.h Show annotated file Show diff for this revision Revisions of this file
exception.h Show annotated file Show diff for this revision Revisions of this file
factorial.h Show annotated file Show diff for this revision Revisions of this file
factory.h Show annotated file Show diff for this revision Revisions of this file
fibonacci.h Show annotated file Show diff for this revision Revisions of this file
fixed_iterator.h Show annotated file Show diff for this revision Revisions of this file
flat_map.h Show annotated file Show diff for this revision Revisions of this file
flat_multimap.h Show annotated file Show diff for this revision Revisions of this file
flat_multiset.h Show annotated file Show diff for this revision Revisions of this file
flat_set.h Show annotated file Show diff for this revision Revisions of this file
fnv_1.h Show annotated file Show diff for this revision Revisions of this file
forward_list.h Show annotated file Show diff for this revision Revisions of this file
frame_check_sequence.h Show annotated file Show diff for this revision Revisions of this file
fsm.h Show annotated file Show diff for this revision Revisions of this file
fsm_generator.h Show annotated file Show diff for this revision Revisions of this file
function.h Show annotated file Show diff for this revision Revisions of this file
functional.h Show annotated file Show diff for this revision Revisions of this file
hash.h Show annotated file Show diff for this revision Revisions of this file
icache.h Show annotated file Show diff for this revision Revisions of this file
ihash.h Show annotated file Show diff for this revision Revisions of this file
instance_count.h Show annotated file Show diff for this revision Revisions of this file
integral_limits.h Show annotated file Show diff for this revision Revisions of this file
intrusive_forward_list.h Show annotated file Show diff for this revision Revisions of this file
intrusive_links.h Show annotated file Show diff for this revision Revisions of this file
intrusive_list.h Show annotated file Show diff for this revision Revisions of this file
intrusive_queue.h Show annotated file Show diff for this revision Revisions of this file
intrusive_stack.h Show annotated file Show diff for this revision Revisions of this file
io_port.h Show annotated file Show diff for this revision Revisions of this file
iterator.h Show annotated file Show diff for this revision Revisions of this file
jenkins.h Show annotated file Show diff for this revision Revisions of this file
largest.h Show annotated file Show diff for this revision Revisions of this file
largest_generator.h Show annotated file Show diff for this revision Revisions of this file
list.h Show annotated file Show diff for this revision Revisions of this file
log.h Show annotated file Show diff for this revision Revisions of this file
map.h Show annotated file Show diff for this revision Revisions of this file
memory.h Show annotated file Show diff for this revision Revisions of this file
message.h Show annotated file Show diff for this revision Revisions of this file
message_bus.h Show annotated file Show diff for this revision Revisions of this file
message_router.h Show annotated file Show diff for this revision Revisions of this file
message_router_generator.h Show annotated file Show diff for this revision Revisions of this file
message_timer.h Show annotated file Show diff for this revision Revisions of this file
message_types.h Show annotated file Show diff for this revision Revisions of this file
multimap.h Show annotated file Show diff for this revision Revisions of this file
multiset.h Show annotated file Show diff for this revision Revisions of this file
murmur3.h Show annotated file Show diff for this revision Revisions of this file
nullptr.h Show annotated file Show diff for this revision Revisions of this file
numeric.h Show annotated file Show diff for this revision Revisions of this file
observer.h Show annotated file Show diff for this revision Revisions of this file
optional.h Show annotated file Show diff for this revision Revisions of this file
packet.h Show annotated file Show diff for this revision Revisions of this file
parameter_type.h Show annotated file Show diff for this revision Revisions of this file
pearson.cpp Show annotated file Show diff for this revision Revisions of this file
pearson.h Show annotated file Show diff for this revision Revisions of this file
platform.h Show annotated file Show diff for this revision Revisions of this file
pool.h Show annotated file Show diff for this revision Revisions of this file
power.h Show annotated file Show diff for this revision Revisions of this file
priority_queue.h Show annotated file Show diff for this revision Revisions of this file
private/ivectorpointer.h Show annotated file Show diff for this revision Revisions of this file
private/pvoidvector.cpp Show annotated file Show diff for this revision Revisions of this file
private/pvoidvector.h Show annotated file Show diff for this revision Revisions of this file
private/vector_base.h Show annotated file Show diff for this revision Revisions of this file
profiles/arduino_arm.h Show annotated file Show diff for this revision Revisions of this file
profiles/armv5.h Show annotated file Show diff for this revision Revisions of this file
profiles/armv6.h Show annotated file Show diff for this revision Revisions of this file
profiles/cpp03.h Show annotated file Show diff for this revision Revisions of this file
profiles/cpp11.h Show annotated file Show diff for this revision Revisions of this file
profiles/cpp14.h Show annotated file Show diff for this revision Revisions of this file
profiles/gcc_generic.h Show annotated file Show diff for this revision Revisions of this file
profiles/gcc_linux_x86.h Show annotated file Show diff for this revision Revisions of this file
profiles/gcc_windows_x86.h Show annotated file Show diff for this revision Revisions of this file
profiles/msvc_x86.h Show annotated file Show diff for this revision Revisions of this file
profiles/ticc.h Show annotated file Show diff for this revision Revisions of this file
queue.h Show annotated file Show diff for this revision Revisions of this file
radix.h Show annotated file Show diff for this revision Revisions of this file
random.cpp Show annotated file Show diff for this revision Revisions of this file
random.h Show annotated file Show diff for this revision Revisions of this file
ratio.h Show annotated file Show diff for this revision Revisions of this file
reference_flat_map.h Show annotated file Show diff for this revision Revisions of this file
reference_flat_multimap.h Show annotated file Show diff for this revision Revisions of this file
reference_flat_multiset.h Show annotated file Show diff for this revision Revisions of this file
reference_flat_set.h Show annotated file Show diff for this revision Revisions of this file
scheduler.h Show annotated file Show diff for this revision Revisions of this file
set.h Show annotated file Show diff for this revision Revisions of this file
smallest.h Show annotated file Show diff for this revision Revisions of this file
smallest_generator.h Show annotated file Show diff for this revision Revisions of this file
sqrt.h Show annotated file Show diff for this revision Revisions of this file
stack.h Show annotated file Show diff for this revision Revisions of this file
static_assert.h Show annotated file Show diff for this revision Revisions of this file
string_view.h Show annotated file Show diff for this revision Revisions of this file
task.h Show annotated file Show diff for this revision Revisions of this file
temp.h Show annotated file Show diff for this revision Revisions of this file
timer.h Show annotated file Show diff for this revision Revisions of this file
type_def.h Show annotated file Show diff for this revision Revisions of this file
type_lookup.h Show annotated file Show diff for this revision Revisions of this file
type_lookup_generator.h Show annotated file Show diff for this revision Revisions of this file
type_traits.h Show annotated file Show diff for this revision Revisions of this file
type_traits_generator.h Show annotated file Show diff for this revision Revisions of this file
u16string.h Show annotated file Show diff for this revision Revisions of this file
u32string.h Show annotated file Show diff for this revision Revisions of this file
unordered_map.h Show annotated file Show diff for this revision Revisions of this file
unordered_multimap.h Show annotated file Show diff for this revision Revisions of this file
unordered_multiset.h Show annotated file Show diff for this revision Revisions of this file
unordered_set.h Show annotated file Show diff for this revision Revisions of this file
user_type.h Show annotated file Show diff for this revision Revisions of this file
utility.h Show annotated file Show diff for this revision Revisions of this file
variant.h Show annotated file Show diff for this revision Revisions of this file
variant_pool.h Show annotated file Show diff for this revision Revisions of this file
vector.h Show annotated file Show diff for this revision Revisions of this file
visitor.h Show annotated file Show diff for this revision Revisions of this file
wstring.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/algorithm.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1120 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_ALGORITHM__
+#define __ETL_ALGORITHM__
+
+///\defgroup algorithm algorithm
+/// Reverse engineered algorithms from C++ 0x11
+/// Additional new variants of certain algorithms.
+///\ingroup utilities
+
+#include <algorithm>
+#include <iterator>
+#include <utility>
+#include <functional>
+#include <iterator>
+#include <stdint.h>
+
+#include "platform.h"
+#include "iterator.h"
+#include "type_traits.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Finds the greatest and the smallest element in the range (begin, end).<br>
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/minmax_element"></a>
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TIterator,
+            typename TCompare>
+  std::pair<TIterator, TIterator> minmax_element(TIterator begin,
+                                                 TIterator end,
+                                                 TCompare  compare)
+  {
+    TIterator minimum = begin;
+    TIterator maximum = begin;
+
+    while (begin != end)
+    {
+      if (compare(*begin, *minimum))
+      {
+        minimum = begin;
+      }
+
+      if (compare(*maximum, *begin))
+      {
+        maximum = begin;
+      }
+
+      ++begin;
+    }
+
+    return std::pair<TIterator, TIterator>(minimum, maximum);
+  }
+
+  //***************************************************************************
+  /// minmax_element
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/minmax_element"></a>
+  //***************************************************************************
+  template <typename TIterator>
+  std::pair<TIterator, TIterator> minmax_element(TIterator begin,
+                                                 TIterator end)
+  {
+      typedef typename std::iterator_traits<TIterator>::value_type value_t;
+
+      return etl::minmax_element(begin, end, std::less<value_t>());
+  }
+
+  //***************************************************************************
+  /// minmax
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/minmax"></a>
+  //***************************************************************************
+  template <typename T>
+  std::pair<const T&, const T&> minmax(const T& a,
+                                       const T& b)
+  {
+    return (b < a) ? std::pair<const T&, const T&>(b, a) : std::pair<const T&, const T&>(a, b);
+  }
+
+  //***************************************************************************
+  /// minmax
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/minmax"></a>
+  //***************************************************************************
+  template <typename T,
+            typename TCompare>
+  std::pair<const T&, const T&> minmax(const T& a,
+                                       const T& b,
+                                       TCompare compare)
+  {
+    return compare(b, a) ? std::pair<const T&, const T&>(b, a) : std::pair<const T&, const T&>(a, b);
+  }
+
+  //***************************************************************************
+  /// is_sorted_until
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_sorted_until"></a>
+  //***************************************************************************
+  template <typename TIterator>
+  TIterator is_sorted_until(TIterator begin,
+                            TIterator end)
+  {
+    if (begin != end)
+    {
+      TIterator next = begin;
+
+      while (++next != end)
+      {
+        if (*next < *begin)
+        {
+          return next;
+        }
+
+        ++begin;
+      }
+    }
+
+    return end;
+  }
+
+  //***************************************************************************
+  /// is_sorted_until
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_sorted_until"></a>
+  //***************************************************************************
+  template <typename TIterator,
+            typename TCompare>
+  TIterator is_sorted_until(TIterator begin,
+                            TIterator end,
+                            TCompare  compare)
+  {
+    if (begin != end)
+    {
+      TIterator next = begin;
+
+      while (++next != end)
+      {
+        if (compare(*next, *begin))
+        {
+          return next;
+        }
+
+        ++begin;
+      }
+    }
+
+    return end;
+  }
+
+  //***************************************************************************
+  /// is_sorted
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_sorted"></a>
+  //***************************************************************************
+  template<typename TIterator>
+  bool is_sorted(TIterator begin,
+                 TIterator end)
+  {
+    return etl::is_sorted_until(begin, end) == end;
+  }
+
+  //***************************************************************************
+  /// is_sorted
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_sorted"></a>
+  //***************************************************************************
+  template<typename TIterator,
+           typename TCompare>
+  bool is_sorted(TIterator begin,
+                 TIterator end,
+                 TCompare  compare)
+  {
+    return etl::is_sorted_until(begin, end, compare) == end;
+  }
+
+  //***************************************************************************
+  /// copy
+  /// A form of copy where the smallest of the two ranges is used.
+  /// There is currently no STL equivalent.
+  /// Specialisation for random access iterators.
+  ///\param i_begin Beginning of the input range.
+  ///\param i_end   End of the input range.
+  ///\param o_begin Beginning of the output range.
+  ///\param o_end   End of the output range.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator,
+            typename TOutputIterator>
+  typename etl::enable_if<etl::is_random_iterator<TInputIterator>::value &&
+                          etl::is_random_iterator<TOutputIterator>::value, TOutputIterator>::type
+   copy(TInputIterator  i_begin,
+        TInputIterator  i_end,
+        TOutputIterator o_begin,
+        TOutputIterator o_end)
+  {
+      size_t s_size = std::distance(i_begin, i_end);
+      size_t d_size = std::distance(o_begin, o_end);
+      size_t size   = (s_size < d_size) ? s_size : d_size;
+
+      return std::copy(i_begin, i_begin + size, o_begin);
+  }
+
+  //***************************************************************************
+  /// copy
+  /// A form of copy where the smallest of the two ranges is used.
+  /// There is currently no STL equivalent.
+  /// Specialisation for non random access iterators.
+  ///\param i_begin Beginning of the input range.
+  ///\param i_end   End of the input range.
+  ///\param o_begin Beginning of the output range.
+  ///\param o_end   End of the output range.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator,
+            typename TOutputIterator>
+  typename etl::enable_if<!etl::is_random_iterator<TInputIterator>::value ||
+                          !etl::is_random_iterator<TOutputIterator>::value, TOutputIterator>::type
+   copy(TInputIterator  i_begin,
+        TInputIterator  i_end,
+        TOutputIterator o_begin,
+        TOutputIterator o_end)
+  {
+    while ((i_begin != i_end) && (o_begin != o_end))
+    {
+      *o_begin++ = *i_begin++;
+    }
+
+    return o_begin;
+  }
+
+  //***************************************************************************
+  /// copy_n (Random input iterators)
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/copy_n"></a>
+  //***************************************************************************
+  template <typename TInputIterator,
+            typename TSize,
+            typename TOutputIterator>
+  typename etl::enable_if<etl::is_random_iterator<TInputIterator>::value, TOutputIterator>::type
+   copy_n(TInputIterator  i_begin,
+          TSize           n,
+          TOutputIterator o_begin)
+  {
+    return std::copy(i_begin, i_begin + n, o_begin);
+  }
+
+  //***************************************************************************
+  /// copy_n (Non-random input iterators)
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/copy_n"></a>
+  //***************************************************************************
+  template <typename TInputIterator,
+            typename TSize,
+            typename TOutputIterator>
+  typename etl::enable_if<!etl::is_random_iterator<TInputIterator>::value, TOutputIterator>::type
+   copy_n(TInputIterator  i_begin,
+          TSize           n,
+          TOutputIterator o_begin)
+  {
+    while (n-- > 0)
+    {
+      *o_begin++ = *i_begin++;
+    }
+
+    return o_begin;
+  }
+
+  //***************************************************************************
+  /// copy_n
+  /// A form of copy_n where the smallest of the two ranges is used.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator,
+            typename TSize,
+            typename TOutputIterator>
+  TOutputIterator copy_n(TInputIterator  i_begin,
+                         TSize           n,
+                         TOutputIterator o_begin,
+                         TOutputIterator o_end)
+  {
+    while ((n-- > 0) && (o_begin != o_end))
+    {
+      *o_begin++ = *i_begin++;
+    }
+
+    return o_begin;
+  }
+
+  //***************************************************************************
+  /// copy_n
+  /// A form of copy_n where the smallest of the two ranges is used.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator,
+            typename TSize1,
+            typename TOutputIterator,
+            typename TSize2>
+  TOutputIterator copy_n(TInputIterator  i_begin,
+                         TSize1          n1,
+                         TOutputIterator o_begin,
+                         TSize2          n2)
+  {
+    while ((n1-- > 0) && (n2-- > 0))
+    {
+      *o_begin++ = *i_begin++;
+    }
+
+    return o_begin;
+  }
+
+  //***************************************************************************
+  /// copy_if
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/copy"></a>
+  //***************************************************************************
+  template <typename TIterator,
+            typename TOutputIterator,
+            typename TUnaryPredicate>
+  TOutputIterator copy_if(TIterator       begin,
+                          TIterator       end,
+                          TOutputIterator out,
+                          TUnaryPredicate predicate)
+  {
+    while (begin != end)
+    {
+      if (predicate(*begin))
+      {
+        *out++ = *begin;
+      }
+
+      ++begin;
+    }
+
+    return out;
+  }
+
+  //***************************************************************************
+  /// copy_if
+  /// A form of copy_if where it terminates when the first end iterator is reached.
+  /// There is currently no STL equivelent.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator,
+            typename TOutputIterator,
+            typename TUnaryPredicate>
+  TOutputIterator copy_if(TInputIterator  i_begin,
+                          TInputIterator  i_end,
+                          TOutputIterator o_begin,
+                          TOutputIterator o_end,
+                          TUnaryPredicate predicate)
+  {
+    while ((i_begin != i_end) && (o_begin != o_end))
+    {
+      if (predicate(*i_begin))
+      {
+        *o_begin++ = *i_begin;
+      }
+
+      ++i_begin;
+    }
+
+    return o_begin;
+  }
+
+  //***************************************************************************
+  /// copy_n_if
+  /// Combination of copy_n and copy_if.
+  ///\ingroup algorithm
+    //***************************************************************************
+  template <typename TInputIterator,
+            typename TSize,
+            typename TOutputIterator,
+            typename TUnaryPredicate>
+  TOutputIterator copy_n_if(TInputIterator  i_begin,
+                            TSize           n,
+                            TOutputIterator o_begin,
+                            TUnaryPredicate predicate)
+  {
+    while (n-- > 0)
+    {
+      if (predicate(*i_begin))
+      {
+        *o_begin++ = *i_begin;
+      }
+
+      ++i_begin;
+    }
+
+    return o_begin;
+  }
+
+  //***************************************************************************
+  /// binary_find
+  ///\ingroup algorithm
+  /// Does a binary search and returns an iterator to the value or end if not found.
+  //***************************************************************************
+  template <typename TIterator,
+            typename TValue>
+    TIterator binary_find(TIterator     begin,
+                          TIterator     end,
+                          const TValue& value)
+  {
+    TIterator it = std::lower_bound(begin, end, value);
+
+    if ((it == end) || (*it != value))
+    {
+      it = end;
+    }
+
+    return it;
+  }
+
+  //***************************************************************************
+  /// binary_find
+  ///\ingroup algorithm
+  /// Does a binary search and returns an iterator to the value or end if not found.
+  //***************************************************************************
+  template <typename TIterator,
+            typename TValue,
+            typename TBinaryPredicate,
+            typename TBinaryEquality>
+    TIterator binary_find(TIterator        begin,
+                          TIterator        end,
+                          const TValue&    value,
+                          TBinaryPredicate predicate,
+                          TBinaryEquality  equality)
+  {
+    TIterator it = std::lower_bound(begin, end, value, predicate);
+
+    if ((it == end) || !equality(*it, value))
+    {
+      it = end;
+    }
+
+    return it;
+  }
+
+  //***************************************************************************
+  /// find_if_not
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/find"></a>
+  //***************************************************************************
+  template <typename TIterator,
+            typename TUnaryPredicate>
+  TIterator find_if_not(TIterator       begin,
+                        TIterator       end,
+                        TUnaryPredicate predicate)
+  {
+    while (begin != end)
+    {
+      if (!predicate(*begin))
+      {
+        return begin;
+      }
+
+      ++begin;
+    }
+
+    return end;
+  }
+
+  //***************************************************************************
+  /// all_of
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/all_any_none_of"></a>
+  //***************************************************************************
+  template <typename TIterator,
+            typename TUnaryPredicate>
+  bool all_of(TIterator       begin,
+              TIterator       end,
+              TUnaryPredicate predicate)
+  {
+    return etl::find_if_not(begin, end, predicate) == end;
+  }
+
+  //***************************************************************************
+  /// any_of
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/all_any_none_of"></a>
+  //***************************************************************************
+  template <typename TIterator,
+            typename TUnaryPredicate>
+  bool any_of(TIterator       begin,
+              TIterator       end,
+              TUnaryPredicate predicate)
+  {
+    return std::find_if(begin, end, predicate) != end;
+  }
+
+  //***************************************************************************
+  /// none_of
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/all_any_none_of"></a>
+  //***************************************************************************
+  template <typename TIterator,
+            typename TUnaryPredicate>
+  bool none_of(TIterator       begin,
+               TIterator       end,
+               TUnaryPredicate predicate)
+  {
+    return std::find_if(begin, end, predicate) == end;
+  }
+
+  //***************************************************************************
+  /// is_permutation
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_permutation"></a>
+  //***************************************************************************
+  template <typename TIterator1,
+            typename TIterator2>
+  bool is_permutation(TIterator1 begin1,
+                      TIterator1 end1,
+                      TIterator2 begin2)
+  {
+    if (begin1 != end1)
+    {
+      TIterator2 end2 = begin2;
+
+      std::advance(end2, std::distance(begin1, end1));
+
+      for (TIterator1 i = begin1; i != end1; ++i)
+      {
+        if (i == std::find(begin1, i, *i))
+        {
+          int32_t n = std::count(begin2, end2, *i);
+
+          if (n == 0 || std::count(i, end1, *i) != n)
+          {
+            return false;
+          }
+        }
+      }
+    }
+
+    return true;
+  }
+
+  //***************************************************************************
+  /// is_permutation
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_permutation"></a>
+  //***************************************************************************
+  template <typename TIterator1,
+            typename TIterator2>
+  bool is_permutation(TIterator1 begin1,
+                      TIterator1 end1,
+                      TIterator2 begin2,
+                      TIterator2 end2)
+  {
+    if (begin1 != end1)
+    {
+      for (TIterator1 i = begin1; i != end1; ++i)
+      {
+        if (i == std::find(begin1, i, *i))
+        {
+          int32_t n = std::count(begin2, end2, *i);
+
+          if (n == 0 || std::count(i, end1, *i) != n)
+          {
+            return false;
+          }
+        }
+      }
+    }
+
+    return true;
+  }
+
+  //***************************************************************************
+  /// is_permutation
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_permutation"></a>
+  //***************************************************************************
+  template <typename TIterator1,
+            typename TIterator2,
+            typename TBinaryPredicate>
+  bool is_permutation(TIterator1       begin1,
+                      TIterator1       end1,
+                      TIterator2       begin2,
+                      TBinaryPredicate predicate)
+  {
+    if (begin1 != end1)
+    {
+      TIterator2 end2 = begin2;
+
+      std::advance(end2, std::distance(begin1, end1));
+
+      for (TIterator1 i = begin1; i != end1; ++i)
+      {
+        if (i == std::find_if(begin1, i, std::bind1st(predicate, *i)))
+        {
+          int32_t n = std::count(begin2, end2, *i);
+
+          if (n == 0 || std::count(i, end1, *i) != n)
+          {
+            return false;
+          }
+        }
+      }
+    }
+
+    return true;
+  }
+
+  //***************************************************************************
+  /// is_permutation
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_permutation"></a>
+  //***************************************************************************
+  template <typename TIterator1,
+            typename TIterator2,
+            typename TBinaryPredicate>
+  bool is_permutation(TIterator1       begin1,
+                      TIterator1       end1,
+                      TIterator2       begin2,
+                      TIterator2       end2,
+                      TBinaryPredicate predicate)
+  {
+    if (begin1 != end1)
+    {
+      for (TIterator1 i = begin1; i != end1; ++i)
+      {
+        if (i == std::find_if(begin1, i, std::bind1st(predicate, *i)))
+        {
+          int32_t n = std::count(begin2, end2, *i);
+
+          if (n == 0 || std::count(i, end1, *i) != n)
+          {
+            return false;
+          }
+        }
+      }
+    }
+
+    return true;
+  }
+
+  //***************************************************************************
+  /// is_partitioned
+  ///\ingroup algorithm
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_partitioned"></a>
+  //***************************************************************************
+  template <typename TIterator,
+            typename TUnaryPredicate>
+  bool is_partitioned(TIterator       begin,
+                      TIterator       end,
+                      TUnaryPredicate predicate)
+  {
+    while (begin != end)
+    {
+      if (!predicate(*begin++))
+      {
+        break;
+      }
+    }
+
+    while (begin != end)
+    {
+      if (predicate(*begin++))
+      {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  //***************************************************************************
+  /// partition_point
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/partition_point"></a>
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TIterator,
+            typename TUnaryPredicate>
+  TIterator partition_point(TIterator       begin,
+                            TIterator       end,
+                            TUnaryPredicate predicate)
+  {
+    while (begin != end)
+    {
+      if (!predicate(*begin))
+      {
+        return begin;
+      }
+
+      ++begin;
+    }
+
+    return begin;
+  }
+
+  //***************************************************************************
+  /// Copies the elements from the range (begin, end) to two different ranges
+  /// depending on the value returned by the predicate.<br>
+  ///<a href="http://en.cppreference.com/w/cpp/algorithm/partition_copy"></a>
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TSource,
+            typename TDestinationTrue,
+            typename TDestinationFalse,
+            typename TUnaryPredicate>
+  std::pair<TDestinationTrue, TDestinationFalse> partition_copy(TSource           begin,
+                                                                TSource           end,
+                                                                TDestinationTrue  destination_true,
+                                                                TDestinationFalse destination_false,
+                                                                TUnaryPredicate   predicate)
+  {
+    while (begin != end)
+    {
+      if (predicate(*begin))
+      {
+        *destination_true++ = *begin++;
+      }
+      else
+      {
+        *destination_false++ = *begin++;
+      }
+    }
+
+    return std::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false);
+  }
+
+  //***************************************************************************
+  /// Like std::for_each but applies a predicate before calling the function.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TIterator,
+            typename TUnaryFunction,
+            typename TUnaryPredicate>
+  TUnaryFunction for_each_if(TIterator       begin,
+                             const TIterator end,
+                             TUnaryFunction  function,
+                             TUnaryPredicate predicate)
+  {
+    while (begin != end)
+    {
+      if (predicate(*begin))
+      {
+        function(*begin);
+      }
+
+      ++begin;
+    }
+
+    return function;
+  }
+
+    //***************************************************************************
+  /// Like std::for_each but for 'n' iterations.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TIterator,
+            typename TSize,
+            typename TUnaryFunction>
+  TIterator for_each_n(TIterator       begin,
+                       TSize           n,
+                       TUnaryFunction  function)
+  {
+    while (n-- > 0)
+    {
+      function(*begin++);
+    }
+
+    return begin;
+  }
+
+  //***************************************************************************
+  /// Like std::for_each but applies a predicate before calling the function, for 'n' iterations
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TIterator,
+            typename TSize,
+            typename TUnaryFunction,
+            typename TUnaryPredicate>
+  TIterator for_each_n_if(TIterator       begin,
+                          TSize           n,
+                          TUnaryFunction  function,
+                          TUnaryPredicate predicate)
+  {
+    while (n-- > 0)
+    {
+      if (predicate(*begin))
+      {
+        function(*begin);
+      }
+
+      ++begin;
+    }
+
+    return begin;
+  }
+
+  //***************************************************************************
+  /// A form of std::transform where the transform returns when the first range
+  /// end is reached.
+  /// There is currently no STL equivalent.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator,
+            typename TOutputIterator,
+            typename TUnaryFunction>
+  void transform(TInputIterator  i_begin,
+                 TInputIterator  i_end,
+                 TOutputIterator o_begin,
+                 TOutputIterator o_end,
+                 TUnaryFunction  function)
+  {
+    while ((i_begin != i_end) && (o_begin != o_end))
+    {
+      *o_begin++ = function(*i_begin++);
+    }
+  }
+
+  //***************************************************************************
+  /// Transform 'n' items.
+  /// Random iterators.
+  /// There is currently no STL equivalent.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator,
+            typename TSize,
+            typename TOutputIterator,
+            typename TUnaryFunction>
+  typename etl::enable_if<etl::is_random_iterator<TInputIterator>::value, void>::type
+   transform_n(TInputIterator  i_begin,
+               TSize           n,
+               TOutputIterator o_begin,
+               TUnaryFunction  function)
+  {
+    std::transform(i_begin, i_begin + n, o_begin, function);
+  }
+
+  //***************************************************************************
+  /// Transform 'n' items from two ranges.
+  /// Random iterators.
+  /// There is currently no STL equivalent.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator1,
+            typename TInputIterator2,
+            typename TSize,
+            typename TOutputIterator,
+            typename TBinaryFunction>
+  typename etl::enable_if<etl::is_random_iterator<TInputIterator1>::value &&
+                          etl::is_random_iterator<TInputIterator2>::value, void>::type
+   transform_n(TInputIterator1 i_begin1,
+               TInputIterator2 i_begin2,
+               TSize           n,
+               TOutputIterator o_begin,
+               TBinaryFunction function)
+  {
+    std::transform(i_begin1, i_begin1 + n, i_begin2, o_begin, function);
+  }
+
+  //***************************************************************************
+  /// Transform 'n' items.
+  /// Non-random iterators.
+  /// There is currently no STL equivalent.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator,
+            typename TSize,
+            typename TOutputIterator,
+            typename TUnaryFunction>
+  typename etl::enable_if<!etl::is_random_iterator<TInputIterator>::value, void>::type
+   transform_n(TInputIterator  i_begin,
+               TSize           n,
+               TOutputIterator o_begin,
+               TUnaryFunction  function)
+  {
+    while (n > 0)
+    {
+      *o_begin++ = function(*i_begin++);
+      --n;
+    }
+  }
+
+  //***************************************************************************
+  /// Transform 'n' items from two ranges.
+  /// Non-random iterators.
+  /// There is currently no STL equivalent.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator1,
+            typename TInputIterator2,
+            typename TSize,
+            typename TOutputIterator,
+            typename TBinaryFunction>
+  typename etl::enable_if<!etl::is_random_iterator<TInputIterator1>::value ||
+                          !etl::is_random_iterator<TInputIterator2>::value, void>::type
+   transform_n(TInputIterator1 i_begin1,
+               TInputIterator2 i_begin2,
+               TSize           n,
+               TOutputIterator o_begin,
+               TBinaryFunction function)
+  {
+    while (n > 0)
+    {
+      *o_begin++ = function(*i_begin1++, *i_begin2++);
+      --n;
+    }
+  }
+
+  //***************************************************************************
+  /// Like std::transform but applies a predicate before calling the function.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator,
+            typename TOutputIterator,
+            typename TUnaryFunction,
+            typename TUnaryPredicate>
+  TOutputIterator transform_if(TInputIterator       i_begin,
+                               const TInputIterator i_end,
+                               TOutputIterator      o_begin,
+                               TUnaryFunction       function,
+                               TUnaryPredicate      predicate)
+  {
+    while (i_begin != i_end)
+    {
+      if (predicate(*i_begin))
+      {
+        *o_begin++ = function(*i_begin);
+      }
+
+      ++i_begin;
+    }
+
+    return o_begin;
+  }
+
+  //***************************************************************************
+  /// Like etl::transform_if but inputs from two ranges.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator1,
+            typename TInputIterator2,
+            typename TOutputIterator,
+            typename TBinaryFunction,
+            typename TBinaryPredicate>
+  TOutputIterator transform_if(TInputIterator1       i_begin1,
+                               const TInputIterator1 i_end1,
+                               TInputIterator2       i_begin2,
+                               TOutputIterator       o_begin,
+                               TBinaryFunction       function,
+                               TBinaryPredicate      predicate)
+  {
+    while (i_begin1 != i_end1)
+    {
+      if (predicate(*i_begin1, *i_begin2))
+      {
+        *o_begin++ = function(*i_begin1, *i_begin2);
+      }
+
+      ++i_begin1;
+      ++i_begin2;
+    }
+
+    return o_begin;
+  }
+
+  //***************************************************************************
+  /// Like std::transform_if, for 'n' items.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator,
+            typename TSize,
+            typename TOutputIterator,
+            typename TUnaryFunction,
+            typename TUnaryPredicate>
+  TOutputIterator transform_n_if(TInputIterator  i_begin,
+                                 TSize           n,
+                                 TOutputIterator o_begin,
+                                 TUnaryFunction  function,
+                                 TUnaryPredicate predicate)
+  {
+    while (n-- > 0)
+    {
+      if (predicate(*i_begin))
+      {
+        *o_begin++ = function(*i_begin);
+      }
+
+      ++i_begin;
+    }
+
+    return o_begin;
+  }
+
+  //***************************************************************************
+  /// Like etl::transform_if but inputs from two ranges for 'n' items.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TInputIterator1,
+            typename TInputIterator2,
+            typename TSize,
+            typename TOutputIterator,
+            typename TBinaryFunction,
+            typename TBinaryPredicate>
+  TOutputIterator transform_n_if(TInputIterator1  i_begin1,
+                                 TInputIterator2  i_begin2,
+                                 TSize            n,
+                                 TOutputIterator  o_begin,
+                                 TBinaryFunction  function,
+                                 TBinaryPredicate predicate)
+  {
+    while (n-- > 0)
+    {
+      if (predicate(*i_begin1, *i_begin2))
+      {
+        *o_begin++ = function(*i_begin1, *i_begin2);
+      }
+
+      ++i_begin1;
+      ++i_begin2;
+    }
+
+    return o_begin;
+  }
+
+  //***************************************************************************
+  /// Transforms the elements from the range (begin, end) to two different ranges
+  /// depending on the value returned by the predicate.<br>
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TSource, typename TDestinationTrue, typename TDestinationFalse,
+            typename TUnaryFunctionTrue, typename TUnaryFunctionFalse,
+            typename TUnaryPredicate>
+  std::pair<TDestinationTrue, TDestinationFalse> partition_transform(TSource             begin,
+                                                                     TSource             end,
+                                                                     TDestinationTrue    destination_true,
+                                                                     TDestinationFalse   destination_false,
+                                                                     TUnaryFunctionTrue  function_true,
+                                                                     TUnaryFunctionFalse function_false,
+                                                                     TUnaryPredicate     predicate)
+  {
+    while (begin != end)
+    {
+      if (predicate(*begin))
+      {
+        *destination_true++ = function_true(*begin++);
+      }
+      else
+      {
+        *destination_false++ = function_false(*begin++);
+      }
+    }
+
+    return std::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false);
+  }
+
+  //***************************************************************************
+  /// Transforms the elements from the ranges (begin1, end1) & (begin2)
+  /// to two different ranges depending on the value returned by the predicate.
+  ///\ingroup algorithm
+  //***************************************************************************
+  template <typename TSource1,
+            typename TSource2,
+            typename TDestinationTrue,
+            typename TDestinationFalse,
+            typename TBinaryFunctionTrue,
+            typename TBinaryFunctionFalse,
+            typename TBinaryPredicate>
+  std::pair<TDestinationTrue, TDestinationFalse> partition_transform(TSource1             begin1,
+                                                                     TSource1             end1,
+                                                                     TSource2             begin2,
+                                                                     TDestinationTrue     destination_true,
+                                                                     TDestinationFalse    destination_false,
+                                                                     TBinaryFunctionTrue  function_true,
+                                                                     TBinaryFunctionFalse function_false,
+                                                                     TBinaryPredicate     predicate)
+  {
+    while (begin1 != end1)
+    {
+      if (predicate(*begin1, *begin2))
+      {
+        *destination_true++ = function_true(*begin1++, *begin2++);
+      }
+      else
+      {
+        *destination_false++ = function_false(*begin1++, *begin2++);
+      }
+    }
+
+    return std::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false);
+  }
+}
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/alignment.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,198 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_ALIGNEMENT__
+#define __ETL_ALIGNEMENT__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "type_traits.h"
+#include "static_assert.h"
+
+///\defgroup alignment alignment
+/// Creates a variable of the specified type at the specified alignment.
+/// \ingroup utilities
+
+namespace etl
+{
+  namespace __private_alignment__
+  {
+    //***************************************************************************
+    // Matcher.
+    //***************************************************************************
+    template <const bool IS_MATCH, const size_t ALIGNMENT, typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void>
+    class type_with_alignment_matcher;
+
+    // Matching alignment.
+    template <const size_t ALIGNMENT, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
+    class type_with_alignment_matcher <true, ALIGNMENT, T1, T2, T3, T4, T5, T6, T7, T8>
+    {
+    public:
+
+      typedef T1 type;
+    };
+
+    // Non-matching alignment.
+    template <const size_t ALIGNMENT, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
+    class type_with_alignment_matcher <false, ALIGNMENT, T1, T2, T3, T4, T5, T6, T7, T8>
+    {
+    public:
+
+      typedef typename type_with_alignment_matcher<ALIGNMENT <= etl::alignment_of<T2>::value, ALIGNMENT, T2, T3, T4, T5, T6, T7, T8, void>::type type;
+    };
+
+    // Non-matching alignment, none left.
+    template <const size_t ALIGNMENT>
+    class type_with_alignment_matcher <false, ALIGNMENT, void, void, void, void, void, void, void, void>
+    {
+    public:
+
+      typedef char type;
+    };
+
+    //***************************************************************************
+    // Helper.
+    //***************************************************************************
+    template <const size_t ALIGNMENT, typename T1, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void>
+    class type_with_alignment_helper
+    {
+    public:
+
+      typedef typename type_with_alignment_matcher<ALIGNMENT <= etl::alignment_of<T1>::value, ALIGNMENT, T1, T2, T3, T4, T5, T6, T7, T8>::type type;
+    };
+  }
+
+  //***************************************************************************
+  /// Gets a type that has the same as the specified alignment.
+  ///\ingroup alignment
+  //***************************************************************************
+  template <const size_t ALIGNMENT>
+  class type_with_alignment
+  {
+  public:
+
+    typedef typename __private_alignment__::type_with_alignment_helper<ALIGNMENT, int_least8_t, int_least16_t, int32_t, int64_t, float, double, void*>::type type;
+  };
+
+  //***************************************************************************
+  /// Aligned storage
+  /// LENGTH should be determined in terms of sizeof()
+  ///\ingroup alignment
+  //***************************************************************************
+  template <const size_t LENGTH, const size_t ALIGNMENT>
+  struct aligned_storage
+  {
+    struct type
+    {
+      /// Convert to T reference.
+      template <typename T>
+      operator T& ()
+      {
+        STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
+        return reinterpret_cast<T&>(*data);
+      }
+
+      /// Convert to const T reference.
+      template <typename T>
+      operator const T& () const
+      {
+        STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
+        return reinterpret_cast<const T&>(*data);
+      }
+
+      /// Convert to T pointer.
+      template <typename T>
+      operator T* ()
+      {
+        STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
+        return reinterpret_cast<T*>(data);
+      }
+
+      /// Convert to const T pointer.
+      template <typename T>
+      operator const T* () const
+      {
+        STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
+        return reinterpret_cast<const T*>(data);
+      }
+
+      /// Get address as T reference.
+      template <typename T>
+      T& get_reference()
+      {
+        STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
+        return reinterpret_cast<T&>(*data);
+      }
+
+      /// Get address as const T reference.
+      template <typename T>
+      const T& get_reference() const
+      {
+        STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
+        return reinterpret_cast<const T&>(*data);
+      }
+
+      /// Get address as T pointer.
+      template <typename T>
+      T* get_address()
+      {
+        STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
+        return reinterpret_cast<T*>(data);
+      }
+
+      /// Get address as const T pointer.
+      template <typename T>
+      const T* get_address() const
+      {
+        STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
+        return reinterpret_cast<const T*>(data);
+      }
+
+      union
+      {
+        char data[LENGTH];
+        typename etl::type_with_alignment<ALIGNMENT>::type __etl_alignment_type__; // A POD type that has the same alignment as ALIGNMENT.
+      };
+    };
+  };
+
+  //***************************************************************************
+  /// Aligned storage as
+  ///\ingroup alignment
+  //***************************************************************************
+  template <const size_t LENGTH, typename T>
+  struct aligned_storage_as : public etl::aligned_storage<LENGTH, etl::alignment_of<T>::value>
+  {
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/array.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,674 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_ARRAY__
+#define __ETL_ARRAY__
+
+#include <iterator>
+#include <functional>
+#include <algorithm>
+#include <stddef.h>
+
+#include "platform.h"
+#include "exception.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "static_assert.h"
+#include "error_handler.h"
+#include "algorithm.h"
+
+///\defgroup array array
+/// A replacement for std::array if you haven't got C++0x11.
+///\ingroup containers
+
+namespace etl
+{
+  //***************************************************************************
+  ///\ingroup array
+  /// The base class for array exceptions.
+  //***************************************************************************
+  class array_exception : public exception
+  {
+  public:
+
+    array_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup array
+  /// The out of range exceptions.
+  //***************************************************************************
+  class array_out_of_range : public array_exception
+  {
+  public:
+
+    array_out_of_range(string_type file_name_, numeric_type line_number_)
+      : array_exception("array:range", file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup array
+  /// A replacement for std::array if you haven't got C++0x11.
+  //***************************************************************************
+  template <typename T, const size_t SIZE_>
+  class array
+  {
+  private:
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+
+  public:
+
+    enum
+    {
+      SIZE = SIZE_
+    };
+
+    typedef T                                     value_type;
+    typedef std::size_t                           size_type;
+    typedef std::ptrdiff_t                        difference_type;
+    typedef T&                                    reference;
+    typedef const T&                              const_reference;
+    typedef T*                                    pointer;
+    typedef const T*                              const_pointer;
+    typedef T*                                    iterator;
+    typedef const T*                              const_iterator;
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+    //*************************************************************************
+    // Element access
+    //*************************************************************************
+
+    //*************************************************************************
+    /// Returns a reference to the value at index 'i'.
+    ///\param i The index of the element to access.
+    //*************************************************************************
+    reference at(size_t i)
+    {
+      ETL_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range));
+
+      return _buffer[i];
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the value at index 'i'.
+    ///\param i The index of the element to access.
+    //*************************************************************************
+    const_reference at(size_t i) const
+    {
+      ETL_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range));
+
+      return _buffer[i];
+    }
+
+    //*************************************************************************
+    /// [] operator.
+    /// Returns a reference to the value at index 'i'.
+    ///\param i The index of the element to access.
+    //*************************************************************************
+    reference operator[](size_t i)
+    {
+      return _buffer[i];
+    }
+
+    //*************************************************************************
+    /// [] operator.
+    /// Returns a const reference to the value at index 'i'.
+    ///\param i The index of the element to access.
+    //*************************************************************************
+    const_reference operator[](size_t i) const
+    {
+      return _buffer[i];
+    }
+
+    //*************************************************************************
+    /// Returns a reference to the first element.
+    //*************************************************************************
+    reference front()
+    {
+      return _buffer[0];
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the first element.
+    //*************************************************************************
+    const_reference front() const
+    {
+      return _buffer[0];
+    }
+
+    //*************************************************************************
+    /// Returns a reference to the last element.
+    //*************************************************************************
+    reference back()
+    {
+      return _buffer[SIZE - 1];
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the last element.
+    //*************************************************************************
+    const_reference back() const
+    {
+      return _buffer[SIZE - 1];
+    }
+
+    //*************************************************************************
+    /// Returns a pointer to the first element of the internal buffer.
+    //*************************************************************************
+    pointer data()
+    {
+      return &_buffer[0];
+    }
+
+    //*************************************************************************
+    /// Returns a const pointer to the first element of the internal buffer.
+    //*************************************************************************
+    const_pointer data() const
+    {
+      return &_buffer[0];
+    }
+
+    //*************************************************************************
+    // Iterators
+    //*************************************************************************
+
+    //*************************************************************************
+    /// Returns an iterator to the beginning of the array.
+    //*************************************************************************
+    iterator begin()
+    {
+      return &_buffer[0];
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the beginning of the array.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return &_buffer[0];
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the beginning of the array.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return begin();
+    }
+
+    //*************************************************************************
+    /// Returns an iterator to the end of the array.
+    //*************************************************************************
+    iterator end()
+    {
+      return &_buffer[SIZE];
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the end of the array.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return &_buffer[SIZE];
+    }
+
+    //*************************************************************************
+    // Returns a const iterator to the end of the array.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return &_buffer[SIZE];
+    }
+
+    //*************************************************************************
+    // Returns an reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(end());
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(end());
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(end());
+    }
+
+    //*************************************************************************
+    /// Returns a reverse iterator to the end of the array.
+    //*************************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(begin());
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the end of the array.
+    //*************************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(begin());
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the end of the array.
+    //*************************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(begin());
+    }
+
+    //*************************************************************************
+    // Capacity
+    //*************************************************************************
+
+    //*************************************************************************
+    /// Returns <b>true</b> if the array size is zero.
+    //*************************************************************************
+    bool empty() const
+    {
+      return (SIZE == 0);
+    }
+
+    //*************************************************************************
+    /// Returns the size of the array.
+    //*************************************************************************
+    size_t size() const
+    {
+      return SIZE;
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the array.
+    //*************************************************************************
+    size_t max_size() const
+    {
+      return SIZE;
+    }
+
+    //*************************************************************************
+    // Operations
+    //*************************************************************************
+
+    //*************************************************************************
+    /// Fills the array with the specified value.
+    ///\param value The value to fill the array with.
+    //*************************************************************************
+    void fill(parameter_t value)
+    {
+      std::fill(begin(), end(), value);
+    }
+
+    //*************************************************************************
+    /// Swaps the contents of this array and another.
+    ///\param other A reference to the other array.
+    //*************************************************************************
+    void swap(array& other)
+    {
+      for (size_t i = 0; i < SIZE; ++i)
+      {
+        std::swap(_buffer[i], other._buffer[i]);
+      }
+    }
+
+    //*************************************************************************
+    /// Fills the array from the range.
+    /// If the range is larger than the array then the extra data is ignored.
+    /// If the range is smaller than the array then the unused array elements are left unmodified.
+    ///\param first The iterator to the first item in the ramge.
+    ///\param last  The iterator to one past the final item in the range.
+    //*************************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, const TIterator last)
+    {
+      etl::copy(first, last, begin(), end());
+    }
+
+    //*************************************************************************
+    /// Fills the array from the range.
+    /// If the range is larger than the array then the extra data is ignored.
+    /// If the range is smaller than the array then the unused array elements are initialised with the supplied value.
+    ///\param first The iterator to the first item in the ramge.
+    ///\param last  The iterator to one past the final item in the range.
+    //*************************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, const TIterator last, parameter_t value)
+    {
+      // Copy from the range.
+      iterator p = etl::copy(first, last, begin(), end());
+
+      // Default initialise any that are left.
+      std::fill(p, end(), value);
+    }
+
+    //*************************************************************************
+    /// Inserts a value into the array.
+    ///\param position The index of the position to insert at.
+    ///\param value    The value to insert.
+    //*************************************************************************
+    inline iterator insert_at(size_t position, parameter_t value)
+    {
+      return insert(begin() + position, value);
+    }
+
+    //*************************************************************************
+    /// Inserts a value into the array.
+    ///\param position The iterator to the position to insert at.
+    ///\param value    The value to insert.
+    //*************************************************************************
+    iterator insert(const_iterator position, parameter_t value)
+    {
+      iterator p = const_cast<iterator>(position);
+
+      std::copy_backward(p, end() - 1, end());
+      *p = value;
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Insert into the array from the range.
+    ///\param position The position to insert at.
+    ///\param first    The iterator to the first item in the range.
+    ///\param last     The iterator to one past the final item in the range.
+    //*************************************************************************
+    template <typename TIterator>
+    inline iterator insert_at(size_t position, TIterator first, const TIterator last)
+    {
+      return insert(begin() + position, first, last);
+    }
+
+    //*************************************************************************
+    /// Insert into the array from the range.
+    ///\param position The position to insert at.
+    ///\param first    The iterator to the first item in the range.
+    ///\param last     The iterator to one past the final item in the range.
+    //*************************************************************************
+    template <typename TIterator>
+    iterator insert(const_iterator position, TIterator first, const TIterator last)
+    {
+      iterator p = const_cast<iterator>(position);
+      iterator result(p);
+
+      size_t source_size       = std::distance(first, last);
+      size_t destination_space = std::distance(position, cend());
+
+      // Do we need to move anything?
+      if (source_size < destination_space)
+      {
+        size_t length = SIZE - (std::distance(begin(), p) + source_size);
+        std::copy_backward(p, p + length, end());
+      }
+
+      // Copy from the range.
+      etl::copy(first, last, p, end());
+
+      return result;
+    }
+
+    //*************************************************************************
+    /// Erases a value from the array.
+    /// After erase, the last value in the array will be unmodified.
+    ///\param position The index of the position to erase at.
+    //*************************************************************************
+    inline iterator erase_at(size_t position)
+    {
+      return erase(begin() + position);
+    }
+
+    //*************************************************************************
+    /// Erases a value from the array.
+    /// After erase, the last value in the array will be unmodified.
+    ///\param position The iterator to the position to erase at.
+    //*************************************************************************
+    iterator erase(const_iterator position)
+    {
+      iterator p = const_cast<iterator>(position);
+      std::copy(p + 1, end(), p);
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Erases a range of values from the array.
+    /// After erase, the last values in the array will be unmodified.
+    ///\param first The first item to erase.
+    ///\param last  The one past the last item to erase.
+    //*************************************************************************
+    iterator erase_range(size_t first, size_t last)
+    {
+      return erase(begin() + first, begin() + last);
+    }
+
+    //*************************************************************************
+    /// Erases a range of values from the array.
+    /// After erase, the last values in the array will be unmodified.
+    ///\param first The first item to erase.
+    ///\param last  The one past the last item to erase.
+    //*************************************************************************
+    iterator erase(const_iterator first, const_iterator last)
+    {
+      iterator p = const_cast<iterator>(first);
+      std::copy(last, cend(), p);
+      return p;
+    }
+
+    //*************************************************************************
+    /// Erases a value from the array.
+    ///\param position The index of the position to erase at.
+    ///\param value    The value to use to overwrite the last element in the array.
+    //*************************************************************************
+    inline iterator erase_at(size_t position, parameter_t value)
+    {
+      return erase(begin() + position, value);
+    }
+
+    //*************************************************************************
+    /// Erases a value from the array.
+    ///\param position The iterator to the position to erase at.
+    ///\param value    The value to use to overwrite the last element in the array.
+    //*************************************************************************
+    iterator erase(const_iterator position, parameter_t value)
+    {
+      iterator p = const_cast<iterator>(position);
+
+      std::copy(p + 1, end(), p);
+      back() = value;
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Erases a range of values from the array.
+    ///\param first The first item to erase.
+    ///\param last  The one past the last item to erase.
+    ///\param value The value to use to overwrite the last elements in the array.
+    //*************************************************************************
+    iterator erase_range(size_t first, size_t last, parameter_t value)
+    {
+      return erase(begin() + first, begin() + last, value);
+    }
+
+    //*************************************************************************
+    /// Erases a range of values from the array.
+    ///\param position The iterator to the position to erase at.
+    ///\param value    The value to use to overwrite the last elements in the array.
+    //*************************************************************************
+    iterator erase(const_iterator first, const_iterator last, parameter_t value)
+    {
+      iterator p = const_cast<iterator>(first);
+
+      p = std::copy(last, cend(), p);
+      std::fill(p, end(), value);
+
+      return const_cast<iterator>(first);
+    }
+
+    /// The array data.
+    T _buffer[SIZE];
+  };
+
+  //*************************************************************************
+  /// Overloaded swap for etl::array<T, SIZE>
+  ///\param lhs The first array.
+  ///\param rhs The second array.
+  //*************************************************************************
+  template <typename T, const size_t SIZE>
+  void swap(etl::array<T, SIZE> &lhs, etl::array<T, SIZE> &rhs)
+  {
+    lhs.swap(rhs);
+  }
+
+  //*************************************************************************
+  /// Equal operator.
+  ///\param lhs The first array.
+  ///\param rhs The second array.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  //*************************************************************************
+  template <typename T, std::size_t SIZE>
+  bool operator ==(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
+  {
+    return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());
+  }
+
+  //*************************************************************************
+  /// Not equal operator.
+  ///\param lhs The first array.
+  ///\param rhs The second array.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  //*************************************************************************
+  template <typename T, std::size_t SIZE>
+  bool operator !=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //*************************************************************************
+  /// Less than operator.
+  ///\param lhs The first array.
+  ///\param rhs The second array.
+  ///\return <b>true</b> if the first array is lexicographically less than the second, otherwise <b>false</b>
+  //*************************************************************************
+  template <typename T, std::size_t SIZE>
+  bool operator <(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
+  {
+    return std::lexicographical_compare(lhs.cbegin(),
+                                        lhs.cend(),
+                                        rhs.cbegin(),
+                                        rhs.cend());
+  }
+
+  //*************************************************************************
+  /// Less than or equal operator.
+  ///\param lhs The first array.
+  ///\param rhs The second array.
+  ///\return <b>true</b> if the first array is lexicographically less than or equal to the second, otherwise <b>false</b>
+  //*************************************************************************
+  template <typename T, std::size_t SIZE>
+  bool operator <=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
+  {
+    return !(lhs > rhs);
+  }
+
+  //*************************************************************************
+  /// Greater than operator.
+  ///\param lhs The first array.
+  ///\param rhs The second array.
+  ///\return <b>true</b> if the first array is lexicographically greater than the second, otherwise <b>false</b>
+  template <typename T, std::size_t SIZE>
+  //*************************************************************************
+  bool operator >(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
+  {
+    return (rhs < lhs);
+  }
+
+  //*************************************************************************
+  /// Greater than or equal operator.
+  ///\param lhs The first array.
+  ///\param rhs The second array.
+  ///\return <b>true</b> if the first array is lexicographically greater than or equal to the second, otherwise <b>false</b>
+  //*************************************************************************
+  template <typename T, std::size_t SIZE>
+  bool operator >=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs)
+  {
+    return !(lhs < rhs);
+  }
+
+  //*************************************************************************
+  /// Gets a reference to an element in the array.
+  ///\tparam I The index.
+  ///\tparam T The type.
+  ///\tparam MAXN The array size.
+  ///\param a The array.
+  ///\return A reference to the element
+  //*************************************************************************
+  template <std::size_t I, typename T, std::size_t MAXN>
+  inline T& get(array<T, MAXN>& a)
+  {
+    STATIC_ASSERT(I < MAXN, "Index out of bounds");
+    return a[I];
+  }
+
+  //*************************************************************************
+  /// Gets a const reference to an element in the array.
+  ///\tparam I The index.
+  ///\tparam T The type.
+  ///\tparam MAXN The array size.
+  ///\param a The array.
+  ///\return A const reference to the element
+  //*************************************************************************
+  template <std::size_t I, typename T, std::size_t MAXN>
+  inline const T& get(const array<T, MAXN>& a)
+  {
+    STATIC_ASSERT(I < MAXN, "Index out of bounds");
+    return a[I];
+  }
+}
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/array_view.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,874 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_ARRAY_VIEW__
+#define __ETL_ARRAY_VIEW__
+
+#include "platform.h"
+#include "memory.h"
+#include "iterator.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "nullptr.h"
+#include "hash.h"
+
+#include <algorithm>
+
+///\defgroup array array
+/// A wrapper for arrays
+///\ingroup containers
+
+#undef ETL_FILE
+#define ETL_FILE "41"
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for array_view exceptions.
+  //***************************************************************************
+  class array_view_exception : public exception
+  {
+  public:
+
+    array_view_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup stack
+  /// The exception thrown when the index is out of bounds.
+  //***************************************************************************
+  class array_view_bounds : public array_view_exception
+  {
+  public:
+
+    array_view_bounds(string_type file_name_, numeric_type line_number_)
+      : array_view_exception(ETL_ERROR_TEXT("array_view:bounds", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup stack
+  /// The exception thrown when the view is uninitialised.
+  //***************************************************************************
+  class array_view_uninitialised : public array_view_exception
+  {
+  public:
+
+    array_view_uninitialised(string_type file_name_, numeric_type line_number_)
+      : array_view_exception(ETL_ERROR_TEXT("array_view:uninitialised", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Array view.
+  //***************************************************************************
+  template <typename T>
+  class array_view
+  {
+  public:
+
+    typedef T                                     value_type;
+    typedef std::size_t                           size_type;
+    typedef T&                                    reference;
+    typedef const T&                              const_reference;
+    typedef T*                                    pointer;
+    typedef const T*                              const_pointer;
+    typedef T*                                    iterator;
+    typedef const T*                              const_iterator;
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    array_view()
+      : mbegin(std::nullptr),
+        mend(std::nullptr)
+    {
+    }
+
+    //*************************************************************************
+    /// Construct from std::array or etl::array or other type that supports
+    /// data() and size() member functions.
+    //*************************************************************************
+    template <typename TArray, 
+              typename TDummy = typename etl::enable_if<!etl::is_same<T, TArray>::value, void>::type>
+    explicit array_view(TArray& a)
+      : mbegin(a.data()),
+        mend(a.data() + a.size())
+    {
+    }
+
+    //*************************************************************************
+    /// Construct from iterators
+    //*************************************************************************
+    template <typename TIterator, 
+              typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type>
+    array_view(TIterator begin_, TIterator end_)
+      : mbegin(etl::addressof(*begin_)),
+        mend(etl::addressof(*begin_) + std::distance(begin_, end_))
+    {
+    }
+
+    //*************************************************************************
+    /// Construct from C array
+    //*************************************************************************
+    template <typename TIterator, 
+              typename TSize, 
+              typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type>
+    array_view(TIterator begin_, TSize size_)
+      : mbegin(etl::addressof(*begin_)),
+        mend(etl::addressof(*begin_) + size_)
+    {
+    }
+    
+    //*************************************************************************
+    /// Construct from C array
+    //*************************************************************************
+    template<const size_t ARRAY_SIZE>
+    explicit array_view(T(&begin_)[ARRAY_SIZE])
+      : mbegin(begin_),
+        mend(begin_ + ARRAY_SIZE)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor
+    //*************************************************************************
+    array_view(const array_view& other)
+      : mbegin(other.mbegin),
+        mend(other.mend)
+    {
+    }
+
+    //*************************************************************************
+    /// Returns a reference to the first element.
+    //*************************************************************************
+    reference front()
+    {
+      return *mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the first element.
+    //*************************************************************************
+    const_reference front() const
+    {
+      return *mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a reference to the last element.
+    //*************************************************************************
+    reference back()
+    {
+      return *(mend - 1);
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the last element.
+    //*************************************************************************
+    const_reference back() const
+    {
+      return *(mend - 1);
+    }
+
+    //*************************************************************************
+    /// Returns a pointer to the first element of the internal storage.
+    //*************************************************************************
+    pointer data()
+    {
+      return mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a const pointer to the first element of the internal storage.
+    //*************************************************************************
+    const_pointer data() const
+    {
+      return mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns an iterator to the beginning of the array.
+    //*************************************************************************
+    iterator begin()
+    {
+      return mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the beginning of the array.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the beginning of the array.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns an iterator to the end of the array.
+    //*************************************************************************
+    iterator end()
+    {
+      return mend;
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the end of the array.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return mend;
+    }
+
+    //*************************************************************************
+    // Returns a const iterator to the end of the array.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return mend;
+    }
+
+    //*************************************************************************
+    // Returns an reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(mend);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(mend);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(mend);
+    }
+
+    //*************************************************************************
+    /// Returns a reverse iterator to the end of the array.
+    //*************************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(mbegin);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the end of the array.
+    //*************************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(mbegin);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the end of the array.
+    //*************************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(mbegin);
+    }
+
+    //*************************************************************************
+    /// Returns <b>true</b> if the array size is zero.
+    //*************************************************************************
+    bool empty() const
+    {
+      return (mbegin == mend);
+    }
+
+    //*************************************************************************
+    /// Returns the size of the array.
+    //*************************************************************************
+    size_t size() const
+    {
+      return (mend - mbegin);
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the array.
+    //*************************************************************************
+    size_t max_size() const
+    {
+      return size();
+    }
+
+    //*************************************************************************
+    /// Assign from a view.
+    //*************************************************************************
+    array_view& operator=(const array_view& other)
+    {
+      mbegin = other.mbegin;
+      mend   = other.mend;
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Assign from iterators
+    //*************************************************************************
+    template <typename TIterator,
+              typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type>
+    void assign(TIterator begin_, TIterator end_)
+    {
+      mbegin = etl::addressof(*begin_);
+      mend = etl::addressof(*begin_) + std::distance(begin_, end_);
+    }
+
+    //*************************************************************************
+    /// Assign from iterator and size.
+    //*************************************************************************
+    template <typename TIterator,
+              typename TSize,
+              typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type>
+    void assign(TIterator begin_, TSize size_)
+    {
+      mbegin = etl::addressof(*begin_);
+      mend = etl::addressof(*begin_) + size_;
+    }
+
+    //*************************************************************************
+    /// Returns a reference to the indexed value.
+    //*************************************************************************
+    reference operator[](size_t i)
+    {
+      return mbegin[i];
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the indexed value.
+    //*************************************************************************
+    const_reference operator[](size_t i) const
+    {
+      return mbegin[i];
+    }
+
+    //*************************************************************************
+    /// Returns a reference to the indexed value.
+    //*************************************************************************
+    reference at(size_t i)
+    {
+      ETL_ASSERT((mbegin != std::nullptr && mend != std::nullptr), ETL_ERROR(array_view_uninitialised));
+      ETL_ASSERT(i < size(), ETL_ERROR(array_view_bounds));
+      return mbegin[i];
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the indexed value.
+    //*************************************************************************
+    const_reference at(size_t i) const
+    {
+      ETL_ASSERT((mbegin != std::nullptr && mend != std::nullptr), ETL_ERROR(array_view_uninitialised));
+      ETL_ASSERT(i < size(), ETL_ERROR(array_view_bounds));
+      return mbegin[i];
+    }
+
+    //*************************************************************************
+    /// Swaps with another array_view.
+    //*************************************************************************
+    void swap(array_view& other)
+    {
+      std::swap(mbegin, other.mbegin);
+      std::swap(mend, other.mend);
+    }
+
+    //*************************************************************************          
+    /// Shrinks the view by moving its start forward.
+    //*************************************************************************          
+    void remove_prefix(size_type n)
+    {
+      mbegin += n;
+    }
+
+    //*************************************************************************          
+    /// Shrinks the view by moving its end backward.
+    //*************************************************************************          
+    void remove_suffix(size_type n)
+    {
+      mend -= n;
+    }
+
+    //*************************************************************************
+    /// Equality for array views.
+    //*************************************************************************
+    friend bool operator == (const array_view<T>& lhs, const array_view<T>& rhs)
+    {
+      return (lhs.size() == rhs.size()) &&
+             std::equal(lhs.begin(), lhs.end(), rhs.begin());
+    }
+
+    //*************************************************************************
+    /// Inequality for array views.
+    //*************************************************************************
+    friend bool operator != (const array_view<T>& lhs, const array_view<T>& rhs)
+    {
+      return !(lhs == rhs);
+    }
+
+    //*************************************************************************
+    /// Less-than for array views.
+    //*************************************************************************
+    friend bool operator < (const array_view<T>& lhs, const array_view<T>& rhs)
+    {
+      return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+    }
+
+    //*************************************************************************
+    /// Greater-than for array views.
+    //*************************************************************************
+    friend bool operator > (const array_view<T>& lhs, const array_view<T>& rhs)
+    {
+      return rhs < lhs;
+    }
+
+    //*************************************************************************
+    /// Less-than-equal for array views.
+    //*************************************************************************
+    friend bool operator <= (const array_view<T>& lhs, const array_view<T>& rhs)
+    {
+      return !(lhs > rhs);
+    }
+
+    //*************************************************************************
+    /// Greater-than-equal for array views.
+    //*************************************************************************
+    friend bool operator >= (const array_view<T>& lhs, const array_view<T>& rhs)
+    {
+      return !(lhs < rhs);
+    }
+
+  private:
+
+    T* mbegin;
+    T* mend;
+  };
+
+  //***************************************************************************
+  /// Constant array view.
+  //***************************************************************************
+  template <typename T>
+  class const_array_view
+  {
+  public:
+
+    typedef T                                     value_type;
+    typedef std::size_t                           size_type;
+    typedef const T&                              const_reference;
+    typedef const T*                              const_pointer;
+    typedef const T*                              const_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    const_array_view()
+      : mbegin(std::nullptr),
+        mend(std::nullptr)
+    {
+    }
+
+    //*************************************************************************
+    /// Construct from std::array or etl::array or other type that supports
+    /// data() and size() member functions.
+    //*************************************************************************
+    template <typename TArray, 
+              typename TDummy = typename etl::enable_if<!etl::is_same<T, TArray>::value, void>::type>
+    explicit const_array_view(TArray& a)
+      : mbegin(a.data()),
+        mend(a.data() + a.size())
+    {
+    }
+
+    //*************************************************************************
+    /// Construct from iterators
+    //*************************************************************************
+    template <typename TIterator, 
+              typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type>
+    const_array_view(TIterator begin_, TIterator end_)
+      : mbegin(etl::addressof(*begin_)),
+        mend(etl::addressof(*begin_) + std::distance(begin_, end_))
+    {
+    }
+
+    //*************************************************************************
+    /// Construct from C array
+    //*************************************************************************
+    template <typename TIterator, 
+              typename TSize, typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type>
+    const_array_view(TIterator begin_, TSize size_)
+      : mbegin(etl::addressof(*begin_)),
+        mend(etl::addressof(*begin_) + size_)
+    {
+    }
+
+    //*************************************************************************
+    /// Construct from C array
+    //*************************************************************************
+    template<const size_t ARRAY_SIZE>
+    explicit const_array_view(const T(&begin_)[ARRAY_SIZE])
+      : mbegin(begin_),
+        mend(begin_ + ARRAY_SIZE)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor
+    //*************************************************************************
+    const_array_view(const array_view<T>& other)
+      : mbegin(other.begin()),
+        mend(other.end())
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor
+    //*************************************************************************
+    const_array_view(const const_array_view& other)
+      : mbegin(other.mbegin),
+      mend(other.mend)
+    {
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the first element.
+    //*************************************************************************
+    const_reference front() const
+    {
+      return *mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the last element.
+    //*************************************************************************
+    const_reference back() const
+    {
+      return *(mend - 1);
+    }
+
+    //*************************************************************************
+    /// Returns a const pointer to the first element of the internal storage.
+    //*************************************************************************
+    const_pointer data() const
+    {
+      return mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the beginning of the array.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the beginning of the array.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the end of the array.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return mend;
+    }
+
+    //*************************************************************************
+    // Returns a const iterator to the end of the array.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return mend;
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(mend);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(mend);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the end of the array.
+    //*************************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(mbegin);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the end of the array.
+    //*************************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(mbegin);
+    }
+
+    //*************************************************************************
+    // Capacity
+    //*************************************************************************
+
+    //*************************************************************************
+    /// Returns <b>true</b> if the array size is zero.
+    //*************************************************************************
+    bool empty() const
+    {
+      return (mbegin == mend);
+    }
+
+    //*************************************************************************
+    /// Returns the size of the array.
+    //*************************************************************************
+    size_t size() const
+    {
+      return (mend - mbegin);
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the array.
+    //*************************************************************************
+    size_t max_size() const
+    {
+      return size();
+    }
+
+    //*************************************************************************
+    /// Assign from a view.
+    //*************************************************************************
+    const_array_view<T>& operator=(const const_array_view<T>& other)
+    {
+      mbegin = other.mbegin;
+      mend   = other.mend;
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Assign from iterators
+    //*************************************************************************
+    template <typename TIterator,
+      typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type>
+    void assign(TIterator begin_, TIterator end_)
+    {
+      mbegin = etl::addressof(*begin_);
+      mend   = etl::addressof(*begin_) + std::distance(begin_, end_);
+    }
+
+    //*************************************************************************
+    /// Assign from iterator and size.
+    //*************************************************************************
+    template <typename TIterator,
+              typename TSize,
+              typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type>
+    void assign(TIterator begin_, TSize size_)
+    {
+      mbegin = etl::addressof(*begin_);
+      mend   = etl::addressof(*begin_) + size_;
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the indexed value.
+    //*************************************************************************
+    const_reference operator[](size_t i) const
+    {
+      return mbegin[i];
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the indexed value.
+    //*************************************************************************
+    const_reference at(size_t i) const
+    {
+      ETL_ASSERT((mbegin != std::nullptr && mend != std::nullptr), ETL_ERROR(array_view_uninitialised));
+      ETL_ASSERT(i < size(), ETL_ERROR(array_view_bounds));
+      return mbegin[i];
+    }
+
+    //*************************************************************************
+    /// Swaps with another array_view.
+    //*************************************************************************
+    void swap(const_array_view& other)
+    {
+      std::swap(mbegin, other.mbegin);
+      std::swap(mend, other.mend);
+    }
+
+    //*************************************************************************          
+    /// Shrinks the view by moving its start forward.
+    //*************************************************************************          
+    void remove_prefix(size_type n)
+    {
+      mbegin += n;
+    }
+
+    //*************************************************************************          
+    /// Shrinks the view by moving its end backward.
+    //*************************************************************************          
+    void remove_suffix(size_type n)
+    {
+      mend -= n;
+    }
+
+    //*************************************************************************
+    /// Equality for array views.
+    //*************************************************************************
+    friend bool operator == (const const_array_view<T>& lhs, const const_array_view<T>& rhs)
+    {
+      return (lhs.size() == rhs.size()) &&
+        std::equal(lhs.begin(), lhs.end(), rhs.begin());
+    }
+
+    //*************************************************************************
+    /// Inequality for array views.
+    //*************************************************************************
+    friend bool operator != (const const_array_view<T>& lhs, const const_array_view<T>& rhs)
+    {
+      return !(lhs == rhs);
+    }
+
+    //*************************************************************************
+    /// Less-than for array views.
+    //*************************************************************************
+    friend bool operator < (const const_array_view<T>& lhs, const const_array_view<T>& rhs)
+    {
+      return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+    }
+
+    //*************************************************************************
+    /// Greater-than for array views.
+    //*************************************************************************
+    friend bool operator > (const const_array_view<T>& lhs, const const_array_view<T>& rhs)
+    {
+      return rhs < lhs;
+    }
+
+    //*************************************************************************
+    /// Less-than-equal for array views.
+    //*************************************************************************
+    friend bool operator <= (const const_array_view<T>& lhs, const const_array_view<T>& rhs)
+    {
+      return !(lhs > rhs);
+    }
+
+    //*************************************************************************
+    /// Greater-than-equal for array views.
+    //*************************************************************************
+    friend bool operator >= (const const_array_view<T>& lhs, const const_array_view<T>& rhs)
+    {
+      return !(lhs < rhs);
+    }
+
+  private:
+
+    const T* mbegin;
+    const T* mend;
+  };
+
+  //*************************************************************************
+  /// Hash function.
+  //*************************************************************************
+#if ETL_8BIT_SUPPORT
+  template <typename T>
+  struct hash<etl::array_view<T> >
+  {
+    size_t operator()(const etl::array_view<T>& view) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&view[0]),
+                                                         reinterpret_cast<const uint8_t*>(&view[view.size()]));
+    }
+  };
+ 
+  template <typename T>
+  struct hash<etl::const_array_view<T> >
+  {
+    size_t operator()(const etl::const_array_view<T>& view) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&view[0]),
+                                                         reinterpret_cast<const uint8_t*>(&view[view.size()]));
+    }
+  };
+#endif
+}
+
+//*************************************************************************
+/// Swaps the values.
+//*************************************************************************
+template <typename T>
+void swap(etl::array_view<T>& lhs, etl::array_view<T>& rhs)
+{
+  lhs.swap(rhs);
+}
+
+//*************************************************************************
+/// Swaps the values.
+//*************************************************************************
+template <typename T>
+void swap(etl::const_array_view<T>& lhs, etl::const_array_view<T>& rhs)
+{
+  lhs.swap(rhs);
+}
+
+#undef ETL_FILE
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/array_wrapper.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,422 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_ARRAY_WRAPPER__
+#define __ETL_ARRAY_WRAPPER__
+
+#include "platform.h"
+#include "iterator.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "hash.h"
+#include "container.h"
+#include "parameter_type.h"
+
+#include <algorithm>
+
+///\defgroup array array
+/// A wrapper for arrays
+///\ingroup containers
+
+#undef ETL_FILE
+#define ETL_FILE "42"
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for array_wrapper exceptions.
+  //***************************************************************************
+  class array_wrapper_exception : public exception
+  {
+  public:
+
+    array_wrapper_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup stack
+  /// The exception thrown when the index is out of bounds.
+  //***************************************************************************
+  class array_wrapper_bounds : public array_wrapper_exception
+  {
+  public:
+
+    array_wrapper_bounds(string_type file_name_, numeric_type line_number_)
+      : array_wrapper_exception(ETL_ERROR_TEXT("array_wrapper:bounds", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Array wrapper.
+  //***************************************************************************
+  template <typename T, std::size_t SIZE_, T(&ARRAY_)[SIZE_]>
+  class array_wrapper
+  {
+  public:
+
+    typedef T                                     value_type;
+    typedef std::size_t                           size_type;
+    typedef T&                                    reference;
+    typedef const T&                              const_reference;
+    typedef T*                                    pointer;
+    typedef const T*                              const_pointer;
+    typedef T*                                    iterator;
+    typedef const T*                              const_iterator;
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+
+    // Indexes for positions in the array.
+    enum
+    {
+      SIZE     = SIZE_,
+      MAX_SIZE = SIZE_,
+      FRONT    = 0,
+      BACK     = SIZE - 1,
+      BEGIN    = 0,
+      END      = SIZE,
+      RBEGIN   = SIZE - 1,
+      REND     = -1
+    };
+
+    //*************************************************************************
+    /// Returns a reference to the first element.
+    //*************************************************************************
+    reference front()
+    {
+      return *&ARRAY_[FRONT];
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the first element.
+    //*************************************************************************
+    ETL_CONSTEXPR const_reference front() const
+    {
+      return *&ARRAY_[FRONT];
+    }
+
+    //*************************************************************************
+    /// Returns a reference to the last element.
+    //*************************************************************************
+    reference back()
+    {
+      return *&ARRAY_[BACK];
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the last element.
+    //*************************************************************************
+    ETL_CONSTEXPR const_reference back() const
+    {
+      return *&ARRAY_[BACK];
+    }
+
+    //*************************************************************************
+    /// Returns a pointer to the first element of the internal storage.
+    //*************************************************************************
+    pointer data()
+    {
+      return &ARRAY_[BEGIN];
+    }
+
+    //*************************************************************************
+    /// Returns a const pointer to the first element of the internal storage.
+    //*************************************************************************
+    ETL_CONSTEXPR const_pointer data() const
+    {
+      return &ARRAY_[BEGIN];
+    }
+
+    //*************************************************************************
+    /// Returns an iterator to the beginning of the array.
+    //*************************************************************************
+    iterator begin()
+    {
+      return &ARRAY_[BEGIN];
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the beginning of the array.
+    //*************************************************************************
+    ETL_CONSTEXPR const_iterator begin() const
+    {
+      return &ARRAY_[BEGIN];
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the beginning of the array.
+    //*************************************************************************
+    ETL_CONSTEXPR const_iterator cbegin() const
+    {
+      return &ARRAY_[BEGIN];
+    }
+
+    //*************************************************************************
+    /// Returns an iterator to the end of the array.
+    //*************************************************************************
+    iterator end()
+    {
+      return &ARRAY_[END];
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the end of the array.
+    //*************************************************************************
+    ETL_CONSTEXPR const_iterator end() const
+    {
+      return &ARRAY_[END];
+    }
+
+    //*************************************************************************
+    // Returns a const iterator to the end of the array.
+    //*************************************************************************
+    ETL_CONSTEXPR const_iterator cend() const
+    {
+      return &ARRAY_[END];
+    }
+
+    //*************************************************************************
+    // Returns an reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(&ARRAY_[END]);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    ETL_CONSTEXPR const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(&ARRAY_[END]);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    ETL_CONSTEXPR const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(&ARRAY_[END]);
+    }
+
+    //*************************************************************************
+    /// Returns a reverse iterator to the end of the array.
+    //*************************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(&ARRAY_[BEGIN]);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the end of the array.
+    //*************************************************************************
+    ETL_CONSTEXPR const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(&ARRAY_[BEGIN]);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the end of the array.
+    //*************************************************************************
+    ETL_CONSTEXPR const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(&ARRAY_[BEGIN]);
+    }
+
+    //*************************************************************************
+    /// Returns the size of the array.
+    //*************************************************************************
+    ETL_CONSTEXPR size_t size() const
+    {
+      return SIZE;
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the array.
+    //*************************************************************************
+    ETL_CONSTEXPR size_t max_size() const
+    {
+      return MAX_SIZE;
+    }
+
+    //*************************************************************************
+    /// Returns a reference to the indexed value.
+    //*************************************************************************
+    reference operator[](size_t i)
+    {
+      return ARRAY_[i];
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the indexed value.
+    //*************************************************************************
+    ETL_CONSTEXPR const_reference operator[](size_t i) const
+    {
+      return ARRAY_[i];
+    }
+
+    //*************************************************************************
+    /// Returns a reference to the indexed value.
+    //*************************************************************************
+    reference at(size_t i)
+    {
+      ETL_ASSERT(i < SIZE, ETL_ERROR(etl::array_wrapper_bounds));
+      return ARRAY_[i];
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the indexed value.
+    //*************************************************************************
+    const_reference at(size_t i) const
+    {
+      ETL_ASSERT(i < SIZE, ETL_ERROR(etl::array_wrapper_bounds));
+      return ARRAY_[i];
+    }
+
+    //*************************************************************************
+    /// Fills the array.
+    //*************************************************************************
+    void fill(parameter_t value)
+    {
+      std::fill(begin(), end(), value);
+    }
+
+    //*************************************************************************
+    /// Swaps the contents of arrays.
+    //*************************************************************************
+    template <typename U, U(&ARRAYOTHER)[SIZE_]>
+    typename etl::enable_if<etl::is_same<T, U>::value, void>::type
+     swap(etl::array_wrapper<U, SIZE_, ARRAYOTHER>& other)
+    {
+      for (size_t i = 0; i < SIZE; ++i)
+      {
+        std::swap(ARRAY_[i], other.begin()[i]);
+      }
+    }
+  };
+
+  //*************************************************************************
+  /// Equality for array wrappers.
+  //*************************************************************************
+  template <typename TL, typename TR, std::size_t SIZEL, std::size_t SIZER, TL(&ARRAYL)[SIZEL], TR(&ARRAYR)[SIZER]>
+  bool operator == (const etl::array_wrapper<TL, SIZEL, ARRAYL>& lhs,
+                    const etl::array_wrapper<TR, SIZER, ARRAYR>& rhs)
+  {
+    return (SIZEL == SIZER) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //*************************************************************************
+  /// Inequality for array wrapper.
+  //*************************************************************************
+  template <typename TL, typename TR, std::size_t SIZEL, std::size_t SIZER, TL(&ARRAYL)[SIZEL], TR(&ARRAYR)[SIZER]>
+  bool operator != (const etl::array_wrapper<TL, SIZEL, ARRAYL>& lhs,
+                    const etl::array_wrapper<TR, SIZER, ARRAYR>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //*************************************************************************
+  /// Less-than for array wrapper.
+  //*************************************************************************
+  template <typename TL, typename TR, std::size_t SIZEL, std::size_t SIZER, TL(&ARRAYL)[SIZEL], TR(&ARRAYR)[SIZER]>
+  bool operator < (const etl::array_wrapper<TL, SIZEL, ARRAYL>& lhs,
+                   const etl::array_wrapper<TR, SIZER, ARRAYR>& rhs)
+  {
+    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+  }
+
+  //*************************************************************************
+  /// Greater-than for array wrapper.
+  //*************************************************************************
+  template <typename TL, typename TR, std::size_t SIZEL, std::size_t SIZER, TL(&ARRAYL)[SIZEL], TR(&ARRAYR)[SIZER]>
+  bool operator > (const etl::array_wrapper<TL, SIZEL, ARRAYL>& lhs,
+                   const etl::array_wrapper<TR, SIZER, ARRAYR>& rhs)
+  {
+    return rhs < lhs;
+  }
+
+  //*************************************************************************
+  /// Less-than-equal for array wrapper.
+  //*************************************************************************
+  template <typename TL, typename TR, std::size_t SIZEL, std::size_t SIZER, TL(&ARRAYL)[SIZEL], TR(&ARRAYR)[SIZER]>
+  bool operator <= (const etl::array_wrapper<TL, SIZEL, ARRAYL>& lhs,
+                    const etl::array_wrapper<TR, SIZER, ARRAYR>& rhs)
+  {
+    return !(lhs > rhs);
+  }
+
+  //*************************************************************************
+  /// Greater-than-equal for array wrapper.
+  //*************************************************************************
+  template <typename TL, typename TR, std::size_t SIZEL, std::size_t SIZER, TL(&ARRAYL)[SIZEL], TR(&ARRAYR)[SIZER]>
+  bool operator >= (const etl::array_wrapper<TL, SIZEL, ARRAYL>& lhs,
+                    const etl::array_wrapper<TR, SIZER, ARRAYR>& rhs)
+  {
+    return !(lhs < rhs);
+  }
+
+  //*************************************************************************
+  /// Hash function.
+  //*************************************************************************
+#if ETL_8BIT_SUPPORT
+  template <typename T, std::size_t SIZE, T(&ARRAY)[SIZE]>
+  struct hash<etl::array_wrapper<T, SIZE, ARRAY> >
+  {
+    size_t operator()(const etl::array_wrapper<T, SIZE, ARRAY>& aw) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&aw[0]),
+                                                         reinterpret_cast<const uint8_t*>(&aw[aw.size()]));
+    }
+  };
+#endif
+}
+
+//*************************************************************************
+/// Swap.
+//*************************************************************************
+template <typename T, std::size_t SIZE, T(&ARRAYL)[SIZE], T(&ARRAYR)[SIZE]>
+void swap(etl::array_wrapper<T, SIZE, ARRAYL>& lhs,
+          etl::array_wrapper<T, SIZE, ARRAYR>& rhs)
+{
+  lhs.swap(rhs);
+}
+
+#define ETL_ARRAY_WRAPPER(arraytype, arrayobject)  etl::array_wrapper<arraytype, ETL_ARRAY_SIZE(arrayobject), arrayobject>
+
+#undef ETL_FILE
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atomic.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,52 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_ATOMIC__
+#define __ETL_ATOMIC__
+
+#include "platform.h"
+
+#if ETL_ATOMIC_SUPPORTED == 1
+  #include <atomic>
+
+  namespace etl
+  {
+    typedef std::atomic<uint32_t> atomic_uint32_t;
+  }
+#elif defined(ETL_COMPILER_ARM)
+  #include "atomic/atomic_arm.h"
+#elif defined(ETL_COMPILER_GCC)
+  #include "atomic/atomic_gcc.h"
+#elif defined(ETL_COMPILER_MSVC)
+  #include "atomic/atomic_windows.h"
+#else
+  #warning NO ATOMIC SUPPORT DEFINED!
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atomic/atomic_arm.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,35 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_ATOMIC_ARM__
+#define __ETL_ATOMIC_ARM__
+
+#include "atomic_gcc.h"
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atomic/atomic_gcc.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,634 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_ATOMIC_GCC__
+#define __ETL_ATOMIC_GCC__
+
+#include "../platform.h"
+#include "../type_traits.h"
+#include "../char_traits.h"
+#include "../static_assert.h"
+#include "../nullptr.h"
+
+#include <stdint.h>
+
+namespace etl
+{
+  //***************************************************************************
+  // Atomic type for pre C++11 GCC compilers that support the builtin 'fetch' functions.
+  // Only integral and pointer types are supported.
+  //***************************************************************************
+  template <typename T>
+  class atomic
+  {
+  public:
+
+    STATIC_ASSERT(etl::is_integral<T>::value, "Only integral types are supported");
+
+    atomic()
+      : value(0)
+    {
+    }
+
+    atomic(T v)
+      : value(v)
+    {
+    }
+
+    // Assignment
+    T operator =(T v)
+    {
+      __sync_lock_test_and_set(&value, v);
+
+      return v;
+    }
+
+    T operator =(T v) volatile
+    {
+      __sync_lock_test_and_set(&value, v);
+
+      return v;
+    }
+
+    // Pre-increment
+    T operator ++()
+    {
+      return fetch_add(1) + 1;
+    }
+
+    T operator ++() volatile
+    {
+      return fetch_add(1) + 1;
+    }
+
+    // Post-increment
+    T operator ++(int)
+    {
+      return fetch_add(1);
+    }
+
+    T operator ++(int) volatile
+    {
+      return fetch_add(1);
+    }
+
+    // Pre-decrement
+    T operator --()
+    {
+      return fetch_sub(1) + 1;
+    }
+
+    T operator --() volatile
+    {
+      return fetch_sub(1) + 1;
+    }
+
+    // Post-decrement
+    T operator --(int)
+    {
+      return fetch_sub(1);
+    }
+
+    T operator --(int) volatile
+    {
+      return fetch_sub(1);
+    }
+
+    // Add
+    T operator +=(T v)
+    {
+      return fetch_add(v) + v;
+    }
+
+    T operator +=(T v) volatile
+    {
+      return fetch_add(v) + v;
+    }
+
+    // Subtract
+    T operator -=(T v)
+    {
+      return fetch_sub(v) - v;
+    }
+
+    T operator -=(T v) volatile
+    {
+      return fetch_sub(v) - v;
+    }
+
+    // And
+    T operator &=(T v)
+    {
+      return fetch_and(v) & v;
+    }
+
+    T operator &=(T v) volatile
+    {
+      return fetch_and(v) & v;
+    }
+
+    // Or
+    T operator |=(T v)
+    {
+      return fetch_or(v) | v;
+    }
+
+    T operator |=(T v) volatile
+    {
+      return fetch_or(v) | v;
+    }
+
+    // Exclusive or
+    T operator ^=(T v)
+    {
+      return fetch_xor(v) ^ v;
+    }
+
+    T operator ^=(T v) volatile
+    {
+      return fetch_xor(v) ^ v;
+    }
+
+    // Conversion operator
+    operator T () const
+    {
+      return __sync_fetch_and_add(const_cast<T*>(&value), 0);
+    }
+
+    operator T() volatile const
+    {
+      return __sync_fetch_and_add(const_cast<T*>(&value), 0);
+    }
+
+    // Is lock free?
+    bool is_lock_free() const
+    {
+      return true;
+    }
+
+    bool is_lock_free() const volatile
+    {
+      return true;
+    }
+
+    // Store
+    void store(T v)
+    {
+      __sync_lock_test_and_set(&value, v);
+    }
+
+    void store(T v) volatile
+    {
+      __sync_lock_test_and_set(&value, v);
+    }
+
+    // Load
+    T load()
+    {
+      return __sync_fetch_and_add(&value, 0);
+    }
+
+    T load() volatile
+    {
+      return __sync_fetch_and_add(&value, 0);
+    }
+
+    // Fetch add
+    T fetch_add(T v)
+    {
+      return __sync_fetch_and_add(&value, v);
+    }
+
+    T fetch_add(T v) volatile
+    {
+      return __sync_fetch_and_add(&value, v);
+    }
+
+    // Fetch subtract
+    T fetch_sub(T v)
+    {
+      return __sync_fetch_and_sub(&value, v);
+    }
+
+    T fetch_sub(T v) volatile
+    {
+      return __sync_fetch_and_sub(&value, v);
+    }
+
+    // Fetch or
+    T fetch_or(T v)
+    {
+      return __sync_fetch_and_or(&value, v);
+    }
+
+    T fetch_or(T v) volatile
+    {
+      return __sync_fetch_and_or(&value, v);
+    }
+
+    // Fetch and
+    T fetch_and(T v)
+    {
+      return __sync_fetch_and_and(&value, v);
+    }
+
+    T fetch_and(T v) volatile
+    {
+      return __sync_fetch_and_and(&value, v);
+    }
+
+    // Fetch exclusive or
+    T fetch_xor(T v)
+    {
+      return __sync_fetch_and_xor(&value, v);
+    }
+
+    T fetch_xor(T v) volatile
+    {
+      return __sync_fetch_and_xor(&value, v);
+    }
+
+    // Exchange
+    T exchange(T v)
+    {
+      return __sync_lock_test_and_set(&value, v);
+    }
+
+    T exchange(T v) volatile
+    {
+      return __sync_lock_test_and_set(&value, v);
+    }
+
+    // Compare exchange weak
+    bool compare_exchange_weak(T& expected, T desired)
+    {
+      T old = __sync_val_compare_and_swap(&value, expected, desired);
+
+      if (old == expected)
+      {
+        return true;
+      }
+      else
+      {
+        expected = old;
+        return false;
+      }
+    }
+
+    bool compare_exchange_weak(T& expected, T desired) volatile
+    {
+      T old = __sync_val_compare_and_swap(&value, expected, desired);
+
+      if (old == expected)
+      {
+        return true;
+      }
+      else
+      {
+        expected = old;
+        return false;
+      }
+    }
+
+    // Compare exchange strong
+    bool compare_exchange_strong(T& expected, T desired)
+    {
+      T old = expected;
+
+      while (!compare_exchange_weak(old, desired))
+      {
+        if (memcmp(&old, &expected, sizeof(T)))
+        {
+          expected = old;
+          return false;
+        }
+      }
+
+      return true;
+    }
+
+    bool compare_exchange_strong(T& expected, T desired) volatile
+    {
+      T old = expected;
+
+      while (!compare_exchange_weak(old, desired))
+      {
+        if (memcmp(&old, &expected, sizeof(T)))
+        {
+          expected = old;
+          return false;
+        }
+      }
+
+      return true;
+    }
+
+  private:
+
+    atomic& operator =(const atomic&);
+    atomic& operator =(const atomic&) volatile;
+
+    T value;
+  };
+
+  //***************************************************************************
+  // Specialisation for pointers.
+  //***************************************************************************
+  template <typename T>
+  class atomic<T*>
+  {
+  public:
+
+    atomic()
+      : value(std::nullptr)
+    {
+    }
+
+    atomic(T v)
+      : value(v)
+    {
+    }
+
+    // Assignment
+    T operator =(T* v)
+    {
+      __sync_lock_test_and_set(&value, v);
+
+      return v;
+    }
+
+    T operator =(T* v) volatile
+    {
+      __sync_lock_test_and_set(&value, v);
+
+      return v;
+    }
+
+    // Pre-increment
+    T operator ++()
+    {
+      return fetch_add(1) + 1;
+    }
+
+    T operator ++() volatile
+    {
+      return fetch_add(1) + 1;
+    }
+
+    // Post-increment
+    T operator ++(int)
+    {
+      return fetch_add(1);
+    }
+
+    T operator ++(int) volatile
+    {
+      return fetch_add(1);
+    }
+
+    // Pre-decrement
+    T operator --()
+    {
+      return fetch_sub(1) + 1;
+    }
+
+    T operator --() volatile
+    {
+      return fetch_sub(1) + 1;
+    }
+
+    // Post-decrement
+    T operator --(int)
+    {
+      return fetch_sub(1);
+    }
+
+    T operator --(int) volatile
+    {
+      return fetch_sub(1);
+    }
+
+    // Add
+    T* operator +=(std::ptrdiff_t v)
+    {
+      return fetch_add(v) + v;
+    }
+
+    T* operator +=(std::ptrdiff_t v) volatile
+    {
+      return fetch_add(v) + v;
+    }
+
+    // Subtract
+    T* operator -=(std::ptrdiff_t v)
+    {
+      return fetch_sub(v) - v;
+    }
+
+    T* operator -=(std::ptrdiff_t v) volatile
+    {
+      return fetch_sub(v) - v;
+    }
+
+    // Conversion operator
+    operator T () const
+    {
+      return __sync_fetch_and_add(const_cast<T**>(&value), 0);
+    }
+
+    operator T() volatile const
+    {
+      return __sync_fetch_and_add(const_cast<T**>(&value), 0);
+    }
+
+    // Is lock free?
+    bool is_lock_free() const
+    {
+      return true;
+    }
+
+    bool is_lock_free() const volatile
+    {
+      return true;
+    }
+
+    // Store
+    void store(T v)
+    {
+      __sync_lock_test_and_set(&value, v);
+    }
+
+    void store(T v) volatile
+    {
+      __sync_lock_test_and_set(&value, v);
+    }
+
+    // Load
+    T load()
+    {
+      return __sync_fetch_and_add(&value, 0);
+    }
+
+    T load() volatile
+    {
+      return __sync_fetch_and_add(&value, 0);
+    }
+
+    // Fetch add
+    T* fetch_add(std::ptrdiff_t v)
+    {
+      return __sync_fetch_and_add(&value, v);
+    }
+
+    T* fetch_add(std::ptrdiff_t v) volatile
+    {
+      return __sync_fetch_and_add(&value, v);
+    }
+
+    // Fetch subtract
+    T* fetch_sub(std::ptrdiff_t v)
+    {
+      return __sync_fetch_and_sub(&value, v);
+    }
+
+    T* fetch_sub(std::ptrdiff_t v) volatile
+    {
+      return __sync_fetch_and_sub(&value, v);
+    }
+
+    // Exchange
+    T exchange(T v)
+    {
+      return __sync_lock_test_and_set(&value, v);
+    }
+
+    T exchange(T v) volatile
+    {
+      return __sync_lock_test_and_set(&value, v);
+    }
+
+    // Compare exchange weak
+    bool compare_exchange_weak(T& expected, T desired)
+    {
+      return __sync_bool_compare_and_swap(&value, expected, desired);
+    }
+
+    bool compare_exchange_weak(T& expected, T desired) volatile
+    {
+      return __sync_bool_compare_and_swap(&value, expected, desired);
+    }
+
+    // Compare exchange strong
+    bool compare_exchange_strong(T& expected, T desired)
+    {
+      T old = expected;
+
+      while (!compare_exchange_weak(old, desired))
+      {
+        if (memcmp(&old, &expected, sizeof(T)))
+        {
+          expected = old;
+          return false;
+        }
+      }
+
+      return true;
+    }
+
+    bool compare_exchange_strong(T& expected, T desired) volatile
+    {
+      T old = expected;
+
+      while (!compare_exchange_weak(old, desired))
+      {
+        if (memcmp(&old, &expected, sizeof(T)))
+        {
+          expected = old;
+          return false;
+        }
+      }
+
+      return true;
+    }
+
+  private:
+
+    atomic& operator =(const atomic&);
+    atomic& operator =(const atomic&) volatile;
+
+    T* value;
+  };
+
+  typedef etl::atomic<char>                atomic_char;
+  typedef etl::atomic<signed char>         atomic_schar;
+  typedef etl::atomic<unsigned char>       atomic_uchar;
+  typedef etl::atomic<short>               atomic_short;
+  typedef etl::atomic<unsigned short>      atomic_ushort;
+  typedef etl::atomic<int>                 atomic_int;
+  typedef etl::atomic<unsigned int>        atomic_uint;
+  typedef etl::atomic<long>                atomic_long;
+  typedef etl::atomic<unsigned long>       atomic_ulong;
+  typedef etl::atomic<long long>           atomic_llong;
+  typedef etl::atomic<unsigned long long>  atomic_ullong;
+  typedef etl::atomic<wchar_t>             atomic_wchar_t;
+  typedef etl::atomic<char16_t>            atomic_char16_t;
+  typedef etl::atomic<char32_t>            atomic_char32_t;
+  typedef etl::atomic<uint8_t>             atomic_uint8_t;
+  typedef etl::atomic<int8_t>              atomic_int8_t;
+  typedef etl::atomic<uint16_t>            atomic_uint16_t;
+  typedef etl::atomic<int16_t>             atomic_int16_t;
+  typedef etl::atomic<uint32_t>            atomic_uint32_t;
+  typedef etl::atomic<int32_t>             atomic_int32_t;
+  typedef etl::atomic<uint64_t>            atomic_uint64_t;
+  typedef etl::atomic<int64_t>             atomic_int64_t;
+  typedef etl::atomic<int_least8_t>        atomic_int_least8_t;
+  typedef etl::atomic<uint_least8_t>       atomic_uint_least8_t;
+  typedef etl::atomic<int_least16_t>       atomic_int_least16_t;
+  typedef etl::atomic<uint_least16_t>      atomic_uint_least16_t;
+  typedef etl::atomic<int_least32_t>       atomic_int_least32_t;
+  typedef etl::atomic<uint_least32_t>      atomic_uint_least32_t;
+  typedef etl::atomic<int_least64_t>       atomic_int_least64_t;
+  typedef etl::atomic<uint_least64_t>      atomic_uint_least64_t;
+  typedef etl::atomic<int_fast8_t>         atomic_int_fast8_t;
+  typedef etl::atomic<uint_fast8_t>        atomic_uint_fast8_t;
+  typedef etl::atomic<int_fast16_t>        atomic_int_fast16_t;
+  typedef etl::atomic<uint_fast16_t>       atomic_uint_fast16_t;
+  typedef etl::atomic<int_fast32_t>        atomic_int_fast32_t;
+  typedef etl::atomic<uint_fast32_t>       atomic_uint_fast32_t;
+  typedef etl::atomic<int_fast64_t>        atomic_int_fast64_t;
+  typedef etl::atomic<uint_fast64_t>       atomic_uint_fast64_t;
+  typedef etl::atomic<intptr_t>            atomic_intptr_t;
+  typedef etl::atomic<uintptr_t>           atomic_uintptr_t;
+  typedef etl::atomic<size_t>              atomic_size_t;
+  typedef etl::atomic<ptrdiff_t>           atomic_ptrdiff_t;
+  typedef etl::atomic<intmax_t>            atomic_intmax_t;
+  typedef etl::atomic<uintmax_t>           atomic_uintmax_t;
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atomic/atomic_windows.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,105 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_ATOMIC_WINDOWS__
+#define __ETL_ATOMIC_WINDOWS__
+
+#include "../platform.h"
+
+#include <stdint.h>
+#include <Windows.h>
+
+namespace etl
+{
+  class atomic_uint32_t
+  {
+  public:
+
+    atomic_uint32_t()
+    {
+      InterlockedExchange(&value, 0);
+    }
+
+    atomic_uint32_t(uint32_t v)
+    {
+      InterlockedExchange(&value, v);
+    }
+
+    atomic_uint32_t& operator =(uint32_t v)
+    {
+      InterlockedExchange(&value, v);
+
+      return *this;
+    }
+
+    atomic_uint32_t& operator ++()
+    {
+      InterlockedIncrement(&value);
+
+      return *this;
+    }
+
+    volatile atomic_uint32_t& operator ++() volatile
+    {
+      InterlockedIncrement(&value);
+
+      return *this;
+    }
+
+    atomic_uint32_t& operator --()
+    {
+      InterlockedDecrement(&value);
+
+      return *this;
+    }
+
+    volatile atomic_uint32_t& operator --() volatile
+    {
+      InterlockedDecrement(&value);
+
+      return *this;
+    }
+
+    operator uint32_t () const
+    {
+      return InterlockedAdd((volatile long*)&value, 0);
+    }
+
+    operator uint32_t() volatile const
+    {
+      return InterlockedAdd((volatile long*)&value, 0);
+    }
+
+  private:
+
+    uint32_t value;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/basic_string.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,2226 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_BASIC_STRING__
+#define __ETL_BASIC_STRING__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <string.h>
+
+#include "platform.h"
+#include "char_traits.h"
+#include "container.h"
+#include "alignment.h"
+#include "array.h"
+#include "algorithm.h"
+#include "type_traits.h"
+#include "error_handler.h"
+#include "integral_limits.h"
+#include "exception.h"
+
+#define ETL_FILE "27"
+
+#ifdef ETL_COMPILER_GCC
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#endif
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef max
+#endif
+
+//*****************************************************************************
+///\defgroup basic_string basic_string
+/// A basic_string with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Alternative strlen for all character types.
+  //***************************************************************************
+  template <typename T>
+  size_t strlen(const T* t)
+  {
+    return etl::char_traits<T>::length(t);
+  }
+
+  //***************************************************************************
+  ///\ingroup string
+  /// Exception base for strings
+  //***************************************************************************
+  class string_exception : public etl::exception
+  {
+  public:
+
+    string_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup string
+  /// String empty exception.
+  //***************************************************************************
+  class string_empty : public etl::string_exception
+  {
+  public:
+
+    string_empty(string_type file_name_, numeric_type line_number_)
+      : string_exception(ETL_ERROR_TEXT("string:empty", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup string
+  /// String out of bounds exception.
+  //***************************************************************************
+  class string_out_of_bounds : public etl::string_exception
+  {
+  public:
+
+    string_out_of_bounds(string_type file_name_, numeric_type line_number_)
+      : string_exception(ETL_ERROR_TEXT("string:bounds", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup string
+  /// String iterator exception.
+  //***************************************************************************
+  class string_iterator : public etl::string_exception
+  {
+  public:
+
+    string_iterator(string_type file_name_, numeric_type line_number_)
+      : string_exception(ETL_ERROR_TEXT("string:iterator", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup string
+  /// The base class for all templated string types.
+  //***************************************************************************
+  class string_base
+  {
+  public:
+
+    typedef size_t size_type;
+
+    enum
+    {
+      npos = etl::integral_limits<size_t>::max
+    };
+
+    //*************************************************************************
+    /// Gets the current size of the string.
+    ///\return The current size of the string.
+    //*************************************************************************
+    size_type size() const
+    {
+      return current_size;
+    }
+
+    //*************************************************************************
+    /// Gets the current size of the string.
+    ///\return The current size of the string.
+    //*************************************************************************
+    size_type length() const
+    {
+      return current_size;
+    }
+
+    //*************************************************************************
+    /// Checks the 'empty' state of the string.
+    ///\return <b>true</b> if empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return (current_size == 0);
+    }
+
+    //*************************************************************************
+    /// Checks the 'full' state of the string.
+    ///\return <b>true</b> if full.
+    //*************************************************************************
+    bool full() const
+    {
+      return current_size == CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the string.
+    ///\return The capacity of the string.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the string.
+    ///\return The maximum size of the string.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return max_size() - size();
+    }
+
+    //*************************************************************************
+    /// Returns whether the string was truncated by the last operation.
+    ///\return Whether the string was truncated by the last operation.
+    //*************************************************************************
+    size_t truncated() const
+    {
+      return is_truncated;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    string_base(size_type max_size_)
+      : is_truncated(false),
+        current_size(0),
+        CAPACITY(max_size_)
+    {
+    }
+
+    bool            is_truncated; ///< Set to true if the operation truncated the string.
+    size_type       current_size; ///< The current number of elements in the string.
+    const size_type CAPACITY;     ///< The maximum number of elements in the string.
+  };
+
+  //***************************************************************************
+  /// The base class for specifically sized strings.
+  /// Can be used as a reference type for all strings containing a specific type.
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  class ibasic_string : public etl::string_base
+  {
+  public:
+
+    typedef T                                     value_type;
+    typedef T&                                    reference;
+    typedef const T&                              const_reference;
+    typedef T*                                    pointer;
+    typedef const T*                              const_pointer;
+    typedef T*                                    iterator;
+    typedef const T*                              const_iterator;
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef size_t                                size_type;
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the string.
+    ///\return An iterator to the beginning of the string.
+    //*********************************************************************
+    iterator begin()
+    {
+      return &p_buffer[0];
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the string.
+    ///\return A const iterator to the beginning of the string.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return &p_buffer[0];
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the string.
+    ///\return An iterator to the end of the string.
+    //*********************************************************************
+    iterator end()
+    {
+      return &p_buffer[current_size];
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the string.
+    ///\return A const iterator to the end of the string.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return &p_buffer[current_size];
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the string.
+    ///\return A const iterator to the beginning of the string.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return &p_buffer[0];
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the string.
+    ///\return A const iterator to the end of the string.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return &p_buffer[current_size];
+    }
+
+    //*********************************************************************
+    /// Returns an reverse iterator to the reverse beginning of the string.
+    ///\return Iterator to the reverse beginning of the string.
+    //*********************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(end());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the string.
+    ///\return Const iterator to the reverse beginning of the string.
+    //*********************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(end());
+    }
+
+    //*********************************************************************
+    /// Returns a reverse iterator to the end + 1 of the string.
+    ///\return Reverse iterator to the end + 1 of the string.
+    //*********************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the string.
+    ///\return Const reverse iterator to the end + 1 of the string.
+    //*********************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the string.
+    ///\return Const reverse iterator to the reverse beginning of the string.
+    //*********************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(cend());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the string.
+    ///\return Const reverse iterator to the end + 1 of the string.
+    //*********************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(cbegin());
+    }
+
+    //*********************************************************************
+    /// Resizes the string.
+    /// If asserts or exceptions are enabled and the new size is larger than the
+    ///\param new_size The new size.
+    //*********************************************************************
+    void resize(size_t new_size)
+    {
+      resize(new_size, 0);
+    }
+
+    //*********************************************************************
+    /// Resizes the string.
+    ///\param new_size The new size.
+    ///\param value    The value to fill new elements with. Default = default constructed value.
+    //*********************************************************************
+    void resize(size_t new_size, T value)
+    {
+      new_size = std::min(new_size, CAPACITY);
+
+      // Size up?
+      if (new_size > current_size)
+      {
+        std::fill(p_buffer + current_size, p_buffer + new_size, value);
+      }
+
+      current_size = new_size;
+      p_buffer[new_size] = 0;
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'i'
+    ///\param i The index.
+    ///\return A reference to the value at index 'i'
+    //*********************************************************************
+    reference operator [](size_t i)
+    {
+      return p_buffer[i];
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'i'
+    ///\param i The index.
+    ///\return A const reference to the value at index 'i'
+    //*********************************************************************
+    const_reference operator [](size_t i) const
+    {
+      return p_buffer[i];
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'i'
+    /// If asserts or exceptions are enabled, emits an etl::string_out_of_bounds if the index is out of range.
+    ///\param i The index.
+    ///\return A reference to the value at index 'i'
+    //*********************************************************************
+    reference at(size_t i)
+    {
+      ETL_ASSERT(i < size(), ETL_ERROR(string_out_of_bounds));
+      return p_buffer[i];
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'i'
+    /// If asserts or exceptions are enabled, emits an etl::string_out_of_bounds if the index is out of range.
+    ///\param i The index.
+    ///\return A const reference to the value at index 'i'
+    //*********************************************************************
+    const_reference at(size_t i) const
+    {
+      ETL_ASSERT(i < size(), ETL_ERROR(string_out_of_bounds));
+      return p_buffer[i];
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the first element.
+    ///\return A reference to the first element.
+    //*********************************************************************
+    reference front()
+    {
+      return p_buffer[0];
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the first element.
+    ///\return A const reference to the first element.
+    //*********************************************************************
+    const_reference front() const
+    {
+      return p_buffer[0];
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the last element.
+    ///\return A reference to the last element.
+    //*********************************************************************
+    reference back()
+    {
+      return p_buffer[current_size - 1];
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the last element.
+    ///\return A const reference to the last element.
+    //*********************************************************************
+    const_reference back() const
+    {
+      return p_buffer[current_size - 1];
+    }
+
+    //*********************************************************************
+    /// Returns a pointer to the beginning of the string data.
+    ///\return A pointer to the beginning of the string data.
+    //*********************************************************************
+    pointer data()
+    {
+      return p_buffer;
+    }
+
+    //*********************************************************************
+    /// Returns a const pointer to the beginning of the string data.
+    ///\return A const pointer to the beginning of the string data.
+    //*********************************************************************
+    const_pointer data() const
+    {
+      return p_buffer;
+    }
+
+    //*********************************************************************
+    /// Assigns values to the string.
+    /// Truncates if the string does not have enough free space.
+    ///\param other The other string.
+    //*********************************************************************
+    void assign(const etl::ibasic_string<T>& other)
+    {
+      size_t len = std::min(CAPACITY, other.size());
+      assign(other.begin(), other.begin() + len);
+    }
+
+    //*********************************************************************
+    /// Assigns values to the string.
+    /// Truncates if the string does not have enough free space.
+    ///\param other The other string.
+    ///\param subposition The position to start from.
+    ///\param sublength   The length to copy.
+    //*********************************************************************
+    void assign(const etl::ibasic_string<T>& other, size_t subposition, size_t sublength)
+    {
+      if (sublength == npos)
+      {
+        sublength = other.size() - subposition;
+      }
+
+      ETL_ASSERT(subposition <= other.size(), ETL_ERROR(string_out_of_bounds));
+
+      assign(other.begin() + subposition, sublength);
+    }
+
+    //*********************************************************************
+    /// Assigns values to the string.
+    /// Truncates if the string does not have enough free space.
+    ///\param other The other string.
+    //*********************************************************************
+    void assign(const_pointer other)
+    {
+      initialise();
+
+      while ((*other != 0) && (current_size < CAPACITY))
+      {
+        p_buffer[current_size++] = *other++;
+      }
+
+      is_truncated = (*other != 0);
+
+      p_buffer[current_size] = 0;
+    }
+
+    //*********************************************************************
+    /// Assigns values to the string.
+    /// Truncates if the string does not have enough free space.
+    ///\param other The other string.
+    ///\param length The length to copy.
+    //*********************************************************************
+    void assign(const_pointer other, size_t length_)
+    {
+      length_ = std::min(length_, CAPACITY);
+
+      initialise();
+
+      etl::copy_n(other, length_, begin());
+
+      current_size = length_;
+      p_buffer[current_size] = 0;
+    }
+
+    //*********************************************************************
+    /// Assigns values to the string.
+    /// If asserts or exceptions are enabled, emits string_iterator if the iterators are reversed.
+    /// Truncates if the string does not have enough free space.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(d >= 0, ETL_ERROR(string_iterator));
+#endif
+
+      initialise();
+
+      while ((first != last) && (current_size != CAPACITY))
+      {
+        p_buffer[current_size++] = *first++;
+      }
+
+      p_buffer[current_size] = 0;
+    }
+
+    //*********************************************************************
+    /// Assigns values to the string.
+    /// Truncates if the string does not have enough free space.
+    ///\param n     The number of elements to add.
+    ///\param value The value to insert for each element.
+    //*********************************************************************
+    void assign(size_t n, T value)
+    {
+      initialise();
+
+      n = std::min(n, CAPACITY);
+
+      std::fill_n(begin(), n, value);
+      current_size = n;
+      p_buffer[current_size] = 0;
+    }
+
+    //*************************************************************************
+    /// Clears the string.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*********************************************************************
+    /// Inserts a value at the end of the string.
+    /// Sets 'truncated' if the string is already full.
+    ///\param value The value to add.
+    //*********************************************************************
+    void push_back(T value)
+    {
+      if (current_size != CAPACITY)
+      {
+        p_buffer[current_size++] = value;
+        is_truncated = false;
+      }
+      else
+      {
+        is_truncated = true;
+      }
+    }
+
+    //*************************************************************************
+    /// Removes an element from the end of the string.
+    /// Does nothing if the string is empty.
+    //*************************************************************************
+    void pop_back()
+    {
+      if (current_size != 0)
+      {
+        p_buffer[--current_size] = 0;
+      }
+    }
+
+    //*********************************************************************
+    /// Appends to the string.
+    ///\param str The string to append.
+    //*********************************************************************
+    ibasic_string& append(const ibasic_string& str)
+    {
+      insert(end(), str.begin(), str.end());
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Appends to the string.
+    ///\param str The string to append.
+    ///\param subposition The position in str.
+    ///\param sublength The number of characters.
+    //*********************************************************************
+    ibasic_string& append(const ibasic_string& str, size_t subposition, size_t sublength = npos)
+    {
+      ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds));
+
+      insert(size(), str, subposition, sublength);
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Appends to the string.
+    ///\param str The string to append.
+    //*********************************************************************
+    ibasic_string& append(const T* str)
+    {
+      insert(size(), str);
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Appends to the string.
+    ///\param str The string to append.
+    ///\param n   The number of characters.
+    //*********************************************************************
+    ibasic_string& append(const T* str, size_t n)
+    {
+      insert(size(), str, n);
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Appends to the string.
+    ///\param n The number of characters.
+    ///\param c The character.
+    //*********************************************************************
+    ibasic_string& append(size_t n, T c)
+    {
+      insert(size(), n, c);
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Appends to the string.
+    ///\param first The first of the characters to append.
+    ///\param last  The last + 1 character to add.
+    //*********************************************************************
+    template <class TIterator>
+    ibasic_string& append(TIterator first, TIterator last)
+    {
+      insert(end(), first, last);
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the string.
+    ///\param position The position to insert before.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(const_iterator position, T value)
+    {
+      is_truncated = false;
+
+      // Quick hack, as iterators are pointers.
+      iterator insert_position = const_cast<iterator>(position);
+
+      if (current_size < CAPACITY)
+      {
+        // Not full yet.
+        if (position != end())
+        {
+          // Insert in the middle.
+          ++current_size;
+          std::copy_backward(insert_position, end() - 1, end());
+          *insert_position = value;
+        }
+        else
+        {
+          // Insert at the end.
+          *insert_position = value;
+          ++current_size;
+        }
+      }
+      else
+      {
+        // Already full.
+        if (position != end())
+        {
+          // Insert in the middle.
+          std::copy_backward(insert_position, end() - 1, end());
+          *insert_position = value;
+        }
+
+        is_truncated = true;
+      }
+
+      p_buffer[current_size] = 0;
+
+      return insert_position;
+    }
+
+    //*********************************************************************
+    /// Inserts 'n' values to the string.
+    ///\param position The position to insert before.
+    ///\param n        The number of elements to add.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    void insert(const_iterator position, size_t n, T value)
+    {
+      is_truncated = false;
+
+      if (n == 0)
+      {
+        return;
+      }
+
+      // Quick hack, as iterators are pointers.
+      iterator insert_position = const_cast<iterator>(position);
+      const size_t start = std::distance(cbegin(), position);
+
+      // No effect.
+      if (start == CAPACITY)
+      {
+        return;
+      }
+
+      // Fills the string to the end?
+      if ((start + n) >= CAPACITY)
+      {
+        is_truncated = ((current_size + n) > CAPACITY);
+        current_size = CAPACITY;
+        std::fill(insert_position, end(), value);
+      }
+      else
+      {
+        // Lets do some shifting.
+        const size_t shift_amount = n;
+        const size_t to_position = start + shift_amount;
+        const size_t remaining_characters = current_size - start;
+        const size_t max_shift_characters = CAPACITY - start - shift_amount;
+        const size_t characters_to_shift = std::min(max_shift_characters, remaining_characters);
+
+        // Will the string truncate?
+        if ((start + shift_amount + remaining_characters) > CAPACITY)
+        {
+          current_size = CAPACITY;
+          is_truncated = true;
+        }
+        else
+        {
+          current_size += shift_amount;
+        }
+
+        std::copy_backward(insert_position, insert_position + characters_to_shift, begin() + to_position + characters_to_shift);
+        std::fill(insert_position, insert_position + shift_amount, value);
+      }
+
+      p_buffer[current_size] = 0;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the string.
+    /// If asserts or exceptions are enabled, emits string_full if the string does not have enough free space.
+    ///\param position The position to insert before.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(iterator position, TIterator first, TIterator last)
+    {
+      is_truncated = false;
+
+      if (first == last)
+      {
+        return;
+      }
+
+      const size_t start = std::distance(begin(), position);
+      const size_t n = std::distance(first, last);
+
+      // No effect.
+      if (start == CAPACITY)
+      {
+        return;
+      }
+
+      // Fills the string to the end?
+      if ((start + n) >= CAPACITY)
+      {
+        is_truncated = ((current_size + n) > CAPACITY);
+        current_size = CAPACITY;
+
+        while (position != end())
+        {
+          *position++ = *first++;
+        }
+      }
+      else
+      {
+        // Lets do some shifting.
+        const size_t shift_amount = n;
+        const size_t to_position = start + shift_amount;
+        const size_t remaining_characters = current_size - start;
+        const size_t max_shift_characters = CAPACITY - start - shift_amount;
+        const size_t characters_to_shift = std::min(max_shift_characters, remaining_characters);
+
+        // Will the string truncate?
+        if ((start + shift_amount + remaining_characters) > CAPACITY)
+        {
+          current_size = CAPACITY;
+          is_truncated = true;
+        }
+        else
+        {
+          current_size += shift_amount;
+        }
+
+        std::copy_backward(position, position + characters_to_shift, begin() + to_position + characters_to_shift);
+
+        while (first != last)
+        {
+          *position++ = *first++;
+        }
+      }
+
+      p_buffer[current_size] = 0;
+    }
+
+    //*********************************************************************
+    /// Inserts a string at the specified position.
+    ///\param position The position to insert before.
+    ///\param str      The string to insert.
+    //*********************************************************************
+    etl::ibasic_string<T>& insert(size_t position, const etl::ibasic_string<T>& str)
+    {
+      ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+      insert(begin() + position, str.cbegin(), str.cend());
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Inserts a string at the specified position from subposition for sublength.
+    ///\param position    The position to insert before.
+    ///\param str         The string to insert.
+    ///\param subposition The subposition to start from.
+    ///\param sublength   The number of characters to insert.
+    //*********************************************************************
+    etl::ibasic_string<T>& insert(size_t position, const etl::ibasic_string<T>& str, size_t subposition, size_t sublength)
+    {
+      ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+      ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds));
+
+      if ((sublength == npos) || (subposition + sublength > str.size()))
+      {
+        sublength = str.size() - subposition;
+      }
+
+      insert(begin() + position, str.cbegin() + subposition, str.cbegin() + subposition + sublength);
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Inserts a string at the specified position from pointer.
+    ///\param position The position to insert before.
+    ///\param s        The string to insert.
+    //*********************************************************************
+    etl::ibasic_string<T>& insert(size_t position, const_pointer s)
+    {
+      ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+      insert(begin() + position, s, s + strlen(s));
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Inserts a string at the specified position from pointer for n characters.
+    ///\param position The position to insert before.
+    ///\param s        The string to insert.
+    ///\param n        The number of characters to insert.
+    //*********************************************************************
+    etl::ibasic_string<T>& insert(size_t position, const_pointer s, size_t n)
+    {
+      ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+      insert(begin() + position, s, s + n);
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Insert n characters of c at position.
+    ///\param position The position to insert before.
+    ///\param n        The number of characters to insert.
+    ///\param c        The character to insert.
+    //*********************************************************************
+    etl::ibasic_string<T>& insert(size_t position, size_t n, value_type c)
+    {
+      ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+      insert(begin() + position, n, c);
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Erases a sequence.
+    ///\param position Position to start from.
+    ///\param length   Number of characters.
+    ///\return A refernce to this string.
+    //*********************************************************************
+    etl::ibasic_string<T>& erase(size_t position, size_t length_ = npos)
+    {
+      // Limit the length.
+      length_ = std::min(length_, size() - position);
+
+      erase(begin() + position, begin() + position + length_);
+
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param i_element Iterator to the element.
+    ///\return An iterator pointing to the element that followed the erased element.
+    //*********************************************************************
+    iterator erase(iterator i_element)
+    {
+      std::copy(i_element + 1, end(), i_element);
+      p_buffer[--current_size] = 0;
+
+      return i_element;
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    ///\return An iterator pointing to the element that followed the erased element.
+    //*********************************************************************
+    iterator erase(iterator first, iterator last)
+    {
+      std::copy(last, end(), first);
+      size_t n_delete = std::distance(first, last);
+
+      current_size -= n_delete;
+      p_buffer[current_size] = 0;
+
+      return first;
+    }
+
+    //*********************************************************************
+    /// Return a pointer to a C string.
+    //*********************************************************************
+    const_pointer c_str() const
+    {
+      return p_buffer;
+    }
+
+    //*********************************************************************
+    /// Copies a portion of a string.
+    ///\param s   Pointer to the string to copy.
+    ///\param len The number of characters to copy.
+    ///\param pos The position to start copying from.
+    //*********************************************************************
+    size_t copy(pointer s, size_t len, size_t pos = 0)
+    {
+      size_t endpos = std::min(pos + len, size());
+
+      for (size_t i = pos; i < endpos; ++i)
+      {
+        *s++ = p_buffer[i];
+      }
+
+      return endpos - pos;
+    }
+
+    //*********************************************************************
+    /// Find content within the string
+    ///\param str The content to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find(const ibasic_string<T>& str, size_t pos = 0) const
+    {
+      if ((pos + str.size()) > size())
+      {
+        return npos;
+      }
+
+      const_iterator iposition = std::search(begin() + pos, end(), str.begin(), str.end());
+
+      if (iposition == end())
+      {
+        return npos;
+      }
+      else
+      {
+        return std::distance(begin(), iposition);
+      }
+    }
+
+    //*********************************************************************
+    /// Find content within the string
+    ///\param s   Pointer to the content to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find(const_pointer s, size_t pos = 0) const
+    {
+#if defined(ETL_DEBUG)
+      if ((pos + etl::strlen(s)) > size())
+      {
+        return npos;
+      }
+#endif
+
+      const_iterator iposition = std::search(begin() + pos, end(), s, s + etl::strlen(s));
+
+      if (iposition == end())
+      {
+        return npos;
+      }
+      else
+      {
+        return std::distance(begin(), iposition);
+      }
+    }
+
+    //*********************************************************************
+    /// Find content within the string
+    ///\param s   Pointer to the content to find
+    ///\param pos The position to start searching from.
+    ///\param n   The number of characters to search for.
+    //*********************************************************************
+    size_t find(const_pointer s, size_t pos, size_t n) const
+    {
+#if defined(ETL_DEBUG)
+      if ((pos + etl::strlen(s) - n) > size())
+      {
+        return npos;
+      }
+#endif
+
+      const_iterator iposition = std::search(begin() + pos, end(), s, s + n);
+
+      if (iposition == end())
+      {
+        return npos;
+      }
+      else
+      {
+        return std::distance(begin(), iposition);
+      }
+    }
+
+    //*********************************************************************
+    /// Find character within the string
+    ///\param c        The character to find.
+    ///\param position The position to start searching from.
+    //*********************************************************************
+    size_t find(T c, size_t position = 0) const
+    {
+      const_iterator i = std::find(begin() + position, end(), c);
+
+      if (i != end())
+      {
+        return std::distance(begin(), i);
+      }
+      else
+      {
+        return npos;
+      }
+    }
+
+    //*********************************************************************
+    /// Find content within the string
+    ///\param str The content to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t rfind(const ibasic_string<T>& str, size_t position = npos) const
+    {
+      if ((str.size()) > size())
+      {
+        return npos;
+      }
+
+      if (position >= size())
+      {
+        position = size();
+      }
+
+      position = size() - position;
+
+      const_reverse_iterator iposition = std::search(rbegin() + position, rend(), str.rbegin(), str.rend());
+
+      if (iposition == rend())
+      {
+        return npos;
+      }
+      else
+      {
+        return size() - str.size() - std::distance(rbegin(), iposition);
+      }
+    }
+
+    //*********************************************************************
+    /// Find content within the string
+    ///\param str The content to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t rfind(const_pointer s, size_t position = npos) const
+    {
+      size_t len = etl::strlen(s);
+
+      if (len > size())
+      {
+        return npos;
+      }
+
+      if (position >= size())
+      {
+        position = size();
+      }
+
+      position = size() - position;
+
+      const_reverse_iterator srbegin(s + len);
+      const_reverse_iterator srend(s);
+
+      const_reverse_iterator iposition = std::search(rbegin() + position, rend(), srbegin, srend);
+
+      if (iposition == rend())
+      {
+        return npos;
+      }
+      else
+      {
+        return size() - len - std::distance(rbegin(), iposition);
+      }
+    }
+
+    //*********************************************************************
+    /// Find content within the string
+    ///\param str The content to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t rfind(const_pointer s, size_t position, size_t length_) const
+    {
+      if (length_ > size())
+      {
+        return npos;
+      }
+
+      if (position >= size())
+      {
+        position = size();
+      }
+
+      position = size() - position;
+
+      const_reverse_iterator srbegin(s + length_);
+      const_reverse_iterator srend(s);
+
+      const_reverse_iterator iposition = std::search(rbegin() + position, rend(), srbegin, srend);
+
+      if (iposition == rend())
+      {
+        return npos;
+      }
+      else
+      {
+        return size() - length_ - std::distance(rbegin(), iposition);
+      }
+    }
+
+    //*********************************************************************
+    /// Find character within the string
+    ///\param c   The character to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t rfind(T c, size_t position = npos) const
+    {
+      if (position >= size())
+      {
+        position = size();
+      }
+
+      position = size() - position;
+
+      const_reverse_iterator i = std::find(rbegin() + position, rend(), c);
+
+      if (i != rend())
+      {
+        return size() - std::distance(rbegin(), i) - 1;
+      }
+      else
+      {
+        return npos;
+      }
+    }
+
+    //*********************************************************************
+    /// Replace 'length' characters from 'position' with 'str'.
+    ///\param position The position to start from.
+    ///\param length   The number of characters to replace.
+    ///\param str      The string to replace it with.
+    //*********************************************************************
+    ibasic_string& replace(size_t position, size_t length_, const ibasic_string& str)
+    {
+      ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+      // Limit the length.
+      length_ = std::min(length_, size() - position);
+
+      // Erase the bit we want to replace.
+      erase(position, length_);
+
+      // Insert the new stuff.
+      insert(position, str);
+
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Replace characters from 'first' to one before 'last' with 'str'.
+    ///\param first The position to start from.
+    ///\param last  The one after the position to end at.
+    ///\param str   The string to replace it with.
+    //*********************************************************************
+    ibasic_string& replace(const_iterator first, const_iterator last, const ibasic_string& str)
+    {
+      // Quick hack, as iterators are pointers.
+      iterator first_ = const_cast<iterator>(first);
+      iterator last_ = const_cast<iterator>(last);
+
+      // Erase the bit we want to replace.
+      erase(first_, last_);
+
+      // Insert the new stuff.
+      insert(first_, str.begin(), str.end());
+
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Replace characters from 'position' of 'length' with 'str' from 'subpsotion' of 'sublength'.
+    //*********************************************************************
+    ibasic_string& replace(size_t position, size_t length_, const ibasic_string& str, size_t subposition, size_t sublength)
+    {
+      ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+      ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds));
+
+      // Limit the lengths.
+      length_ = std::min(length_, size() - position);
+      sublength = std::min(sublength, str.size() - subposition);
+
+      // Erase the bit we want to replace.
+      erase(position, length_);
+
+      // Insert the new stuff.
+      insert(position, str, subposition, sublength);
+
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Replace characters from 'position' of 'length' with pointed to string.
+    //*********************************************************************
+    ibasic_string& replace(size_t position, size_t length_, const_pointer s)
+    {
+      ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+      // Limit the length.
+      length_ = std::min(length_, size() - position);
+
+      // Erase the bit we want to replace.
+      erase(position, length_);
+
+      // Insert the new stuff.
+      insert(position, s, etl::strlen(s));
+
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Replace characters from 'first'  'last' with pointed to string.
+    //*********************************************************************
+    ibasic_string& replace(const_iterator first, const_iterator last, const_pointer s)
+    {
+      // Quick hack, as iterators are pointers.
+      iterator first_ = const_cast<iterator>(first);
+      iterator last_ = const_cast<iterator>(last);
+
+      // Erase the bit we want to replace.
+      erase(first_, last_);
+
+      // Insert the new stuff.
+      insert(first_, s, s + etl::strlen(s));
+
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Replace characters from 'position' of 'length' with 'n' characters from pointed to string.
+    //*********************************************************************
+    ibasic_string& replace(size_t position, size_t length_, const_pointer s, size_t n)
+    {
+      ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+      // Limit the length.
+      length_ = std::min(length_, size() - position);
+
+      // Erase the bit we want to replace.
+      erase(position, length_);
+
+      // Insert the new stuff.
+      insert(position, s, n);
+
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Replace characters from 'first' to 'last' with 'n' characters from pointed to string.
+    //*********************************************************************
+    ibasic_string& replace(const_iterator first, const_iterator last, const_pointer s, size_t n)
+    {
+      // Quick hack, as iterators are pointers.
+      iterator first_ = const_cast<iterator>(first);
+      iterator last_ = const_cast<iterator>(last);
+
+      // Erase the bit we want to replace.
+      erase(first_, last_);
+
+      // Insert the new stuff.
+      insert(first_, s, s + n);
+
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Replace characters from 'position' of 'length' with 'n' copies of 'c'.
+    //*********************************************************************
+    ibasic_string& replace(size_t position, size_t length_, size_t n, value_type c)
+    {
+      ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+      // Limit the length.
+      length_ = std::min(length_, size() - position);
+
+      // Erase the bit we want to replace.
+      erase(position, length_);
+
+      // Insert the new stuff.
+      insert(position, n, c);
+
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Replace characters from 'first' of 'last' with 'n' copies of 'c'.
+    //*********************************************************************
+    ibasic_string& replace(const_iterator first, const_iterator last, size_t n, value_type c)
+    {
+      // Quick hack, as iterators are pointers.
+      iterator first_ = const_cast<iterator>(first);
+      iterator last_ = const_cast<iterator>(last);
+
+      // Erase the bit we want to replace.
+      erase(first_, last_);
+
+      // Insert the new stuff.
+      insert(first_, n, c);
+
+      return *this;
+    }
+
+    //*********************************************************************
+    /// Replace characters from 'first' of 'last' with characters from 'first_replace' to 'last_replace'.
+    //*********************************************************************
+    template <typename TIterator>
+    ibasic_string& replace(const_iterator first, const_iterator last, TIterator first_replace, TIterator last_replace)
+    {
+      // Quick hack, as iterators are pointers.
+      iterator first_ = const_cast<iterator>(first);
+      iterator last_ = const_cast<iterator>(last);
+
+      // Erase the bit we want to replace.
+      erase(first_, last_);
+
+      // Insert the new stuff.
+      insert(first_, first_replace, last_replace);
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Compare with string.
+    //*************************************************************************
+    int compare(const ibasic_string& str) const
+    {
+      return compare(p_buffer,
+        p_buffer + size(),
+        str.p_buffer,
+        str.p_buffer + str.size());
+    }
+
+    //*************************************************************************
+    /// Compare position / length with string.
+    //*************************************************************************
+    int compare(size_t position, size_t length_, const ibasic_string& str) const
+    {
+      ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+
+      // Limit the length.
+      length_ = std::min(length_, size() - position);
+
+      return compare(p_buffer + position,
+        p_buffer + position + length_,
+        str.p_buffer,
+        str.p_buffer + str.size());
+    }
+
+    //*************************************************************************
+    /// Compare position / length with string / subposition / sublength.
+    //*************************************************************************
+    int compare(size_t position, size_t length_, const ibasic_string& str, size_t subposition, size_t sublength) const
+    {
+      ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds));
+      ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds));
+
+      // Limit the lengths.
+      length_ = std::min(length_, size() - position);
+      sublength = std::min(sublength, str.size() - subposition);
+
+      return compare(p_buffer + position,
+        p_buffer + position + length_,
+        str.p_buffer + subposition,
+        str.p_buffer + subposition + sublength);
+    }
+
+    //*************************************************************************
+    ///  Compare with C string
+    //*************************************************************************
+    int compare(const value_type* s) const
+    {
+      return compare(p_buffer,
+        p_buffer + size(),
+        s,
+        s + etl::strlen(s));
+    }
+
+    //*************************************************************************
+    /// Compare position / length with C string.
+    //*************************************************************************
+    int compare(size_t position, size_t length_, const_pointer s) const
+    {
+      return compare(p_buffer + position,
+        p_buffer + position + length_,
+        s,
+        s + etl::strlen(s));
+    }
+
+    //*************************************************************************
+    /// Compare position / length with C string / n.
+    //*************************************************************************
+    int compare(size_t position, size_t length_, const_pointer s, size_t n) const
+    {
+      return compare(p_buffer + position,
+        p_buffer + position + length_,
+        s,
+        s + n);;
+    }
+
+    //*********************************************************************
+    /// Find first of any of content within the string
+    ///\param str The content to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find_first_of(const ibasic_string<T>& str, size_t position = 0) const
+    {
+      return find_first_of(str.c_str(), position, str.size());
+    }
+
+    //*********************************************************************
+    /// Find first of any of content within the string
+    ///\param s   Pointer to the content to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find_first_of(const_pointer s, size_t position = 0) const
+    {
+      return find_first_of(s, position, etl::strlen(s));
+    }
+
+    //*********************************************************************
+    /// Find first of any of content within the string
+    ///\param s   Pointer to the content to find
+    ///\param pos The position to start searching from.
+    ///\param n   The number of characters to search for.
+    //*********************************************************************
+    size_t find_first_of(const_pointer s, size_t position, size_t n) const
+    {
+      if (position < size())
+      {
+        for (size_t i = position; i < size(); ++i)
+        {
+          for (size_t j = 0; j < n; ++j)
+          {
+            if (p_buffer[i] == s[j])
+            {
+              return i;
+            }
+          }
+        }
+      }
+
+      return npos;
+    }
+
+    //*********************************************************************
+    /// Find first of character within the string
+    ///\param c   The character to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find_first_of(value_type c, size_t position = 0) const
+    {
+      if (position < size())
+      {
+        for (size_t i = position; i < size(); ++i)
+        {
+          if (p_buffer[i] == c)
+          {
+            return i;
+          }
+        }
+      }
+
+      return npos;
+    }
+
+    //*********************************************************************
+    /// Find last of any of content within the string
+    ///\param str The content to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find_last_of(const ibasic_string<T>& str, size_t position = npos) const
+    {
+      return find_last_of(str.c_str(), position, str.size());
+    }
+
+    //*********************************************************************
+    /// Find last of any of content within the string
+    ///\param s   Pointer to the content to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find_last_of(const_pointer s, size_t position = npos) const
+    {
+      return find_last_of(s, position, etl::strlen(s));
+    }
+
+    //*********************************************************************
+    /// Find last of any of content within the string
+    ///\param s   Pointer to the content to find
+    ///\param pos The position to start searching from.
+    ///\param n   The number of characters to search for.
+    //*********************************************************************
+    size_t find_last_of(const_pointer s, size_t position, size_t n) const
+    {
+      if (empty())
+      {
+        return npos;
+      }
+
+      position = std::min(position, size() - 1);
+
+      const_reverse_iterator it = rbegin() + size() - position - 1;
+
+      while (it != rend())
+      {
+        for (size_t j = 0; j < n; ++j)
+        {
+          if (p_buffer[position] == s[j])
+          {
+            return position;
+          }
+        }
+
+        ++it;
+        --position;
+      }
+
+      return npos;
+    }
+
+    //*********************************************************************
+    /// Find last of character within the string
+    ///\param c   The character to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find_last_of(value_type c, size_t position = npos) const
+    {
+      if (empty())
+      {
+        return npos;
+      }
+
+      position = std::min(position, size() - 1);
+
+      const_reverse_iterator it = rbegin() + size() - position - 1;
+
+      while (it != rend())
+      {
+        if (p_buffer[position] == c)
+        {
+          return position;
+        }
+
+        ++it;
+        --position;
+      }
+
+      return npos;
+    }
+
+    //*********************************************************************
+    /// Find first not of any of content within the string
+    ///\param str The content to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find_first_not_of(const ibasic_string<T>& str, size_t position = 0) const
+    {
+      return find_first_not_of(str.c_str(), position, str.size());
+    }
+
+    //*********************************************************************
+    /// Find first not of any of content within the string
+    ///\param s   Pointer to the content to not find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find_first_not_of(const_pointer s, size_t position = 0) const
+    {
+      return find_first_not_of(s, position, etl::strlen(s));
+    }
+
+    //*********************************************************************
+    /// Find first not of any of content within the string
+    ///\param s   Pointer to the content to not find
+    ///\param pos The position to start searching from.
+    ///\param n   The number of characters to search for.
+    //*********************************************************************
+    size_t find_first_not_of(const_pointer s, size_t position, size_t n) const
+    {
+      if (position < size())
+      {
+        for (size_t i = position; i < size(); ++i)
+        {
+          bool found = false;
+
+          for (size_t j = 0; j < n; ++j)
+          {
+            if (p_buffer[i] == s[j])
+            {
+              found = true;
+            }
+          }
+
+          if (!found)
+          {
+            return i;
+          }
+        }
+      }
+
+      return npos;
+    }
+
+    //*********************************************************************
+    /// Find first not of character within the string
+    ///\param c   The character to not find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find_first_not_of(value_type c, size_t position = 0) const
+    {
+      if (position < size())
+      {
+        for (size_t i = position; i < size(); ++i)
+        {
+          if (p_buffer[i] != c)
+          {
+            return i;
+          }
+        }
+      }
+
+      return npos;
+    }
+
+    //*********************************************************************
+    /// Find last not of any of content within the string
+    ///\param str The content to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find_last_not_of(const ibasic_string<T>& str, size_t position = npos) const
+    {
+      return find_last_not_of(str.c_str(), position, str.size());
+    }
+
+    //*********************************************************************
+    /// Find last not of any of content within the string
+    ///\param s   The pointer to the content to find
+    ///\param pos The position to start searching from.
+    //*********************************************************************
+    size_t find_last_not_of(const_pointer s, size_t position = npos) const
+    {
+      return find_last_not_of(s, position, etl::strlen(s));
+    }
+
+    //*********************************************************************
+    /// Find last not of any of content within the string
+    ///\param s   The pointer to the content to find
+    ///\param pos The position to start searching from.
+    ///\param n   The number of characters to use.
+    //*********************************************************************
+    size_t find_last_not_of(const_pointer s, size_t position, size_t n) const
+    {
+      if (empty())
+      {
+        return npos;
+      }
+
+      position = std::min(position, size() - 1);
+
+      const_reverse_iterator it = rbegin() + size() - position - 1;
+
+      while (it != rend())
+      {
+        bool found = false;
+
+        for (size_t j = 0; j < n; ++j)
+        {
+          if (p_buffer[position] == s[j])
+          {
+            found = true;
+          }
+        }
+
+        if (!found)
+        {
+          return position;
+        }
+
+        ++it;
+        --position;
+      }
+
+      return npos;
+    }
+
+    //*********************************************************************
+    //
+    //*********************************************************************
+    size_t find_last_not_of(value_type c, size_t position = npos) const
+    {
+      if (empty())
+      {
+        return npos;
+      }
+
+      position = std::min(position, size() - 1);
+
+      const_reverse_iterator it = rbegin() + size() - position - 1;
+
+      while (it != rend())
+      {
+        if (p_buffer[position] != c)
+        {
+          return position;
+        }
+
+        ++it;
+        --position;
+      }
+
+      return npos;
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    ibasic_string& operator = (const ibasic_string& rhs)
+    {
+      if (&rhs != this)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// += operator.
+    //*************************************************************************
+    ibasic_string& operator += (const ibasic_string& rhs)
+    {
+      if (&rhs != this)
+      {
+        append(rhs);
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// += operator.
+    //*************************************************************************
+    ibasic_string& operator += (const T* rhs)
+    {
+      append(rhs);
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// += operator.
+    //*************************************************************************
+    ibasic_string& operator += (T rhs)
+    {
+      append(size_t(1), rhs);
+
+      return *this;
+    }
+
+#ifdef ETL_ISTRING_REPAIR_ENABLE
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    virtual void repair() = 0;
+#endif
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    ibasic_string(T* p_buffer_, size_t MAX_SIZE_)
+      : string_base(MAX_SIZE_),
+        p_buffer(p_buffer_)
+    {
+    }
+
+    //*********************************************************************
+    /// Initialise the string.
+    //*********************************************************************
+    void initialise()
+    {
+      current_size = 0;
+      p_buffer[0] = 0;
+    }
+
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    void repair(T* p_buffer_)
+    {
+      p_buffer = p_buffer_;
+    }
+
+  private:
+
+    //*************************************************************************
+    /// Compare helper function
+    //*************************************************************************
+    int compare(const_pointer first1, const_pointer last1, const_pointer first2, const_pointer last2) const
+    {
+      while ((first1 != last1) && (first2 != last2))
+      {
+        if (*first1 < *first2)
+        {
+          // Compared character is lower.
+          return -1;
+        }
+        else if (*first1 > *first2)
+        {
+          // Compared character is higher.
+          return 1;
+        }
+
+        ++first1;
+        ++first2;
+      }
+
+      // We reached the end of one or both of the strings.
+      if ((first1 == last1) && (first2 == last2))
+      {
+        // Same length.
+        return 0;
+      }
+      else if (first1 == last1)
+      {
+        // Compared string is shorter.
+        return -1;
+      }
+      else
+      {
+        // Compared string is longer.
+        return 1;
+      }
+    }
+
+    // Disable copy construction.
+    ibasic_string(const ibasic_string&);
+
+    T* p_buffer;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator ==(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator ==(const etl::ibasic_string<T>& lhs, const T* rhs)
+  {
+    return (lhs.size() == etl::strlen(rhs)) && std::equal(lhs.begin(), lhs.end(), rhs);
+  }
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator ==(const T* lhs, const etl::ibasic_string<T>& rhs)
+  {
+    return (rhs.size() == etl::strlen(lhs)) && std::equal(rhs.begin(), rhs.end(), lhs);
+  }
+
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator !=(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator !=(const etl::ibasic_string<T>& lhs, const T* rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator !=(const T* lhs, const etl::ibasic_string<T>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+
+  //***************************************************************************
+  /// Less than operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the first string is lexicographically less than the second, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator <(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs)
+  {
+    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+  }
+
+  //***************************************************************************
+  /// Less than operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the first string is lexicographically less than the second, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator <(const etl::ibasic_string<T>& lhs, const T* rhs)
+  {
+    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs, rhs + etl::strlen(rhs));
+  }
+
+  //***************************************************************************
+  /// Less than operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the first string is lexicographically less than the second, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator <(const T* lhs, const etl::ibasic_string<T>& rhs)
+  {
+    return std::lexicographical_compare(lhs, lhs + etl::strlen(lhs), rhs.begin(), rhs.end());
+  }
+
+
+  //***************************************************************************
+  /// Greater than operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the first string is lexicographically greater than the second, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator >(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs)
+  {
+    return (rhs < lhs);
+  }
+
+  //***************************************************************************
+  /// Greater than operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the first string is lexicographically greater than the second, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator >(const etl::ibasic_string<T>& lhs, const T* rhs)
+  {
+    return (rhs < lhs);
+  }
+
+  //***************************************************************************
+  /// Greater than operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the first string is lexicographically greater than the second, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator >(const T* lhs, const etl::ibasic_string<T>& rhs)
+  {
+    return (rhs < lhs);
+  }
+
+
+  //***************************************************************************
+  /// Less than or equal operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the first string is lexicographically less than or equal to the second, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator <=(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs)
+  {
+    return !(lhs > rhs);
+  }
+
+  //***************************************************************************
+  /// Less than or equal operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the first string is lexicographically less than or equal to the second, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator <=(const etl::ibasic_string<T>& lhs, const T* rhs)
+  {
+    return !(lhs > rhs);
+  }
+
+  //***************************************************************************
+  /// Less than or equal operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the first string is lexicographically less than or equal to the second, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator <=(const T* lhs, const etl::ibasic_string<T>& rhs)
+  {
+    return !(lhs > rhs);
+  }
+
+
+  //***************************************************************************
+  /// Greater than or equal operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the first string is lexicographically greater than or equal to the second, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator >=(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs)
+  {
+    return !(lhs < rhs);
+  }
+
+  //***************************************************************************
+  /// Greater than or equal operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the first string is lexicographically greater than or equal to the second, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator >=(const etl::ibasic_string<T>& lhs, const T* rhs)
+  {
+    return !(lhs < rhs);
+  }
+
+  //***************************************************************************
+  /// Greater than or equal operator.
+  ///\param lhs Reference to the first string.
+  ///\param rhs Reference to the second string.
+  ///\return <b>true</b> if the first string is lexicographically greater than or equal to the second, otherwise <b>false</b>
+  ///\ingroup string
+  //***************************************************************************
+  template <typename T>
+  bool operator >=(const T* lhs, const etl::ibasic_string<T>& rhs)
+  {
+    return !(lhs < rhs);
+  }
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/binary.cpp	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,471 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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.
+******************************************************************************/
+
+#include "platform.h"
+#include "binary.h"
+
+namespace etl
+{
+#if ETL_8BIT_SUPPORT
+  //***************************************************************************
+  /// Reverse 8 bits.
+  //***************************************************************************
+  uint8_t reverse_bits(uint8_t value)
+  {
+    value = ((value & 0xAA) >> 1) | ((value & 0x55) << 1);
+    value = ((value & 0xCC) >> 2) | ((value & 0x33) << 2);
+    value = (value >> 4) | (value << 4);
+
+    return value;
+  }
+#endif
+
+  //***************************************************************************
+  /// Reverse 16 bits.
+  //***************************************************************************
+  uint16_t reverse_bits(uint16_t value)
+  {
+    value = ((value & 0xAAAA) >> 1) | ((value & 0x5555) << 1);
+    value = ((value & 0xCCCC) >> 2) | ((value & 0x3333) << 2);
+    value = ((value & 0xF0F0) >> 4) | ((value & 0x0F0F) << 4);
+    value = (value >> 8) | (value << 8);
+
+    return value;
+  }
+ 
+  //***************************************************************************
+  /// Reverse 32 bits.
+  //***************************************************************************
+  uint32_t reverse_bits(uint32_t value)
+  {
+    value = ((value & 0xAAAAAAAA) >>  1) | ((value & 0x55555555) <<  1);
+    value = ((value & 0xCCCCCCCC) >>  2) | ((value & 0x33333333) <<  2);
+    value = ((value & 0xF0F0F0F0) >>  4) | ((value & 0x0F0F0F0F) <<  4);
+    value = ((value & 0xFF00FF00) >>  8) | ((value & 0x00FF00FF) <<  8);
+    value = (value >> 16) | (value << 16);
+
+    return value;
+  }
+
+  //***************************************************************************
+  /// Reverse 64 bits.
+  //***************************************************************************
+  uint64_t reverse_bits(uint64_t value)
+  {
+    value = ((value & 0xAAAAAAAAAAAAAAAA) >>  1) | ((value & 0x5555555555555555) <<  1);
+    value = ((value & 0xCCCCCCCCCCCCCCCC) >>  2) | ((value & 0x3333333333333333) <<  2);
+    value = ((value & 0xF0F0F0F0F0F0F0F0) >>  4) | ((value & 0x0F0F0F0F0F0F0F0F) <<  4);
+    value = ((value & 0xFF00FF00FF00FF00) >>  8) | ((value & 0x00FF00FF00FF00FF) <<  8);
+    value = ((value & 0xFFFF0000FFFF0000) >> 16) | ((value & 0x0000FFFF0000FFFF) << 16);
+    value = (value >> 32) | (value << 32);
+
+    return value;
+  }
+
+  //***************************************************************************
+  /// Reverse bytes 16 bit.
+  //***************************************************************************
+  uint16_t reverse_bytes(uint16_t value)
+  {
+    value = (value >> 8) | (value << 8);
+
+    return value;
+  }
+
+  //***************************************************************************
+  /// Reverse bytes 32 bit.
+  //***************************************************************************
+  uint32_t reverse_bytes(uint32_t value)
+  {
+    value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
+    value = (value >> 16) | (value << 16);
+
+    return value;
+  }
+  
+  //***************************************************************************
+  /// Reverse bytes 64 bit.
+  //***************************************************************************
+  uint64_t reverse_bytes(uint64_t value)
+  {
+    value = ((value & 0xFF00FF00FF00FF00) >> 8)  | ((value & 0x00FF00FF00FF00FF) << 8);
+    value = ((value & 0xFFFF0000FFFF0000) >> 16) | ((value & 0x0000FFFF0000FFFF) << 16);
+    value = (value >> 32) | (value << 32);
+
+    return value;
+  }
+
+#if ETL_8BIT_SUPPORT
+  //***************************************************************************
+  /// Converts Gray code to binary.
+  //***************************************************************************
+  uint8_t gray_to_binary(uint8_t value)
+  {
+    value ^= (value >> 4);
+    value ^= (value >> 2);
+    value ^= (value >> 1);
+
+    return value;
+  }
+#endif
+
+  //***************************************************************************
+  /// Converts Gray code to binary.
+  //***************************************************************************
+  uint16_t gray_to_binary(uint16_t value)
+  {
+    value ^= (value >> 8);
+    value ^= (value >> 4);
+    value ^= (value >> 2);
+    value ^= (value >> 1);
+
+    return value;
+  }
+
+  //***************************************************************************
+  /// Converts Gray code to binary.
+  //***************************************************************************
+  uint32_t gray_to_binary(uint32_t value)
+  {
+    value ^= (value >> 16);
+    value ^= (value >> 8);
+    value ^= (value >> 4);
+    value ^= (value >> 2);
+    value ^= (value >> 1);
+
+    return value;
+  }
+
+  //***************************************************************************
+  /// Converts Gray code to binary.
+  //***************************************************************************
+  uint64_t gray_to_binary(uint64_t value)
+  {
+    value ^= (value >> 32);
+    value ^= (value >> 16);
+    value ^= (value >> 8);
+    value ^= (value >> 4);
+    value ^= (value >> 2);
+    value ^= (value >> 1);
+
+    return value;
+  }
+
+#if ETL_8BIT_SUPPORT
+  //***************************************************************************
+  /// Count set bits. 8 bits.
+  //***************************************************************************
+  uint_least8_t count_bits(uint8_t value)
+  {
+    uint32_t count;
+    static const int S[] = { 1, 2, 4 };
+    static const uint8_t B[] = { 0x55, 0x33, 0x0F };
+
+    count = value - ((value >> 1) & B[0]);
+    count = ((count >> S[1]) & B[1]) + (count & B[1]);
+    count = ((count >> S[2]) + count) & B[2];
+
+    return uint_least8_t(count);
+  }
+#endif
+
+  //***************************************************************************
+  /// Count set bits. 16 bits.
+  //***************************************************************************
+  uint_least8_t count_bits(uint16_t value)
+  {
+    uint32_t count;
+    static const int S[] = { 1, 2, 4, 8 };
+    static const uint16_t B[] = { 0x5555, 0x3333, 0x0F0F, 0x00FF };
+
+    count = value - ((value >> 1) & B[0]);
+    count = ((count >> S[1]) & B[1]) + (count & B[1]);
+    count = ((count >> S[2]) + count) & B[2];
+    count = ((count >> S[3]) + count) & B[3];
+
+    return count;
+  }
+
+  //***************************************************************************
+  /// Count set bits. 32 bits.
+  //***************************************************************************
+  uint_least8_t count_bits(uint32_t value)
+  {
+    uint32_t count;
+
+    value = value - ((value >> 1) & 0x55555555);
+    value = (value & 0x33333333) + ((value >> 2) & 0x33333333);
+    count = (((value + (value >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
+
+    return uint_least8_t(count);
+  }
+
+  //***************************************************************************
+  /// Count set bits. 64 bits.
+  //***************************************************************************
+  uint_least8_t count_bits(uint64_t value)
+  {
+    uint64_t count;
+    static const int S[] = { 1, 2, 4, 8, 16, 32 };
+    static const uint64_t B[] = { 0x5555555555555555, 0x3333333333333333, 0x0F0F0F0F0F0F0F0F, 0x00FF00FF00FF00FF, 0x0000FFFF0000FFFF, 0x00000000FFFFFFFF };
+
+    count = value - ((value >> 1) & B[0]);
+    count = ((count >> S[1]) & B[1]) + (count & B[1]);
+    count = ((count >> S[2]) + count) & B[2];
+    count = ((count >> S[3]) + count) & B[3];
+    count = ((count >> S[4]) + count) & B[4];
+    count = ((count >> S[5]) + count) & B[5];
+
+    return uint_least8_t(count);
+  }
+
+#if ETL_8BIT_SUPPORT
+  //***************************************************************************
+  /// Parity. 8bits. 0 = even, 1 = odd
+  //***************************************************************************
+  uint_least8_t parity(uint8_t value)
+  {
+    value ^= value >> 4;
+    value &= 0x0F;
+    return (0x6996 >> value) & 1;
+  }
+#endif
+
+  //***************************************************************************
+  /// Parity. 16bits. 0 = even, 1 = odd
+  //***************************************************************************
+  uint_least8_t parity(uint16_t value)
+  {
+    value ^= value >> 8;
+    value ^= value >> 4;
+    value &= 0x0F;
+    return (0x6996 >> value) & 1;
+  }
+
+  //***************************************************************************
+  /// Parity. 32bits. 0 = even, 1 = odd
+  //***************************************************************************
+  uint_least8_t parity(uint32_t value)
+  {
+    value ^= value >> 16;
+    value ^= value >> 8;
+    value ^= value >> 4;
+    value &= 0x0F;
+    return (0x6996 >> value) & 1;
+  }
+
+  //***************************************************************************
+  /// Parity. 64bits. 0 = even, 1 = odd
+  //***************************************************************************
+  uint_least8_t parity(uint64_t value)
+  {
+    value ^= value >> 32;
+    value ^= value >> 16;
+    value ^= value >> 8;
+    value ^= value >> 4;
+    value &= 0x0F;
+    return (0x69966996 >> value) & 1;
+  }
+
+#if ETL_8BIT_SUPPORT
+  //***************************************************************************
+  /// Count trailing zeros. bit.
+  /// Uses a binary search.
+  //***************************************************************************
+  uint_least8_t count_trailing_zeros(uint8_t value)
+  {
+    uint_least8_t count;
+
+    if (value & 0x1)
+    {
+      count = 0;
+    }
+    else
+    {
+      count = 1;
+
+      if ((value & 0xF) == 0)
+      {
+        value >>= 4;
+        count += 4;
+      }
+
+      if ((value & 0x3) == 0)
+      {
+        value >>= 2;
+        count += 2;
+      }
+
+      count -= value & 0x1;
+    }
+
+    return count;
+  }
+#endif
+
+  //***************************************************************************
+  /// Count trailing zeros. 16bit.
+  /// Uses a binary search.
+  //***************************************************************************
+  uint_least8_t count_trailing_zeros(uint16_t value)
+  {
+    uint_least8_t count;
+
+    if (value & 0x1)
+    {
+      count = 0;
+    }
+    else
+    {
+      count = 1;
+
+      if ((value & 0xFF) == 0)
+      {
+        value >>= 8;
+        count += 8;
+      }
+
+      if ((value & 0xF) == 0)
+      {
+        value >>= 4;
+        count += 4;
+      }
+
+      if ((value & 0x3) == 0)
+      {
+        value >>= 2;
+        count += 2;
+      }
+
+      count -= value & 0x1;
+    }
+
+    return count;
+  }
+
+  //***************************************************************************
+  /// Count trailing zeros. 32bit.
+  /// Uses a binary search.
+  //***************************************************************************
+  uint_least8_t count_trailing_zeros(uint32_t value)
+  {
+    uint_least8_t count;
+
+    if (value & 0x1)
+    {
+      count = 0;
+    }
+    else
+    {
+      count = 1;
+
+      if ((value & 0xFFFF) == 0)
+      {
+        value >>= 16;
+        count += 16;
+      }
+
+      if ((value & 0xFF) == 0)
+      {
+        value >>= 8;
+        count += 8;
+      }
+
+      if ((value & 0xF) == 0)
+      {
+        value >>= 4;
+        count += 4;
+      }
+
+      if ((value & 0x3) == 0)
+      {
+        value >>= 2;
+        count += 2;
+      }
+
+      count -= value & 0x1;
+    }
+
+    return count;
+  }
+
+  //***************************************************************************
+  /// Count trailing zeros. 64bit.
+  /// Uses a binary search.
+  //***************************************************************************
+  uint_least8_t count_trailing_zeros(uint64_t value)
+  {
+      uint_least8_t count;
+
+      if (value & 0x1)
+      {
+        count = 0;
+      }
+      else
+      {
+        count = 1;
+
+        if ((value & 0xFFFFFFFF) == 0)
+        {
+          value >>= 32;
+          count += 32;
+        }
+
+        if ((value & 0xFFFF) == 0)
+        {
+          value >>= 16;
+          count += 16;
+        }
+
+        if ((value & 0xFF) == 0)
+        {
+          value >>= 8;
+          count += 8;
+        }
+
+        if ((value & 0xF) == 0)
+        {
+          value >>= 4;
+          count += 4;
+        }
+
+        if ((value & 0x3) == 0)
+        {
+          value >>= 2;
+          count += 2;
+        }
+
+        count -= value & 0x1;
+      }
+
+      return count;
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/binary.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,726 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+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 __ETL_BINARY__
+#define __ETL_BINARY__
+
+///\defgroup binary binary
+/// Binary utilities
+///\ingroup utilities
+
+#include <limits>
+#include <assert.h>
+
+#include "platform.h"
+#include "type_traits.h"
+#include "integral_limits.h"
+#include "static_assert.h"
+#include "log.h"
+#include "power.h"
+#include "smallest.h"
+#include "platform.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Maximum value that can be contained in N bits.
+  //***************************************************************************
+  /// Definition for non-zero NBITS.
+  template <const size_t NBITS>
+  struct max_value_for_nbits
+  {
+    typedef typename etl::smallest_uint_for_bits<NBITS>::type value_type;
+    static const value_type value = (value_type(1) << (NBITS - 1)) | max_value_for_nbits<NBITS - 1>::value;
+  };
+
+  /// Specialisation for when NBITS == 0.
+  template <>
+  struct max_value_for_nbits<0>
+  {
+      typedef etl::smallest_uint_for_bits<0>::type value_type;
+      static const value_type value = 0;
+  };
+
+  template <const size_t NBITS>
+  const typename max_value_for_nbits<NBITS>::value_type max_value_for_nbits<NBITS>::value;
+
+  //***************************************************************************
+  /// Rotate left.
+  //***************************************************************************
+  template <typename T>
+  T rotate_left(T value)
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+
+    const size_t SHIFT = etl::integral_limits<typename etl::make_unsigned<T>::type>::bits - 1;
+
+    return (value << 1) | (value >> SHIFT);
+  }
+
+  //***************************************************************************
+  /// Rotate left.
+  //***************************************************************************
+  template <typename T>
+  T rotate_left(T value, size_t distance)
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+
+    const size_t BITS = etl::integral_limits<typename etl::make_unsigned<T>::type>::bits;
+    distance %= BITS;
+    const size_t SHIFT = BITS - distance;
+
+    return (value << distance) | (value >> SHIFT);
+  }
+
+  //***************************************************************************
+  /// Rotate right.
+  //***************************************************************************
+  template <typename T>
+  T rotate_right(T value)
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+
+    const size_t SHIFT = etl::integral_limits<typename etl::make_unsigned<T>::type>::bits - 1;
+
+    return (value >> 1) | (value << SHIFT);
+  }
+
+  //***************************************************************************
+  /// Rotate right.
+  //***************************************************************************
+  template <typename T>
+  T rotate_right(T value, size_t distance)
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+
+    const size_t BITS = etl::integral_limits<typename etl::make_unsigned<T>::type>::bits;
+    distance %= BITS;
+    const size_t SHIFT = BITS - distance;
+
+    return (value >> distance) | (value << SHIFT);
+  }
+
+  //***************************************************************************
+  /// Rotate.
+  /// Positive is left, negative is right.
+  //***************************************************************************
+  template <typename T>
+  T rotate(T value, typename etl::make_signed<size_t>::type distance)
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+
+    T result;
+
+    if (distance > 0)
+    {
+      result = rotate_left(value, size_t(distance));
+    }
+    else
+    {
+      result = rotate_right(value, size_t(-distance));
+    }
+
+    return result;
+  }
+
+  //***************************************************************************
+  /// Reverse bits.
+  //***************************************************************************
+#if ETL_8BIT_SUPPORT
+  uint8_t reverse_bits(uint8_t value);
+  inline int8_t reverse_bits(int8_t value) { return int8_t(reverse_bits(uint8_t(value))); }
+#endif
+  uint16_t reverse_bits(uint16_t value);
+  inline int16_t reverse_bits(int16_t value) { return int16_t(reverse_bits(uint16_t(value))); }
+  uint32_t reverse_bits(uint32_t value);
+  inline int32_t reverse_bits(int32_t value) { return int32_t(reverse_bits(uint32_t(value))); }
+  uint64_t reverse_bits(uint64_t value);
+  inline int64_t reverse_bits(int64_t value) { return int64_t(reverse_bits(uint64_t(value))); }
+
+  //***************************************************************************
+  /// Reverse bytes.
+  //***************************************************************************
+#if ETL_8BIT_SUPPORT
+  inline uint8_t reverse_bytes(uint8_t value) { return value; }
+  inline int8_t reverse_bytes(int8_t value) { return value; }
+#endif
+  uint16_t reverse_bytes(uint16_t value);
+  inline int16_t reverse_bytes(int16_t value) { return int16_t(reverse_bytes(uint16_t(value))); }
+  uint32_t reverse_bytes(uint32_t value);
+  inline int32_t reverse_bytes(int32_t value) { return int32_t(reverse_bytes(uint32_t(value))); }
+  uint64_t reverse_bytes(uint64_t value);
+  inline int64_t reverse_bytes(int64_t value) { return int64_t(reverse_bytes(uint64_t(value))); }
+
+  //***************************************************************************
+  /// Converts binary to Gray code.
+  //***************************************************************************
+  template <typename T>
+  T binary_to_gray(T value)
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+
+    return (value >> 1) ^ value;
+  }
+
+  //***************************************************************************
+  /// Converts Gray code to binary.
+  //***************************************************************************
+#if ETL_8BIT_SUPPORT
+  uint8_t gray_to_binary(uint8_t value);
+  inline int8_t gray_to_binary(int8_t value) { return int8_t(gray_to_binary(uint8_t(value))); }
+#endif
+  uint16_t gray_to_binary(uint16_t value);
+  inline int16_t gray_to_binary(int16_t value) { return int16_t(gray_to_binary(uint16_t(value))); }
+  uint32_t gray_to_binary(uint32_t value);
+  inline int32_t gray_to_binary(int32_t value) { return int32_t(gray_to_binary(uint32_t(value))); }
+  uint64_t gray_to_binary(uint64_t value);
+  inline int64_t gray_to_binary(int64_t value) { return int64_t(gray_to_binary(uint64_t(value))); }
+
+  //***************************************************************************
+  /// Count set bits.
+  //***************************************************************************
+#if ETL_8BIT_SUPPORT
+  uint_least8_t count_bits(uint8_t value);
+  inline uint_least8_t count_bits(int8_t value) { return count_bits(uint8_t(value)); }
+#endif
+  uint_least8_t count_bits(uint16_t value);
+  inline uint_least8_t count_bits(int16_t value) { return count_bits(uint16_t(value)); }
+  uint_least8_t count_bits(uint32_t value);
+  inline uint_least8_t count_bits(int32_t value) { return count_bits(uint32_t(value)); }
+  uint_least8_t count_bits(uint64_t value);
+  inline uint_least8_t count_bits(int64_t value) { return count_bits(uint64_t(value)); }
+
+  //***************************************************************************
+  /// Parity. 0 = even, 1 = odd
+  //***************************************************************************
+#if ETL_8BIT_SUPPORT
+  uint_least8_t parity(uint8_t value);
+  inline uint_least8_t parity(int8_t value) { return parity(uint8_t(value)); }
+#endif
+  uint_least8_t parity(uint16_t value);
+  inline uint_least8_t parity(int16_t value) { return parity(uint16_t(value)); }
+  uint_least8_t parity(uint32_t value);
+  inline uint_least8_t parity(int32_t value) { return parity(uint32_t(value)); }
+  uint_least8_t parity(uint64_t value);
+  inline uint_least8_t parity(int64_t value) { return parity(uint64_t(value)); }
+
+  //***************************************************************************
+  /// Fold a binary number down to a set number of bits using XOR.
+  //***************************************************************************
+  template <typename TReturn, const size_t NBITS, typename TValue>
+  TReturn fold_bits(TValue value)
+  {
+    STATIC_ASSERT(integral_limits<TReturn>::bits >= NBITS, "Return type too small to hold result");
+
+    const TValue mask  = etl::power<2, NBITS>::value - 1;
+    const size_t shift = NBITS;
+
+    // Fold the value down to fit the width.
+    TReturn folded_value = 0;
+
+    // Keep shifting down and XORing the lower bits.
+    while (value >= etl::max_value_for_nbits<NBITS>::value)
+    {
+      folded_value ^= value & mask;
+      value >>= shift;
+    }
+
+    // Fold the remaining bits.
+    folded_value ^= value & mask;
+
+    return folded_value;
+  }
+
+  //***************************************************************************
+  /// Sign extend.
+  /// Converts an N bit binary number, where bit N-1 is the sign bit, to a signed integral type.
+  //***************************************************************************
+  template <typename TReturn, const size_t NBITS, typename TValue>
+  TReturn sign_extend(TValue value)
+  {
+    STATIC_ASSERT(etl::is_integral<TValue>::value,  "TValue not an integral type");
+    STATIC_ASSERT(etl::is_integral<TReturn>::value, "TReturn not an integral type");
+    STATIC_ASSERT(etl::is_signed<TReturn>::value,   "TReturn not a signed type");
+    STATIC_ASSERT(NBITS <= std::numeric_limits<TReturn>::digits, "NBITS too large for return type");
+
+    const TReturn negative = (TReturn(1) << (NBITS - 1));
+    TReturn signed_value = value & ((1 << NBITS) - 1);
+
+    if ((signed_value & negative) != 0)
+    {
+      const TReturn sign_bits = ~((TReturn(1) << NBITS) - 1);
+      signed_value |= sign_bits;
+    }
+
+    return signed_value;
+  }
+
+  //***************************************************************************
+  /// Sign extend.
+  /// Converts an N bit binary number, where bit N-1 is the sign bit, and SHIFT
+  /// is the right shift amount, to a signed integral type.
+  //***************************************************************************
+  template <typename TReturn, const size_t NBITS, const size_t SHIFT, typename TValue>
+  TReturn sign_extend(TValue value)
+  {
+    STATIC_ASSERT(etl::is_integral<TValue>::value, "TValue not an integral type");
+    STATIC_ASSERT(etl::is_integral<TReturn>::value, "TReturn not an integral type");
+    STATIC_ASSERT(etl::is_signed<TReturn>::value, "TReturn not a signed type");
+    STATIC_ASSERT(NBITS <= std::numeric_limits<TReturn>::digits, "NBITS too large for return type");
+    STATIC_ASSERT(SHIFT <= std::numeric_limits<TReturn>::digits, "SHIFT too large");
+
+    const TReturn negative = (TReturn(1) << (NBITS - 1));
+    TReturn signed_value = (value >> SHIFT) & ((1 << NBITS) - 1);
+
+    if ((signed_value & negative) != 0)
+    {
+      const TReturn sign_bits = ~((TReturn(1) << NBITS) - 1);
+      signed_value |= sign_bits;
+    }
+
+    return signed_value;
+  }
+
+  //***************************************************************************
+  /// Sign extend.
+  /// Converts an N bit binary number, where bit N-1 is the sign bit, to a signed integral type.
+  //***************************************************************************
+  template <typename TReturn, typename TValue>
+  TReturn sign_extend(TValue value, const size_t NBITS)
+  {
+    STATIC_ASSERT(etl::is_integral<TValue>::value,  "TValue not an integral type");
+    STATIC_ASSERT(etl::is_integral<TReturn>::value, "TReturn not an integral type");
+    STATIC_ASSERT(etl::is_signed<TReturn>::value,   "TReturn not a signed type");
+    assert(NBITS <= std::numeric_limits<TReturn>::digits);
+
+    const TReturn negative = (TReturn(1) << (NBITS - 1));
+    TReturn signed_value = value & ((1 << NBITS) - 1);
+
+    if ((signed_value & negative) != 0)
+    {
+      const TReturn sign_bits = ~((TReturn(1) << NBITS) - 1);
+      signed_value |= sign_bits;
+    }
+
+    return signed_value;
+  }
+
+  //***************************************************************************
+  /// Sign extend.
+  /// Converts an N bit binary number, where bit N-1 is the sign bit, and SHIFT
+  /// is the right shift amount, to a signed integral type.
+  //***************************************************************************
+  template <typename TReturn, typename TValue>
+  TReturn sign_extend(TValue value, const size_t NBITS, const size_t SHIFT)
+  {
+    STATIC_ASSERT(etl::is_integral<TValue>::value, "TValue not an integral type");
+    STATIC_ASSERT(etl::is_integral<TReturn>::value, "TReturn not an integral type");
+    STATIC_ASSERT(etl::is_signed<TReturn>::value, "TReturn not a signed type");
+    assert(NBITS <= std::numeric_limits<TReturn>::digits);
+
+    const TReturn negative = (TReturn(1) << (NBITS - 1));
+    TReturn signed_value = (value >> SHIFT) & ((1 << NBITS) - 1);
+
+    if ((signed_value & negative) != 0)
+    {
+      const TReturn sign_bits = ~((TReturn(1) << NBITS) - 1);
+      signed_value |= sign_bits;
+    }
+
+    return signed_value;
+  }
+
+  //***************************************************************************
+  /// Count trailing zeros. bit.
+  /// Uses a binary search.
+  //***************************************************************************
+#if ETL_8BIT_SUPPORT
+  uint_least8_t count_trailing_zeros(uint8_t value);
+  inline uint_least8_t count_trailing_zeros(int8_t value) { return count_trailing_zeros(uint8_t(value)); }
+#endif
+  uint_least8_t count_trailing_zeros(uint16_t value);
+  inline uint_least8_t count_trailing_zeros(int16_t value) { return count_trailing_zeros(uint16_t(value)); }
+  uint_least8_t count_trailing_zeros(uint32_t value);
+  inline uint_least8_t count_trailing_zeros(int32_t value) { return count_trailing_zeros(uint32_t(value)); }
+  uint_least8_t count_trailing_zeros(uint64_t value);
+  inline uint_least8_t count_trailing_zeros(int64_t value) { return count_trailing_zeros(uint64_t(value)); }
+
+  //***************************************************************************
+  /// Find the position of the first set bit.
+  /// Starts from LSB.
+  //***************************************************************************
+  template <typename T>
+  uint_least8_t first_set_bit_position(T value)
+  {
+    return count_trailing_zeros(value);
+  }
+
+  //***************************************************************************
+  /// Find the position of the first clear bit.
+  /// Starts from LSB.
+  //***************************************************************************
+  template <typename T>
+  uint_least8_t first_clear_bit_position(T value)
+  {
+    value = ~value;
+    return count_trailing_zeros(value);
+  }
+
+  //***************************************************************************
+  /// Find the position of the first bit that is clear or set.
+  /// Starts from LSB.
+  //***************************************************************************
+  template <typename T>
+  uint_least8_t first_bit_position(bool state, T value)
+  {
+    if (!state)
+    {
+      value = ~value;
+    }
+
+    return count_trailing_zeros(value);
+  }
+
+  //***************************************************************************
+  /// Gets the value of the bit at POSITION
+  /// Starts from LSB.
+  //***************************************************************************
+  template <const size_t POSITION>
+  struct bit
+  {
+    typedef typename etl::smallest_uint_for_bits<POSITION + 1>::type value_type;
+    static const value_type value = value_type(1) << POSITION;
+  };
+
+  template <const size_t POSITION>
+  const typename bit<POSITION>::value_type bit<POSITION>::value;
+
+  //***************************************************************************
+  /// 8 bit binary constants.
+  //***************************************************************************
+  enum binary_constant
+  {
+    b00000000 = 0,
+    b00000001 = 1,
+    b00000010 = 2,
+    b00000011 = 3,
+    b00000100 = 4,
+    b00000101 = 5,
+    b00000110 = 6,
+    b00000111 = 7,
+    b00001000 = 8,
+    b00001001 = 9,
+    b00001010 = 10,
+    b00001011 = 11,
+    b00001100 = 12,
+    b00001101 = 13,
+    b00001110 = 14,
+    b00001111 = 15,
+    b00010000 = 16,
+    b00010001 = 17,
+    b00010010 = 18,
+    b00010011 = 19,
+    b00010100 = 20,
+    b00010101 = 21,
+    b00010110 = 22,
+    b00010111 = 23,
+    b00011000 = 24,
+    b00011001 = 25,
+    b00011010 = 26,
+    b00011011 = 27,
+    b00011100 = 28,
+    b00011101 = 29,
+    b00011110 = 30,
+    b00011111 = 31,
+    b00100000 = 32,
+    b00100001 = 33,
+    b00100010 = 34,
+    b00100011 = 35,
+    b00100100 = 36,
+    b00100101 = 37,
+    b00100110 = 38,
+    b00100111 = 39,
+    b00101000 = 40,
+    b00101001 = 41,
+    b00101010 = 42,
+    b00101011 = 43,
+    b00101100 = 44,
+    b00101101 = 45,
+    b00101110 = 46,
+    b00101111 = 47,
+    b00110000 = 48,
+    b00110001 = 49,
+    b00110010 = 50,
+    b00110011 = 51,
+    b00110100 = 52,
+    b00110101 = 53,
+    b00110110 = 54,
+    b00110111 = 55,
+    b00111000 = 56,
+    b00111001 = 57,
+    b00111010 = 58,
+    b00111011 = 59,
+    b00111100 = 60,
+    b00111101 = 61,
+    b00111110 = 62,
+    b00111111 = 63,
+    b01000000 = 64,
+    b01000001 = 65,
+    b01000010 = 66,
+    b01000011 = 67,
+    b01000100 = 68,
+    b01000101 = 69,
+    b01000110 = 70,
+    b01000111 = 71,
+    b01001000 = 72,
+    b01001001 = 73,
+    b01001010 = 74,
+    b01001011 = 75,
+    b01001100 = 76,
+    b01001101 = 77,
+    b01001110 = 78,
+    b01001111 = 79,
+    b01010000 = 80,
+    b01010001 = 81,
+    b01010010 = 82,
+    b01010011 = 83,
+    b01010100 = 84,
+    b01010101 = 85,
+    b01010110 = 86,
+    b01010111 = 87,
+    b01011000 = 88,
+    b01011001 = 89,
+    b01011010 = 90,
+    b01011011 = 91,
+    b01011100 = 92,
+    b01011101 = 93,
+    b01011110 = 94,
+    b01011111 = 95,
+    b01100000 = 96,
+    b01100001 = 97,
+    b01100010 = 98,
+    b01100011 = 99,
+    b01100100 = 100,
+    b01100101 = 101,
+    b01100110 = 102,
+    b01100111 = 103,
+    b01101000 = 104,
+    b01101001 = 105,
+    b01101010 = 106,
+    b01101011 = 107,
+    b01101100 = 108,
+    b01101101 = 109,
+    b01101110 = 110,
+    b01101111 = 111,
+    b01110000 = 112,
+    b01110001 = 113,
+    b01110010 = 114,
+    b01110011 = 115,
+    b01110100 = 116,
+    b01110101 = 117,
+    b01110110 = 118,
+    b01110111 = 119,
+    b01111000 = 120,
+    b01111001 = 121,
+    b01111010 = 122,
+    b01111011 = 123,
+    b01111100 = 124,
+    b01111101 = 125,
+    b01111110 = 126,
+    b01111111 = 127,
+    b10000000 = 128,
+    b10000001 = 129,
+    b10000010 = 130,
+    b10000011 = 131,
+    b10000100 = 132,
+    b10000101 = 133,
+    b10000110 = 134,
+    b10000111 = 135,
+    b10001000 = 136,
+    b10001001 = 137,
+    b10001010 = 138,
+    b10001011 = 139,
+    b10001100 = 140,
+    b10001101 = 141,
+    b10001110 = 142,
+    b10001111 = 143,
+    b10010000 = 144,
+    b10010001 = 145,
+    b10010010 = 146,
+    b10010011 = 147,
+    b10010100 = 148,
+    b10010101 = 149,
+    b10010110 = 150,
+    b10010111 = 151,
+    b10011000 = 152,
+    b10011001 = 153,
+    b10011010 = 154,
+    b10011011 = 155,
+    b10011100 = 156,
+    b10011101 = 157,
+    b10011110 = 158,
+    b10011111 = 159,
+    b10100000 = 160,
+    b10100001 = 161,
+    b10100010 = 162,
+    b10100011 = 163,
+    b10100100 = 164,
+    b10100101 = 165,
+    b10100110 = 166,
+    b10100111 = 167,
+    b10101000 = 168,
+    b10101001 = 169,
+    b10101010 = 170,
+    b10101011 = 171,
+    b10101100 = 172,
+    b10101101 = 173,
+    b10101110 = 174,
+    b10101111 = 175,
+    b10110000 = 176,
+    b10110001 = 177,
+    b10110010 = 178,
+    b10110011 = 179,
+    b10110100 = 180,
+    b10110101 = 181,
+    b10110110 = 182,
+    b10110111 = 183,
+    b10111000 = 184,
+    b10111001 = 185,
+    b10111010 = 186,
+    b10111011 = 187,
+    b10111100 = 188,
+    b10111101 = 189,
+    b10111110 = 190,
+    b10111111 = 191,
+    b11000000 = 192,
+    b11000001 = 193,
+    b11000010 = 194,
+    b11000011 = 195,
+    b11000100 = 196,
+    b11000101 = 197,
+    b11000110 = 198,
+    b11000111 = 199,
+    b11001000 = 200,
+    b11001001 = 201,
+    b11001010 = 202,
+    b11001011 = 203,
+    b11001100 = 204,
+    b11001101 = 205,
+    b11001110 = 206,
+    b11001111 = 207,
+    b11010000 = 208,
+    b11010001 = 209,
+    b11010010 = 210,
+    b11010011 = 211,
+    b11010100 = 212,
+    b11010101 = 213,
+    b11010110 = 214,
+    b11010111 = 215,
+    b11011000 = 216,
+    b11011001 = 217,
+    b11011010 = 218,
+    b11011011 = 219,
+    b11011100 = 220,
+    b11011101 = 221,
+    b11011110 = 222,
+    b11011111 = 223,
+    b11100000 = 224,
+    b11100001 = 225,
+    b11100010 = 226,
+    b11100011 = 227,
+    b11100100 = 228,
+    b11100101 = 229,
+    b11100110 = 230,
+    b11100111 = 231,
+    b11101000 = 232,
+    b11101001 = 233,
+    b11101010 = 234,
+    b11101011 = 235,
+    b11101100 = 236,
+    b11101101 = 237,
+    b11101110 = 238,
+    b11101111 = 239,
+    b11110000 = 240,
+    b11110001 = 241,
+    b11110010 = 242,
+    b11110011 = 243,
+    b11110100 = 244,
+    b11110101 = 245,
+    b11110110 = 246,
+    b11110111 = 247,
+    b11111000 = 248,
+    b11111001 = 249,
+    b11111010 = 250,
+    b11111011 = 251,
+    b11111100 = 252,
+    b11111101 = 253,
+    b11111110 = 254,
+    b11111111 = 255
+  };
+
+  enum bit_constant
+  {
+    b0  = 0x1,
+    b1  = 0x2,
+    b2  = 0x4,
+    b3  = 0x8,
+    b4  = 0x10,
+    b5  = 0x20,
+    b6  = 0x40,
+    b7  = 0x80,
+    b8  = 0x100,
+    b9  = 0x200,
+    b10 = 0x400,
+    b11 = 0x800,
+    b12 = 0x1000,
+    b13 = 0x2000,
+    b14 = 0x4000,
+    b15 = 0x8000,
+    b16 = 0x10000,
+    b17 = 0x20000,
+    b18 = 0x40000,
+    b19 = 0x80000,
+    b20 = 0x100000,
+    b21 = 0x200000,
+    b22 = 0x400000,
+    b23 = 0x800000,
+    b24 = 0x1000000,
+    b25 = 0x2000000,
+    b26 = 0x4000000,
+    b27 = 0x8000000,
+    b28 = 0x10000000,
+    b29 = 0x20000000,
+    b30 = 0x40000000,
+    b31 = 0x80000000
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bitset.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1011 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_BITSET__
+#define __ETL_BITSET__
+
+#include <algorithm>
+#include <iterator>
+#include <string.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "platform.h"
+#include "integral_limits.h"
+#include "algorithm.h"
+#include "nullptr.h"
+#include "log.h"
+#include "exception.h"
+#include "integral_limits.h"
+#include "binary.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#include "error_handler.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+//*****************************************************************************
+///\defgroup bitset bitset
+/// Similar to std::bitset but without requiring std::string.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception base for bitset
+  ///\ingroup bitset
+  //***************************************************************************
+  class bitset_exception : public etl::exception
+  {
+  public:
+
+    bitset_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Bitset nullptr exception.
+  ///\ingroup bitset
+  //***************************************************************************
+  class bitset_nullptr : public bitset_exception
+  {
+  public:
+
+    bitset_nullptr(string_type file_name_, numeric_type line_number_)
+      : bitset_exception("bitset: nullptr", file_name_, line_number_)
+    {
+    }
+  };
+
+  //*************************************************************************
+  /// The base class for etl::bitset
+  ///\ingroup bitset
+  //*************************************************************************
+  class ibitset
+  {
+  protected:
+
+    // The type used for each element in the array.
+#if !defined(ETL_BITSET_ELEMENT_TYPE)
+    typedef uint_least8_t element_t;
+#else
+    typedef ETL_BITSET_ELEMENT_TYPE element_t;
+#endif
+
+  public:
+
+    static const element_t ALL_SET = etl::integral_limits<element_t>::max;
+    static const element_t ALL_CLEAR = 0;
+
+    static const size_t    BITS_PER_ELEMENT = etl::integral_limits<element_t>::bits;
+
+    enum
+    {
+      npos = etl::integral_limits<size_t>::max
+    };
+
+    //*************************************************************************
+    /// The reference type returned.
+    //*************************************************************************
+    class bit_reference
+    {
+    public:
+
+      friend class ibitset;
+
+      //*******************************
+      /// Conversion operator.
+      //*******************************
+      operator bool() const
+      {
+        return p_bitset->test(position);
+      }
+
+      //*******************************
+      /// Assignment operator.
+      //*******************************
+      bit_reference& operator = (bool b)
+      {
+        p_bitset->set(position, b);
+        return *this;
+      }
+
+      //*******************************
+      /// Assignment operator.
+      //*******************************
+      bit_reference& operator = (const bit_reference& r)
+      {
+        p_bitset->set(position, bool(r));
+        return *this;
+      }
+
+      //*******************************
+      /// Flip the bit.
+      //*******************************
+      bit_reference& flip()
+      {
+        p_bitset->flip(position);
+        return *this;
+      }
+
+      //*******************************
+      /// Return the logical inverse of the bit.
+      //*******************************
+      bool operator~() const
+      {
+        return !p_bitset->test(position);
+      }
+
+    private:
+
+      //*******************************
+      /// Default constructor.
+      //*******************************
+      bit_reference()
+        : p_bitset(std::nullptr),
+        position(0)
+      {
+      }
+
+      //*******************************
+      /// Constructor.
+      //*******************************
+      bit_reference(ibitset& r_bitset, size_t position_)
+        : p_bitset(&r_bitset),
+        position(position_)
+      {
+      }
+
+      ibitset* p_bitset; ///< The bitset.
+      size_t   position; ///< The position in the bitset.
+    };
+
+    //*************************************************************************
+    /// The size of the bitset.
+    //*************************************************************************
+    size_t size() const
+    {
+      return NBITS;
+    }
+
+    //*************************************************************************
+    /// Count the number of bits set.
+    //*************************************************************************
+    size_t count() const
+    {
+      size_t n = 0;
+
+      for (size_t i = 0; i < SIZE; ++i)
+      {
+        n += etl::count_bits(pdata[i]);
+      }
+
+      return n;
+    }
+
+    //*************************************************************************
+    /// Tests a bit at a position.
+    /// Positions greater than the number of configured bits will return <b>false</b>.
+    //*************************************************************************
+    bool test(size_t position) const
+    {
+      size_t       index;
+      element_t mask;
+
+      if (SIZE == 1)
+      {
+        index = 0;
+        mask = element_t(1) << position;
+      }
+      else
+      {
+        index = position >> etl::log2<BITS_PER_ELEMENT>::value;
+        mask = element_t(1) << (position & (BITS_PER_ELEMENT - 1));
+      }
+
+      return (pdata[index] & mask) != 0;
+    }
+
+    //*************************************************************************
+    /// Set the bit at the position.
+    //*************************************************************************
+    ibitset& set()
+    {
+      for (size_t i = 0; i < SIZE; ++i)
+      {
+        pdata[i] = ALL_SET;
+      }
+
+      pdata[SIZE - 1] &= TOP_MASK;
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Set the bit at the position.
+    //*************************************************************************
+    ibitset& set(size_t position, bool value = true)
+    {
+      size_t    index;
+      element_t bit;
+
+      if (SIZE == 1)
+      {
+        index = 0;
+        bit = element_t(1) << position;
+      }
+      else
+      {
+        index = position >> etl::log2<BITS_PER_ELEMENT>::value;
+        bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1));
+      }
+
+      if (value)
+      {
+        pdata[index] |= bit;
+      }
+      else
+      {
+        pdata[index] &= ~bit;
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Set from a string.
+    //*************************************************************************
+    ibitset& set(const char* text)
+    {
+      reset();
+
+      size_t i = std::min(NBITS, strlen(text));
+
+      while (i > 0)
+      {
+        set(--i, *text++ == '1');
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Resets the bitset.
+    //*************************************************************************
+    ibitset& reset()
+    {
+      for (size_t i = 0; i < SIZE; ++i)
+      {
+        pdata[i] = ALL_CLEAR;
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Reset the bit at the position.
+    //*************************************************************************
+    ibitset& reset(size_t position)
+    {
+      size_t       index;
+      element_t bit;
+
+      if (SIZE == 1)
+      {
+        index = 0;
+        bit = element_t(1) << position;
+      }
+      else
+      {
+        index = position >> etl::log2<BITS_PER_ELEMENT>::value;
+        bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1));
+      }
+
+      pdata[index] &= ~bit;
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Flip all of the bits.
+    //*************************************************************************
+    ibitset& flip()
+    {
+      for (size_t i = 0; i < SIZE; ++i)
+      {
+        pdata[i] = ~pdata[i];
+      }
+
+      pdata[SIZE - 1] &= TOP_MASK;
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Flip the bit at the position.
+    //*************************************************************************
+    ibitset& flip(size_t position)
+    {
+      if (position < NBITS)
+      {
+        size_t    index;
+        element_t bit;
+
+        if (SIZE == 1)
+        {
+          index = 0;
+          bit = element_t(1) << position;
+        }
+        else
+        {
+          index = position >> log2<BITS_PER_ELEMENT>::value;
+          bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1));
+        }
+
+        pdata[index] ^= bit;
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    // Are all the bits sets?
+    //*************************************************************************
+    bool all() const
+    {
+      // All but the last.
+      for (size_t i = 0; i < (SIZE - 1); ++i)
+      {
+        if (pdata[i] != ALL_SET)
+        {
+          return false;
+        }
+      }
+
+      // The last.
+      if (pdata[SIZE - 1] != (ALL_SET & TOP_MASK))
+      {
+        return false;
+      }
+
+      return true;
+    }
+
+    //*************************************************************************
+    /// Are any of the bits set?
+    //*************************************************************************
+    bool any() const
+    {
+      return !none();
+    }
+
+    //*************************************************************************
+    /// Are none of the bits set?
+    //*************************************************************************
+    bool none() const
+    {
+      for (size_t i = 0; i < SIZE; ++i)
+      {
+        if (pdata[i] != 0)
+        {
+          return false;
+        }
+      }
+
+      return true;
+    }
+
+    //*************************************************************************
+    /// Finds the first bit in the specified state.
+    ///\param state The state to search for.
+    ///\returns The position of the bit or SIZE if none were found.
+    //*************************************************************************
+    size_t find_first(bool state) const
+    {
+      return find_next(state, 0);
+    }
+
+    //*************************************************************************
+    /// Finds the next bit in the specified state.
+    ///\param state    The state to search for.
+    ///\param position The position to start from.
+    ///\returns The position of the bit or SIZE if none were found.
+    //*************************************************************************
+    size_t find_next(bool state, size_t position) const
+    {
+      // Where to start.
+      size_t index;
+      size_t bit;
+
+      if (SIZE == 1)
+      {
+        index = 0;
+        bit = position;
+      }
+      else
+      {
+        index = position >> log2<BITS_PER_ELEMENT>::value;
+        bit = position & (BITS_PER_ELEMENT - 1);
+      }
+
+      element_t mask = 1 << bit;
+
+      // For each element in the bitset...
+      while (index < SIZE)
+      {
+        element_t value = pdata[index];
+
+        // Needs checking?
+        if ((state && (value != ALL_CLEAR)) ||
+          (!state && (value != ALL_SET)))
+        {
+          // For each bit in the element...
+          while ((bit < BITS_PER_ELEMENT) && (position < NBITS))
+          {
+            // Equal to the required state?
+            if (((value & mask) != 0) == state)
+            {
+              return position;
+            }
+
+            // Move on to the next bit.
+            mask <<= 1;
+            ++position;
+            ++bit;
+          }
+        }
+        else
+        {
+          position += BITS_PER_ELEMENT;
+        }
+
+        // Start at the beginning for all other elements.
+        bit = 0;
+        mask = 1;
+
+        ++index;
+      }
+
+      return ibitset::npos;
+    }
+
+    //*************************************************************************
+    /// Read [] operator.
+    //*************************************************************************
+    bool operator[] (size_t position) const
+    {
+      return test(position);
+    }
+
+    //*************************************************************************
+    /// Write [] operator.
+    //*************************************************************************
+    bit_reference operator [] (size_t position)
+    {
+      return bit_reference(*this, position);
+    }
+
+    //*************************************************************************
+    /// operator &=
+    //*************************************************************************
+    ibitset& operator &=(const ibitset& other)
+    {
+      for (size_t i = 0; i < SIZE; ++i)
+      {
+        pdata[i] &= other.pdata[i];
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// operator |=
+    //*************************************************************************
+    ibitset& operator |=(const ibitset& other)
+    {
+      for (size_t i = 0; i < SIZE; ++i)
+      {
+        pdata[i] |= other.pdata[i];
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// operator ^=
+    //*************************************************************************
+    ibitset& operator ^=(const ibitset& other)
+    {
+      for (size_t i = 0; i < SIZE; ++i)
+      {
+        pdata[i] ^= other.pdata[i];
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// operator <<=
+    //*************************************************************************
+    ibitset& operator<<=(size_t shift)
+    {
+      if (SIZE == 1)
+      {
+        pdata[0] <<= shift;
+      }
+      else
+      {
+        size_t source = NBITS - shift - 1;
+        size_t destination = NBITS - 1;
+
+        for (size_t i = 0; i < (NBITS - shift); ++i)
+        {
+          set(destination--, test(source--));
+        }
+
+        for (size_t i = 0; i < shift; ++i)
+        {
+          reset(destination--);
+        }
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// operator >>=
+    //*************************************************************************
+    ibitset& operator>>=(size_t shift)
+    {
+      if (SIZE == 1)
+      {
+        pdata[0] >>= shift;
+      }
+      else
+      {
+        size_t source = shift;
+        size_t destination = 0;
+
+        for (size_t i = 0; i < (NBITS - shift); ++i)
+        {
+          set(destination++, test(source++));
+        }
+
+        for (size_t i = 0; i < shift; ++i)
+        {
+          reset(destination++);
+        }
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// operator =
+    //*************************************************************************
+    ibitset& operator =(const ibitset& other)
+    {
+      if (this != &other)
+      {
+        etl::copy_n(other.pdata, SIZE, pdata);
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// swap
+    //*************************************************************************
+    void swap(ibitset& other)
+    {
+      std::swap_ranges(pdata, pdata + SIZE, other.pdata);
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Initialise from an unsigned long long.
+    //*************************************************************************
+    ibitset& initialise(unsigned long long value)
+    {
+      reset();
+
+      const size_t SHIFT = (integral_limits<unsigned long long>::bits <= (int)BITS_PER_ELEMENT) ? 0 : BITS_PER_ELEMENT;
+
+      // Can we do it in one hit?
+      if (SHIFT == 0)
+      {
+        pdata[0] = element_t(value);
+      }
+      else
+      {
+        size_t i = 0;
+
+        while ((value != 0) && (i < SIZE))
+        {
+          pdata[i++] = value & ALL_SET;
+          value = value >> SHIFT;
+        }
+      }
+
+      pdata[SIZE - 1] &= TOP_MASK;
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Invert
+    //*************************************************************************
+    void invert()
+    {
+      for (size_t i = 0; i < SIZE; ++i)
+      {
+        pdata[i] = ~pdata[i];
+      }
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the specified bit.
+    //*************************************************************************
+    bit_reference get_bit_reference(size_t position)
+    {
+      return bit_reference(*this, position);
+    }
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    ibitset(size_t nbits_, size_t size_, element_t* pdata_)
+      : NBITS(nbits_),
+        SIZE(size_),
+        pdata(pdata_)
+    {
+      size_t allocated_bits = SIZE * BITS_PER_ELEMENT;
+      size_t top_mask_shift = ((BITS_PER_ELEMENT - (allocated_bits - NBITS)) % BITS_PER_ELEMENT);
+      TOP_MASK = element_t(top_mask_shift == 0 ? ALL_SET : ~(ALL_SET << top_mask_shift));
+    }
+
+    //*************************************************************************
+    /// Compare bitsets.
+    //*************************************************************************
+    static bool is_equal(const ibitset& lhs, const ibitset&rhs)
+    {
+      return std::equal(lhs.pdata, lhs.pdata + lhs.SIZE, rhs.pdata);
+    }
+
+    element_t TOP_MASK;
+
+  private:
+
+    // Disable copy construction.
+    ibitset(const ibitset&);
+
+    const size_t NBITS;
+    const size_t SIZE;
+    element_t*   pdata;
+  };
+
+  //*************************************************************************
+  /// The class emulates an array of bool elements, but optimized for space allocation.
+  /// Will accommodate any number of bits.
+  /// Does not use std::string.
+  ///\tparam N The number of bits.
+  ///\ingroup bitset
+  //*************************************************************************
+  template <const size_t MAXN>
+  class bitset : public etl::ibitset
+  {
+
+    static const size_t ARRAY_SIZE = (MAXN % BITS_PER_ELEMENT == 0) ? MAXN / BITS_PER_ELEMENT : MAXN / BITS_PER_ELEMENT + 1;
+
+  public:
+
+    static const size_t ALLOCATED_BITS = ARRAY_SIZE * BITS_PER_ELEMENT;
+
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    bitset()
+      : etl::ibitset(MAXN, ARRAY_SIZE, data)
+    {
+      reset();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    bitset(const bitset<MAXN>& other)
+      : etl::ibitset(MAXN, ARRAY_SIZE, data)
+    {
+      etl::copy_n(other.data, ARRAY_SIZE, data);
+    }
+
+    //*************************************************************************
+    /// Construct from a value.
+    //*************************************************************************
+    bitset(unsigned long long value)
+      : etl::ibitset(MAXN, ARRAY_SIZE, data)
+    {
+      initialise(value);
+    }
+
+    //*************************************************************************
+    /// Construct from a string.
+    //*************************************************************************
+    bitset(const char* text)
+      : etl::ibitset(MAXN, ARRAY_SIZE, data)
+    {
+      set(text);
+    }
+
+    //*************************************************************************
+    /// Set all of the bits.
+    //*************************************************************************
+    bitset<MAXN>& set()
+    {
+      etl::ibitset::set();
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Set the bit at the position.
+    //*************************************************************************
+    bitset<MAXN>& set(size_t position, bool value = true)
+    {
+      etl::ibitset::set(position, value);
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Set from a string.
+    //*************************************************************************
+    bitset<MAXN>& set(const char* text)
+    {
+      ETL_ASSERT(text != 0, ETL_ERROR(bitset_nullptr));
+      etl::ibitset::set(text);
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Reset all of the bits.
+    //*************************************************************************
+    bitset<MAXN>& reset()
+    {
+      ibitset::reset();
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Reset the bit at the position.
+    //*************************************************************************
+    bitset<MAXN>& reset(size_t position)
+    {
+      etl::ibitset::reset(position);
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Flip all of the bits.
+    //*************************************************************************
+    bitset<MAXN>& flip()
+    {
+      ibitset::flip();
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Flip the bit at the position.
+    //*************************************************************************
+    bitset<MAXN>& flip(size_t position)
+    {
+      etl::ibitset::flip(position);
+      return *this;
+    }
+
+    //*************************************************************************
+    /// operator =
+    //*************************************************************************
+    bitset<MAXN>& operator =(const bitset<MAXN>& other)
+    {
+      if (this != &other)
+      {
+        etl::copy_n(other.data, ARRAY_SIZE, data);
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// operator &=
+    //*************************************************************************
+    bitset<MAXN>& operator &=(const bitset<MAXN>& other)
+    {
+      etl::ibitset::operator &=(other);
+      return *this;
+    }
+
+    //*************************************************************************
+    /// operator |=
+    //*************************************************************************
+    bitset<MAXN>& operator |=(const bitset<MAXN>& other)
+    {
+      etl::ibitset::operator |=(other);
+      return *this;
+    }
+
+    //*************************************************************************
+    /// operator ^=
+    //*************************************************************************
+    bitset<MAXN>& operator ^=(const bitset<MAXN>& other)
+    {
+      ibitset::operator ^=(other);
+      return *this;
+    }
+
+    //*************************************************************************
+    /// operator ~
+    //*************************************************************************
+    bitset<MAXN> operator ~() const
+    {
+      etl::bitset<MAXN> temp(*this);
+
+      temp.invert();
+
+      return temp;
+    }
+
+    //*************************************************************************
+    /// operator <<
+    //*************************************************************************
+    bitset<MAXN> operator<<(size_t shift) const
+    {
+      etl::bitset<MAXN> temp(*this);
+
+      temp <<= shift;
+
+      return temp;
+    }
+
+    //*************************************************************************
+    /// operator <<=
+    //*************************************************************************
+    bitset<MAXN>& operator<<=(size_t shift)
+    {
+      etl::ibitset::operator <<=(shift);
+      return *this;
+    }
+
+    //*************************************************************************
+    /// operator >>
+    //*************************************************************************
+    bitset<MAXN> operator>>(size_t shift) const
+    {
+      bitset<MAXN> temp(*this);
+
+      temp >>= shift;
+
+      return temp;
+    }
+
+    //*************************************************************************
+    /// operator >>=
+    //*************************************************************************
+    bitset<MAXN>& operator>>=(size_t shift)
+    {
+      etl::ibitset::operator >>=(shift);
+      return *this;
+    }
+
+    //*************************************************************************
+    /// operator ==
+    //*************************************************************************
+    friend bool operator == (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs)
+    {
+      return etl::ibitset::is_equal(lhs, rhs);
+    }
+
+  private:
+
+    element_t data[ARRAY_SIZE];
+  };
+
+  //***************************************************************************
+  /// operator &
+  ///\ingroup bitset
+  //***************************************************************************
+  template <const size_t MAXN>
+  bitset<MAXN> operator & (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs)
+  {
+    bitset<MAXN> temp(lhs);
+    temp &= rhs;
+    return temp;
+  }
+
+  //***************************************************************************
+  /// operator |
+  ///\ingroup bitset
+  //***************************************************************************
+  template<const size_t MAXN>
+  bitset<MAXN> operator | (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs)
+  {
+    bitset<MAXN> temp(lhs);
+    temp |= rhs;
+    return temp;
+  }
+
+  //***************************************************************************
+  /// operator ^
+  ///\ingroup bitset
+  //***************************************************************************
+  template<const size_t MAXN>
+  bitset<MAXN> operator ^ (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs)
+  {
+    bitset<MAXN> temp(lhs);
+    temp ^= rhs;
+    return temp;
+  }
+
+  //***************************************************************************
+  /// operator !=
+  ///\ingroup bitset
+  //***************************************************************************
+  template<const size_t MAXN>
+  bool operator != (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+}
+
+//*************************************************************************
+/// swap
+//*************************************************************************
+template <const size_t MAXN>
+void swap(etl::bitset<MAXN>& lhs, etl::bitset<MAXN>& rhs)
+{
+  lhs.swap(rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bloom_filter.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,191 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_BLOOM_FILTER__
+#define __ETL_BLOOM_FILTER__
+
+#include "platform.h"
+#include "parameter_type.h"
+#include "bitset.h"
+#include "type_traits.h"
+#include "binary.h"
+#include "log.h"
+#include "power.h"
+
+///\defgroup bloom_filter bloom_filter
+/// A Bloom filter
+///\ingroup containers
+
+namespace etl
+{
+  namespace __private_bloom_filter__
+  {
+    // Placeholder null hash for defaulted template parameters.
+    struct null_hash
+    {
+      template <typename T>
+      size_t operator ()(T)
+      {
+        return 0;
+      }
+    };
+  }
+
+  //***************************************************************************
+  /// An implementation of a bloom filter.
+  /// Allows up to three hashes to be defined.
+  /// Hashes must support the () operator and define 'argument_type'.
+  ///\tparam DESIRED_WIDTH The desired number of hash results that can be stored. Rounded up to best fit the underlying bitset.
+  ///\tparam THash1        The first hash generator class.
+  ///\tparam THash2        The second hash generator class. If omitted, uses the null hash.
+  ///\tparam THash3        The third hash generator class.  If omitted, uses the null hash.
+  /// The hash classes must define <b>argument_type</b>.
+  ///\ingroup bloom_filter
+  //***************************************************************************
+  template <const size_t DESIRED_WIDTH,
+            typename     THash1,
+            typename     THash2 = __private_bloom_filter__::null_hash,
+            typename     THash3 = __private_bloom_filter__::null_hash>
+  class bloom_filter
+  {
+  private:
+
+    typedef typename etl::parameter_type<typename THash1::argument_type>::type parameter_t;
+    typedef __private_bloom_filter__::null_hash null_hash;
+
+  public:
+
+    enum
+    {
+      // Make the most efficient use of the bitset.
+      WIDTH = etl::bitset<DESIRED_WIDTH>::ALLOCATED_BITS
+    };
+
+    //***************************************************************************
+    /// Clears the bloom filter of all entries.
+	  //***************************************************************************
+	  void clear()
+	  {
+	    flags.reset();
+	  }
+
+    //***************************************************************************
+    /// Adds a key to the filter.
+    ///\param key The key to add.
+    //***************************************************************************
+    void add(parameter_t key)
+    {
+      flags.set(get_hash<THash1>(key));
+
+      if (!etl::is_same<THash2, null_hash>::value)
+      {
+        flags.set(get_hash<THash2>(key));
+      }
+
+      if (!etl::is_same<THash3, null_hash>::value)
+      {
+        flags.set(get_hash<THash3>(key));
+      }
+    }
+
+    //***************************************************************************
+    /// Tests a key to see if it exists in the filter.
+    ///\param  key The key to test.
+    ///\return <b>true</b> if the key exists in the filter.
+    //***************************************************************************
+    bool exists(parameter_t key) const
+    {
+      bool exists1 = flags[get_hash<THash1>(key)];
+      bool exists2 = true;
+      bool exists3 = true;
+
+      // Do we have a second hash?
+      if (!etl::is_same<THash2, null_hash>::value)
+      {
+        exists2 = flags[get_hash<THash2>(key)];
+      }
+
+      // Do we have a third hash?
+      if (!etl::is_same<THash3, null_hash>::value)
+      {
+        exists3 = flags[get_hash<THash3>(key)];
+      }
+
+      return exists1 && exists2 && exists3;
+    }
+
+    //***************************************************************************
+    /// Returns the width of the Bloom filter.
+    //***************************************************************************
+    size_t width() const
+    {
+      return WIDTH;
+    }
+
+    //***************************************************************************
+    /// Returns the percentage of usage. Range 0 to 100.
+    //***************************************************************************
+    size_t usage() const
+    {
+      return (100 * count()) / WIDTH;
+    }
+
+    //***************************************************************************
+    /// Returns the number of filter flags set.
+    //***************************************************************************
+    size_t count() const
+    {
+      return flags.count();
+    }
+
+  private:
+
+    //***************************************************************************
+    /// Gets the hash for the key.
+    ///\param  key The key.
+    ///\return The hash value.
+    //***************************************************************************
+    template <typename THash>
+    size_t get_hash(parameter_t key) const
+    {
+      size_t hash = THash()(key);
+
+      // Fold the hash down to fit the width.
+      return fold_bits<size_t, etl::log2<WIDTH>::value>(hash);
+    }
+
+    /// The Bloom filter flags.
+    etl::bitset<WIDTH> flags;
+  };
+}
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/c/ecl_timer.c	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,566 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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.
+******************************************************************************/
+
+#include <stdint.h>
+#include <assert.h>
+
+#include "ecl_timer.h"
+
+//*****************************************************************************
+// Internal timer list
+//*****************************************************************************
+
+static ecl_timer_id_t head;
+static ecl_timer_id_t tail;
+static ecl_timer_id_t current;
+
+static struct ecl_timer_config* ptimers;
+
+static void ecl_timer_list_init(struct ecl_timer_config* const ptimers_)
+{
+  ptimers = ptimers_;
+  head    = ECL_TIMER_NO_TIMER;
+  tail    = ECL_TIMER_NO_TIMER;
+  current = ECL_TIMER_NO_TIMER;
+}
+
+//*******************************
+static struct ecl_timer_config* ecl_timer_list_front()
+{
+  return &ptimers[head];
+}
+
+//*******************************
+static ecl_timer_id_t ecl_timer_list_begin()
+{
+  current = head;
+  return current;
+}
+
+//*******************************
+static ecl_timer_id_t ecl_timer_list_next(ecl_timer_id_t last)
+{
+  current = ptimers[last].next;
+  return current;
+}
+
+//*******************************
+static int ecl_timer_list_empty()
+{
+  return head == ECL_TIMER_NO_TIMER;
+}
+
+//*******************************
+// Inserts the timer at the correct delta position
+//*******************************
+static void ecl_timer_list_insert(ecl_timer_id_t id_)
+{
+  struct ecl_timer_config* ptimer = &ptimers[id_];
+
+  if (head == ECL_TIMER_NO_TIMER)
+  {
+    // No entries yet.
+    head = id_;
+    tail = id_;
+    ptimer->previous = ECL_TIMER_NO_TIMER;
+    ptimer->next     = ECL_TIMER_NO_TIMER;
+  }
+  else
+  {
+    // We already have entries.
+    ecl_timer_id_t test_id = ecl_timer_list_begin();
+
+    while (test_id != ECL_TIMER_NO_TIMER)
+    {
+      struct ecl_timer_config* ptest = &ptimers[test_id];
+
+      // Find the correct place to insert.
+      if (ptimer->delta <= ptest->delta)
+      {
+        if (ptest->id == head)
+        {
+          head = ptimer->id;
+        }
+
+        // Insert before ptest->
+        ptimer->previous = ptest->previous;
+        ptest->previous = ptimer->id;
+        ptimer->next = ptest->id;
+
+        // Adjust the next delta to compensate.
+        ptest->delta -= ptimer->delta;
+
+        if (ptimer->previous != ECL_TIMER_NO_TIMER)
+        {
+          ptimers[ptimer->previous].next = ptimer->id;
+        }
+        break;
+      }
+      else
+      {
+        ptimer->delta -= ptest->delta;
+      }
+
+      test_id = ecl_timer_list_next(test_id);
+    }
+
+    // Reached the end?
+    if (test_id == ECL_TIMER_NO_TIMER)
+    {
+      // Tag on to the tail.
+      ptimers[tail].next = ptimer->id;
+      ptimer->previous   = tail;
+      ptimer->next       = ECL_TIMER_NO_TIMER;
+      tail               = ptimer->id;
+    }
+  }
+}
+
+//*******************************
+static void ecl_timer_list_remove(ecl_timer_id_t id_, int has_expired)
+{
+  struct ecl_timer_config* ptimer = &ptimers[id_];
+
+  if (head == id_)
+  {
+    head = ptimer->next;
+  }
+  else
+  {
+    ptimers[ptimer->previous].next = ptimer->next;
+  }
+
+  if (tail == id_)
+  {
+    tail = ptimer->previous;
+  }
+  else
+  {
+    ptimers[ptimer->next].previous = ptimer->previous;
+  }
+
+  if (!has_expired)
+  {
+    // Adjust the next delta.
+    if (ptimer->next != ECL_TIMER_NO_TIMER)
+    {
+      ptimers[ptimer->next].delta += ptimer->delta;
+    }
+  }
+
+  ptimer->previous = ECL_TIMER_NO_TIMER;
+  ptimer->next     = ECL_TIMER_NO_TIMER;
+  ptimer->delta    = ECL_TIMER_INACTIVE;
+}
+
+//*******************************
+static void ecl_timer_list_clear()
+{
+  ecl_timer_id_t id = ecl_timer_list_begin();
+
+  while (id != ECL_TIMER_NO_TIMER)
+  {
+    struct ecl_timer_config* ptimer = &ptimers[id];
+    id = ecl_timer_list_next(id);
+    ptimer->next = ECL_TIMER_NO_TIMER;
+  }
+
+  head = ECL_TIMER_NO_TIMER;
+  tail = ECL_TIMER_NO_TIMER;
+  current = ECL_TIMER_NO_TIMER;
+}
+
+//*****************************************************************************
+// Timer Framework
+//*****************************************************************************
+
+//*******************************************
+/// Default initialisation.
+//*******************************************
+void ecl_timer_data_init_default(struct ecl_timer_config* ptimer_data_)
+{
+  assert(ptimer_data_ != 0);
+
+  ptimer_data_->pcallback = 0;
+  ptimer_data_->period    = 0;
+  ptimer_data_->delta     = ECL_TIMER_INACTIVE;
+  ptimer_data_->id        = ECL_TIMER_NO_TIMER;
+  ptimer_data_->previous  = ECL_TIMER_NO_TIMER;
+  ptimer_data_->next      = ECL_TIMER_NO_TIMER;
+  ptimer_data_->repeating = ECL_TIMER_REPEATING;
+}
+
+//*******************************************
+/// Parameterised initialisation.
+//*******************************************
+void ecl_timer_data_init(struct ecl_timer_config* ptimer_data_,
+                         ecl_timer_id_t               id_,
+                         void                   (*pcallback_)(),
+                         ecl_timer_time_t             period_,
+                         ecl_timer_mode_t             repeating_)
+{
+  assert(ptimer_data_ != 0);
+  assert(pcallback_   != 0);
+
+  ptimer_data_->pcallback = pcallback_;
+  ptimer_data_->period    = period_;
+  ptimer_data_->delta     = ECL_TIMER_INACTIVE;
+  ptimer_data_->id        = id_;
+  ptimer_data_->previous  = ECL_TIMER_NO_TIMER;
+  ptimer_data_->next      = ECL_TIMER_NO_TIMER;
+  ptimer_data_->repeating = repeating_;
+}
+
+//*******************************************
+/// Returns true if the timer is active.
+//*******************************************
+ecl_timer_result_t ecl_timer_is_active(struct ecl_timer_config* ptimer_data_)
+{
+  assert(ptimer_data_ != 0);
+
+  return (ptimer_data_->delta != ECL_TIMER_INACTIVE) ? ECL_TIMER_PASS : ECL_TIMER_FAIL;
+}
+
+//*******************************************
+/// Sets the timer to the inactive state.
+//*******************************************
+void ecl_set_timer_inactive(struct ecl_timer_config* ptimer_data_)
+{
+  assert(ptimer_data_ != 0);
+
+  ptimer_data_->delta = ECL_TIMER_INACTIVE;
+}
+
+struct ecl_time_config
+{
+  struct ecl_timer_config* ptimers;
+  uint_least8_t max_timers;
+  volatile ecl_timer_enable_t enabled;
+  ECL_TIMER_TIMER_SEMAPHORE process_semaphore;
+  volatile uint_least8_t registered_timers;
+};
+
+static struct ecl_time_config ecl;
+
+void ecl_timer_init(struct ecl_timer_config* ptimers_, uint_least8_t max_timers_)
+{
+  assert(ptimers_ != 0);
+
+  ecl.ptimers           = ptimers_;
+  ecl.max_timers        = max_timers_;
+  ecl.enabled           = 0;
+  ecl.process_semaphore = 0;
+  ecl.registered_timers = 0;
+
+  int i;
+  for (i = 0; i < max_timers_; ++i)
+  {
+    ecl_timer_data_init_default(&ecl.ptimers[i]);
+  }
+
+  ecl_timer_list_init(ecl.ptimers);
+}
+
+//*******************************************
+/// Register a ptimer->
+//*******************************************
+ecl_timer_id_t ecl_timer_register(void             (*pcallback_)(),
+                                  ecl_timer_time_t period_,
+                                  ecl_timer_mode_t repeating_)
+{
+  assert(pcallback_ != 0);
+  assert(ecl.ptimers != 0);
+
+  ecl_timer_id_t id = ECL_TIMER_NO_TIMER;
+
+  ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore);
+
+  int is_space = (ecl.registered_timers < ecl.max_timers);
+
+  if (is_space)
+  {
+    // Search for the free space.
+    uint_least8_t i;
+    for (i = 0; i < ecl.max_timers; ++i)
+    {
+      struct ecl_timer_config* ptimer = &ecl.ptimers[i];
+
+      if (ptimer->id == ECL_TIMER_NO_TIMER)
+      {
+        // Create in-place.
+        ecl_timer_data_init(ptimer, i, pcallback_, period_, repeating_);
+        ++ecl.registered_timers;
+        id = i;
+        break;
+      }
+    }
+  }
+
+  ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore);
+
+  return id;
+}
+
+//*******************************************
+/// Unregister a ptimer->
+//*******************************************
+ecl_timer_result_t ecl_timer_unregister(ecl_timer_id_t id_)
+{
+  assert(ecl.ptimers != 0);
+  
+  ecl_timer_result_t result = ECL_TIMER_FAIL;
+
+  if (id_ != ECL_TIMER_NO_TIMER)
+  {
+    ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore);
+
+    struct ecl_timer_config* ptimer = &ecl.ptimers[id_];
+
+    if (ptimer->id != ECL_TIMER_NO_TIMER)
+    {
+      if (ecl_timer_is_active(ptimer))
+      {
+        ecl_timer_list_remove(ptimer->id, 0);
+
+        // Reset in-place.
+        ecl_timer_data_init_default(ptimer);
+        --ecl.registered_timers;
+
+        result = ECL_TIMER_PASS;
+      }
+    }
+
+    ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore);
+  }
+
+  return result;
+}
+
+//*******************************************
+/// Enable/disable the ptimer->
+//*******************************************
+void ecl_timer_enable(ecl_timer_enable_t state_)
+{
+  assert(ecl.ptimers != 0);
+  assert((state_ == ECL_TIMER_ENABLED) || (state_ == ECL_TIMER_DISABLED));
+
+  ecl.enabled = state_;
+}
+
+//*******************************************
+/// Get the enable/disable state.
+//*******************************************
+ecl_timer_result_t ecl_timer_is_running()
+{
+  return ecl.enabled;
+}
+
+//*******************************************
+/// Clears the timer of data.
+//*******************************************
+void ecl_timer_clear()
+{ 
+  ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore);
+
+  ecl_timer_list_clear();
+
+  int i;
+  for (i = 0; i < ecl.max_timers; ++i)
+  {
+    ecl_timer_data_init_default(&ecl.ptimers[i]);
+  }
+
+  ecl.registered_timers = 0;
+
+  ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore);
+}
+
+//*******************************************
+// Called by the timer service to indicate the
+// amount of time that has elapsed since the last successful call to 'tick'.
+// Returns true if the tick was processed, false if not.
+//*******************************************
+ecl_timer_result_t ecl_timer_tick(uint32_t count)
+{
+  assert(ecl.ptimers != 0);
+  
+  if (ecl.enabled)
+  {
+    if (ECL_TIMER_PROCESSING_ENABLED(ecl.process_semaphore))
+    {
+      // We have something to do?
+      int has_active = !ecl_timer_list_empty();
+
+      if (has_active)
+      {
+        while (has_active && (count >= ecl_timer_list_front()->delta))
+        {
+          struct ecl_timer_config* ptimer = ecl_timer_list_front();
+
+          count -= ptimer->delta;
+
+          ecl_timer_list_remove(ptimer->id, 1);
+
+          if (ptimer->repeating)
+          {
+            // Reinsert the ptimer->
+            ptimer->delta = ptimer->period;
+            ecl_timer_list_insert(ptimer->id);
+          }
+
+          if (ptimer->pcallback != 0)
+          {
+            // Call the C callback.
+            (ptimer->pcallback)();
+          }
+
+          has_active = !ecl_timer_list_empty();
+        }
+
+        if (has_active)
+        {
+          // Subtract any remainder from the next due timeout.
+          ecl_timer_list_front()->delta -= count;
+        }
+      }
+
+      return ECL_TIMER_PASS;
+    }
+  }
+
+  return ECL_TIMER_FAIL;
+}
+
+//*******************************************
+/// Starts a timer
+//*******************************************
+ecl_timer_result_t ecl_timer_start(ecl_timer_id_t id_, ecl_timer_start_t immediate_)
+{
+  assert(ecl.ptimers != 0);
+  
+  ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore);
+
+  ecl_timer_result_t result = ECL_TIMER_FAIL;
+
+  // Valid timer id?
+  if (id_ != ECL_TIMER_NO_TIMER)
+  {
+    struct ecl_timer_config* ptimer = &ecl.ptimers[id_];
+
+    // Registered timer?
+    if (ptimer->id != ECL_TIMER_NO_TIMER)
+    {
+      // Has a valid period.
+      if (ptimer->period != ECL_TIMER_INACTIVE)
+      {
+        if (ecl_timer_is_active(ptimer))
+        {
+          ecl_timer_list_remove(ptimer->id, 0);
+        }
+
+        ptimer->delta = immediate_ ? 0 : ptimer->period;
+        ecl_timer_list_insert(ptimer->id);
+
+        result = ECL_TIMER_PASS;
+      }
+    }
+  }
+
+  ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore);
+
+  return result;
+}
+
+//*******************************************
+/// Stops a timer
+//*******************************************
+ecl_timer_result_t ecl_timer_stop(ecl_timer_id_t id_)
+{
+  assert(ecl.ptimers != 0);
+  
+  ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore);
+
+  ecl_timer_result_t result = ECL_TIMER_FAIL;
+
+  // Valid timer id?
+  if (id_ != ECL_TIMER_NO_TIMER)
+  {
+    struct ecl_timer_config* ptimer = &ecl.ptimers[id_];
+
+    // Registered timer?
+    if (ptimer->id != ECL_TIMER_NO_TIMER)
+    {
+      if (ecl_timer_is_active(ptimer))
+      {
+        ecl_timer_list_remove(ptimer->id, 0);
+        result = ECL_TIMER_PASS;
+      }
+    }
+  }
+
+  ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore);
+
+  return result;
+}
+
+//*******************************************
+/// Sets a timer's period.
+//*******************************************
+ecl_timer_result_t ecl_timer_set_period(ecl_timer_id_t id_, ecl_timer_time_t period_)
+{
+  assert(ecl.ptimers != 0);
+  
+  if (ecl_timer_stop(id_))
+  {
+    ecl.ptimers[id_].period = period_;
+    return ecl_timer_start(id_, 0);
+  }
+
+  return ECL_TIMER_FAIL;
+}
+
+//*******************************************
+/// Sets a timer's mode.
+//*******************************************
+ecl_timer_result_t ecl_timer_set_mode(ecl_timer_id_t id_, ecl_timer_mode_t repeating_)
+{
+  assert(ecl.ptimers != 0);
+  
+  if (ecl_timer_stop(id_))
+  {
+    ecl.ptimers[id_].repeating = repeating_;
+    return ecl_timer_start(id_, 0);
+  }
+
+  return ECL_TIMER_FAIL;
+}
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/c/ecl_timer.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,119 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_C_TIMER_FRAMEWORK__
+#define __ETL_C_TIMER_FRAMEWORK__
+
+#include <stdint.h>
+
+#include "ecl_user.h"
+
+// Pass/fail results.
+enum
+{
+  ECL_TIMER_FAIL = 0,
+  ECL_TIMER_PASS = 1,
+};
+
+typedef int ecl_timer_result_t;
+
+// Enable states.
+enum
+{
+  ECL_TIMER_DISABLED = ECL_TIMER_FAIL,
+  ECL_TIMER_ENABLED  = ECL_TIMER_PASS
+};
+
+typedef int ecl_timer_enable_t;
+
+// Timer modes.
+enum
+{
+  ECL_TIMER_SINGLE_SHOT = 0,
+  ECL_TIMER_REPEATING   = 1
+};
+
+typedef char ecl_timer_mode_t;
+
+// Timer start action.
+enum
+{
+  ECL_TIMER_START_DELAYED   = 0,
+  ECL_TIMER_START_IMMEDIATE = 1
+};
+
+typedef char ecl_timer_start_t;
+
+// Timer identifiers.
+enum
+{
+  ECL_TIMER_NO_TIMER = 255
+};
+
+typedef uint_least8_t ecl_timer_id_t;
+
+// Timer times.
+#define ECL_TIMER_INACTIVE 0xFFFFFFFF
+
+typedef uint32_t ecl_timer_time_t;
+
+//*************************************************************************
+/// The configuration of a timer.
+//*************************************************************************
+struct ecl_timer_config
+{
+  void             (*pcallback)();
+  ecl_timer_time_t  period;
+  ecl_timer_time_t  delta;
+  ecl_timer_id_t    id;
+  uint_least8_t     previous;
+  uint_least8_t     next;
+  char              repeating;
+};
+
+//*************************************************************************
+/// The API.
+//*************************************************************************
+void ecl_timer_data_init_default(struct ecl_timer_config* ptimer_data_);
+void ecl_timer_data_init(struct ecl_timer_config* ptimer_data_, ecl_timer_id_t id_, void(*pcallback_)(), ecl_timer_time_t period_, ecl_timer_mode_t repeating_);
+ecl_timer_result_t ecl_timer_is_active(struct ecl_timer_config* ptimer_data_);
+void ecl_set_timer_inactive(struct ecl_timer_config* ptimer_data_);
+void ecl_timer_init(struct ecl_timer_config* ptimers_, uint_least8_t max_timers_);
+ecl_timer_id_t ecl_timer_register(void(*pcallback_)(), ecl_timer_time_t period_, ecl_timer_mode_t repeating_);
+ecl_timer_result_t ecl_timer_unregister(ecl_timer_id_t id_);
+void ecl_timer_enable(ecl_timer_enable_t state_);
+ecl_timer_result_t ecl_timer_is_running(void);
+void ecl_timer_clear(void);
+ecl_timer_result_t ecl_timer_tick(uint32_t count);
+ecl_timer_result_t ecl_timer_start(ecl_timer_id_t id_, ecl_timer_start_t immediate_);
+ecl_timer_result_t ecl_timer_stop(ecl_timer_id_t id_);
+ecl_timer_result_t ecl_timer_set_period(ecl_timer_id_t id_, ecl_timer_time_t period_);
+ecl_timer_result_t ecl_timer_set_mode(ecl_timer_id_t id_, ecl_timer_mode_t repeating_);
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/callback.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,81 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+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 __ETL_CALLBACK__
+#define __ETL_CALLBACK__
+
+namespace etl
+{
+  //***************************************************************************
+  /// A callback class designed to be multiply inherited by other client classes.
+  /// The class is parametrised with a callback parameter type and a unique id.
+  /// The unique id allows multiple callbacks with the same parameter type.
+  ///\tparam TParameter The callback parameter type.
+  ///\tparam ID The unique id for this callback.
+  //***************************************************************************
+  template <typename TParameter, const int ID>
+  class callback
+  {
+  private:
+
+    // Creates a parameter type unique to this ID.
+    template <typename T, const int I>
+    struct parameter
+    {
+        parameter(T value)
+            : value(value)
+        {
+        }
+
+        typedef T value_type;
+
+        T value;
+
+    private:
+
+        parameter();
+    };
+
+    // Specialisation for void.
+    template <const int I>
+    struct parameter<void, I>
+    {
+        typedef void value_type;
+    };
+
+  public:
+
+    typedef parameter<TParameter, ID> type;
+
+    virtual void etl_callback(type p = type()) = 0;
+  };
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/callback_timer.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,694 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_CALLBACK_TIMER__
+#define __ETL_CALLBACK_TIMER__
+
+#include <stdint.h>
+#include <algorithm>
+
+#include "platform.h"
+#include "nullptr.h"
+#include "function.h"
+#include "static_assert.h"
+#include "timer.h"
+#include "atomic.h"
+
+#undef ETL_FILE
+#define ETL_FILE "42"
+
+namespace etl
+{
+  //*************************************************************************
+  /// The configuration of a timer.
+  struct callback_timer_data
+  {
+    //*******************************************
+    callback_timer_data()
+      : p_callback(std::nullptr),
+        period(0),
+        delta(etl::timer::state::INACTIVE),
+        id(etl::timer::id::NO_TIMER),
+        previous(etl::timer::id::NO_TIMER),
+        next(etl::timer::id::NO_TIMER),
+        repeating(true),
+        has_c_callback(true)
+    {
+    }
+
+    //*******************************************
+    /// C function callback
+    //*******************************************
+    callback_timer_data(etl::timer::id::type id_,
+                        void                 (*p_callback_)(),
+                        uint32_t             period_,
+                        bool                 repeating_)
+      : p_callback(reinterpret_cast<void*>(p_callback_)),
+        period(period_),
+        delta(etl::timer::state::INACTIVE),
+        id(id_),
+        previous(etl::timer::id::NO_TIMER),
+        next(etl::timer::id::NO_TIMER),
+        repeating(repeating_),
+        has_c_callback(true)
+    {
+    }
+
+    //*******************************************
+    /// ETL function callback
+    //*******************************************
+    callback_timer_data(etl::timer::id::type  id_,
+                        etl::ifunction<void>& callback_,
+                        uint32_t              period_,
+                        bool                  repeating_)
+      : p_callback(reinterpret_cast<void*>(&callback_)),
+        period(period_),
+        delta(etl::timer::state::INACTIVE),
+        id(id_),
+        previous(etl::timer::id::NO_TIMER),
+        next(etl::timer::id::NO_TIMER),
+        repeating(repeating_),
+        has_c_callback(false)
+    {
+    }
+
+    //*******************************************
+    /// Returns true if the timer is active.
+    //*******************************************
+    bool is_active() const
+    {
+      return delta != etl::timer::state::INACTIVE;
+    }
+
+    //*******************************************
+    /// Sets the timer to the inactive state.
+    //*******************************************
+    void set_inactive()
+    {
+      delta = etl::timer::state::INACTIVE;
+    }
+
+    void*                 p_callback;
+    uint32_t              period;
+    uint32_t              delta;
+    etl::timer::id::type  id;
+    uint_least8_t         previous;
+    uint_least8_t         next;
+    bool                  repeating;
+    bool                  has_c_callback;
+
+  private:
+
+    // Disabled.
+    callback_timer_data(const callback_timer_data& other);
+    callback_timer_data& operator =(const callback_timer_data& other);
+  };
+
+  namespace __private_callback_timer__
+  {
+    //*************************************************************************
+    /// A specialised intrusive linked list for timer data.
+    //*************************************************************************
+    class list
+    {
+    public:
+
+      //*******************************
+      list(etl::callback_timer_data* ptimers_)
+        : head(etl::timer::id::NO_TIMER),
+          tail(etl::timer::id::NO_TIMER),
+          current(etl::timer::id::NO_TIMER),
+          ptimers(ptimers_)
+      {
+      }
+
+      //*******************************
+      bool empty() const
+      {
+        return head == etl::timer::id::NO_TIMER;
+      }
+
+      //*******************************
+      // Inserts the timer at the correct delta position
+      //*******************************
+      void insert(etl::timer::id::type id_)
+      {
+        etl::callback_timer_data& timer = ptimers[id_];
+
+        if (head == etl::timer::id::NO_TIMER)
+        {
+          // No entries yet.
+          head = id_;
+          tail = id_;
+          timer.previous = etl::timer::id::NO_TIMER;
+          timer.next     = etl::timer::id::NO_TIMER;
+        }
+        else
+        {
+          // We already have entries.
+          etl::timer::id::type test_id = begin();
+
+          while (test_id != etl::timer::id::NO_TIMER)
+          {
+            etl::callback_timer_data& test = ptimers[test_id];
+
+            // Find the correct place to insert.
+            if (timer.delta <= test.delta)
+            {
+              if (test.id == head)
+              {
+                head = timer.id;
+              }
+
+              // Insert before test.
+              timer.previous = test.previous;
+              test.previous  = timer.id;
+              timer.next     = test.id;
+
+              // Adjust the next delta to compensate.
+              test.delta -= timer.delta;
+
+              if (timer.previous != etl::timer::id::NO_TIMER)
+              {
+                ptimers[timer.previous].next = timer.id;
+              }
+              break;
+            }
+            else
+            {
+              timer.delta -= test.delta;
+            }
+
+            test_id = next(test_id);
+          }
+
+          // Reached the end?
+          if (test_id == etl::timer::id::NO_TIMER)
+          {
+            // Tag on to the tail.
+            ptimers[tail].next = timer.id;
+            timer.previous     = tail;
+            timer.next         = etl::timer::id::NO_TIMER;
+            tail               = timer.id;
+          }
+        }
+      }
+
+      //*******************************
+      void remove(etl::timer::id::type id_, bool has_expired)
+      {
+        etl::callback_timer_data& timer = ptimers[id_];
+
+        if (head == id_)
+        {
+          head = timer.next;
+        }
+        else
+        {
+          ptimers[timer.previous].next = timer.next;
+        }
+
+        if (tail == id_)
+        {
+          tail = timer.previous;
+        }
+        else
+        {
+          ptimers[timer.next].previous = timer.previous;
+        }
+
+        if (!has_expired)
+        {
+          // Adjust the next delta.
+          if (timer.next != etl::timer::id::NO_TIMER)
+          {
+            ptimers[timer.next].delta += timer.delta;
+          }
+        }
+
+        timer.previous = etl::timer::id::NO_TIMER;
+        timer.next     = etl::timer::id::NO_TIMER;
+        timer.delta    = etl::timer::state::INACTIVE;
+      }
+
+      //*******************************
+      etl::callback_timer_data& front()
+      {
+        return ptimers[head];
+      }
+
+      //*******************************
+      etl::timer::id::type begin()
+      {
+        current = head;
+        return current;
+      }
+
+      //*******************************
+      etl::timer::id::type previous(etl::timer::id::type last)
+      {
+        current = ptimers[last].previous;
+        return current;
+      }
+
+      //*******************************
+      etl::timer::id::type next(etl::timer::id::type last)
+      {
+        current = ptimers[last].next;
+        return current;
+      }
+
+      //*******************************
+      void clear()
+      {
+        etl::timer::id::type id = begin();
+
+        while (id != etl::timer::id::NO_TIMER)
+        {
+          etl::callback_timer_data& timer = ptimers[id];
+          id = next(id);
+          timer.next = etl::timer::id::NO_TIMER;
+        }
+
+        head    = etl::timer::id::NO_TIMER;
+        tail    = etl::timer::id::NO_TIMER;
+        current = etl::timer::id::NO_TIMER;
+      }
+
+    private:
+
+      etl::timer::id::type head;
+      etl::timer::id::type tail;
+      etl::timer::id::type current;
+
+      etl::callback_timer_data* const ptimers;
+    };
+  }
+
+  //***************************************************************************
+  /// Interface for callback timer
+  //***************************************************************************
+  class icallback_timer
+  {
+  public:
+
+    //*******************************************
+    /// Register a timer.
+    //*******************************************
+    etl::timer::id::type register_timer(void     (*p_callback_)(),
+                                        uint32_t period_,
+                                        bool     repeating_)
+    {
+      etl::timer::id::type id = etl::timer::id::NO_TIMER;
+
+      disable_timer_updates();
+
+      bool is_space = (registered_timers < MAX_TIMERS);
+
+      if (is_space)
+      {
+        // Search for the free space.
+        for (uint_least8_t i = 0; i < MAX_TIMERS; ++i)
+        {
+          etl::callback_timer_data& timer = timer_array[i];
+
+          if (timer.id == etl::timer::id::NO_TIMER)
+          {
+            // Create in-place.
+            new (&timer) callback_timer_data(i, p_callback_, period_, repeating_);
+            ++registered_timers;
+            id = i;
+            break;
+          }
+        }
+      }
+
+      enable_timer_updates();
+
+      return id;
+    }
+
+    //*******************************************
+    /// Register a timer.
+    //*******************************************
+    etl::timer::id::type register_timer(etl::ifunction<void>& callback_,
+                                        uint32_t              period_,
+                                        bool                  repeating_)
+    {
+      etl::timer::id::type id = etl::timer::id::NO_TIMER;
+
+      disable_timer_updates();
+
+      bool is_space = (registered_timers < MAX_TIMERS);
+
+      if (is_space)
+      {
+        // Search for the free space.
+        for (uint_least8_t i = 0; i < MAX_TIMERS; ++i)
+        {
+          etl::callback_timer_data& timer = timer_array[i];
+
+          if (timer.id == etl::timer::id::NO_TIMER)
+          {
+            // Create in-place.
+            new (&timer) callback_timer_data(i, callback_, period_, repeating_);
+            ++registered_timers;
+            id = i;
+            break;
+          }
+        }
+      }
+
+      enable_timer_updates();
+
+      return id;
+    }
+
+    //*******************************************
+    /// Unregister a timer.
+    //*******************************************
+    bool unregister_timer(etl::timer::id::type id_)
+    {
+      bool result = false;
+
+      if (id_ != etl::timer::id::NO_TIMER)
+      {
+        disable_timer_updates();
+
+        etl::callback_timer_data& timer = timer_array[id_];
+
+        if (timer.id != etl::timer::id::NO_TIMER)
+        {
+          if (timer.is_active())
+          {
+            active_list.remove(timer.id, false);
+
+            // Reset in-place.
+            new (&timer) callback_timer_data();
+            --registered_timers;
+
+            result = true;
+          }
+        }
+
+        enable_timer_updates();
+      }
+
+      return result;
+    }
+
+    //*******************************************
+    /// Enable/disable the timer.
+    //*******************************************
+    void enable(bool state_)
+    {
+      enabled = state_;
+    }
+
+    //*******************************************
+    /// Get the enable/disable state.
+    //*******************************************
+    bool is_running() const
+    {
+      return enabled;
+    }
+
+    //*******************************************
+    /// Clears the timer of data.
+    //*******************************************
+    void clear()
+    {
+      disable_timer_updates();
+
+      active_list.clear();
+
+      for (int i = 0; i < MAX_TIMERS; ++i)
+      {
+        new (&timer_array[i]) callback_timer_data();
+      }
+
+      registered_timers = 0;
+
+      enable_timer_updates();
+    }
+
+    //*******************************************
+    // Called by the timer service to indicate the
+    // amount of time that has elapsed since the last successful call to 'tick'.
+    // Returns true if the tick was processed,
+    // false if not.
+    //*******************************************
+    bool tick(uint32_t count)
+    {
+      if (enabled)
+      {
+        if (process_semaphore.load() == 0)
+        {
+          // We have something to do?
+          bool has_active = !active_list.empty();
+
+          if (has_active)
+          {
+            while (has_active && (count >= active_list.front().delta))
+            {
+              etl::callback_timer_data& timer = active_list.front();
+
+              count -= timer.delta;
+
+              active_list.remove(timer.id, true);
+
+              if (timer.repeating)
+              {
+                // Reinsert the timer.
+                timer.delta = timer.period;
+                active_list.insert(timer.id);
+              }
+
+              if (timer.p_callback != std::nullptr)
+              {
+                if (timer.has_c_callback)
+                {
+                  // Call the C callback.
+                  reinterpret_cast<void(*)()>(timer.p_callback)();
+                }
+                else
+                {
+                  // Call the function wrapper callback.
+                  (*reinterpret_cast<etl::ifunction<void>*>(timer.p_callback))();
+                }
+              }
+
+              has_active = !active_list.empty();
+            }
+
+            if (has_active)
+            {
+              // Subtract any remainder from the next due timeout.
+              active_list.front().delta -= count;
+            }
+          }
+
+          return true;
+        }
+      }
+
+      return false;
+    }
+
+    //*******************************************
+    /// Starts a timer.
+    //*******************************************
+    bool start(etl::timer::id::type id_, bool immediate_ = false)
+    {
+      disable_timer_updates();
+
+      bool result = false;
+
+      // Valid timer id?
+      if (id_ != etl::timer::id::NO_TIMER)
+      {
+        etl::callback_timer_data& timer = timer_array[id_];
+
+        // Registered timer?
+        if (timer.id != etl::timer::id::NO_TIMER)
+        {         
+          // Has a valid period.
+          if (timer.period != etl::timer::state::INACTIVE)
+          {
+            if (timer.is_active())
+            {
+              active_list.remove(timer.id, false);
+            }
+
+            timer.delta = immediate_ ? 0 : timer.period;
+            active_list.insert(timer.id);
+
+            result = true;
+          }                
+        }
+      }
+
+      enable_timer_updates();
+
+      return result;
+    }
+
+    //*******************************************
+    /// Stops a timer.
+    //*******************************************
+    bool stop(etl::timer::id::type id_)
+    {
+      disable_timer_updates();
+
+      bool result = false;
+
+      // Valid timer id?
+      if (id_ != etl::timer::id::NO_TIMER)
+      {
+        etl::callback_timer_data& timer = timer_array[id_];
+
+        // Registered timer?
+        if (timer.id != etl::timer::id::NO_TIMER)
+        {
+          if (timer.is_active())
+          {
+            active_list.remove(timer.id, false);
+            result = true;
+          }
+        }
+      }
+
+      enable_timer_updates();
+
+      return result;
+    }
+
+    //*******************************************
+    /// Sets a timer's period.
+    //*******************************************
+    bool set_period(etl::timer::id::type id_, uint32_t period_)
+    {
+      if (stop(id_))
+      {
+        timer_array[id_].period = period_;
+        return start(id_);
+      }
+
+      return false;
+    }
+
+    //*******************************************
+    /// Sets a timer's mode.
+    //*******************************************
+    bool set_mode(etl::timer::id::type id_, bool repeating_)
+    {
+      if (stop(id_))
+      {
+        timer_array[id_].repeating = repeating_;
+        return start(id_);
+      }
+
+      return false;
+    }
+
+  protected:
+
+    //*******************************************
+    /// Constructor.
+    //*******************************************
+    icallback_timer(callback_timer_data* const timer_array_, const uint_least8_t  MAX_TIMERS_)
+      : timer_array(timer_array_),
+        active_list(timer_array_),
+        enabled(false),
+        process_semaphore(0),
+        registered_timers(0),
+        MAX_TIMERS(MAX_TIMERS_)
+    {
+    }
+
+  private:
+
+    //*******************************************
+    /// Enable timer callback events.
+    //*******************************************
+    void enable_timer_updates()
+    {
+      --process_semaphore;
+    }
+
+    //*******************************************
+    /// Disable timer callback events.
+    //*******************************************
+    void disable_timer_updates()
+    {
+      ++process_semaphore;
+    }
+
+    // The array of timer data structures.
+    callback_timer_data* const timer_array;
+
+    // The list of active timers.
+    __private_callback_timer__::list active_list;
+
+    volatile bool enabled;
+    volatile etl::timer_semaphore_t process_semaphore;
+    volatile uint_least8_t registered_timers;
+
+  public:
+
+    const uint_least8_t MAX_TIMERS;
+  };
+
+  //***************************************************************************
+  /// The callback timer
+  //***************************************************************************
+  template <const uint_least8_t MAX_TIMERS_>
+  class callback_timer : public etl::icallback_timer
+  {
+  public:
+
+    STATIC_ASSERT(MAX_TIMERS_ <= 254, "No more than 254 timers are allowed");
+
+    //*******************************************
+    /// Constructor.
+    //*******************************************
+    callback_timer()
+      : icallback_timer(timer_array, MAX_TIMERS_)
+    {
+    }
+
+  private:
+
+    callback_timer_data timer_array[MAX_TIMERS_];
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/char_traits.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,244 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_CHAR_TRAITS__
+#define __ETL_CHAR_TRAITS__
+
+#include <algorithm>
+
+#include "platform.h"
+#include <stdint.h>
+#include "algorithm.h"
+
+//*****************************************************************************
+///\defgroup char_traits char_traits
+/// Character traits
+///\ingroup string
+//*****************************************************************************
+
+// Define the large character types if necessary.
+#if (ETL_NO_LARGE_CHAR_SUPPORT)
+typedef int16_t char16_t;
+typedef int32_t char32_t;
+#endif
+
+namespace etl
+{
+  template<typename T> struct char_traits_types;
+  
+  template<> struct char_traits_types<char>
+  {
+    typedef char      char_type;
+    typedef int       int_type;
+    typedef long long off_type;
+    typedef size_t    pos_type;
+    typedef char      state_type;
+  };
+  
+  template<> struct char_traits_types<wchar_t>
+  {
+    typedef wchar_t   char_type;
+    typedef wchar_t   int_type;
+    typedef long long off_type;
+    typedef size_t    pos_type;
+    typedef char      state_type;
+  };
+  
+  template<> struct char_traits_types<char16_t>
+  {
+    typedef char16_t       char_type;
+    typedef uint_least16_t int_type;
+    typedef long long      off_type;
+    typedef size_t         pos_type;
+    typedef char           state_type; 
+  };
+  
+  template<> struct char_traits_types<char32_t>
+  {
+    typedef char32_t       char_type;
+    typedef uint_least32_t int_type;
+    typedef long long      off_type;
+    typedef size_t         pos_type;
+    typedef char           state_type;  
+  };
+  
+  //***************************************************************************
+  /// Character traits for any character type.
+  //***************************************************************************
+  template<typename T>
+  struct char_traits : public char_traits_types<T>
+  {   
+    typedef typename char_traits_types<T>::char_type  char_type;
+    typedef typename char_traits_types<T>::int_type   int_type;
+    typedef typename char_traits_types<T>::off_type   off_type;
+    typedef typename char_traits_types<T>::pos_type   pos_type;
+    typedef typename char_traits_types<T>::state_type state_type;
+    
+    //*************************************************************************
+    static bool eq(char_type a, char_type b)
+    {
+      return a == b;
+    }
+    
+    //*************************************************************************
+    static bool lt(char_type a, char_type b)
+    {
+      return a < b;
+    }     
+    
+    //*************************************************************************
+    static size_t length(const char_type* str)
+    {
+      size_t count = 0;
+          
+      if (str != 0)
+      {
+        while (*str++ != 0)
+        {
+          ++count;
+        }
+      }
+      
+      return count;
+    }
+    
+    //*************************************************************************
+    static void assign(char_type& r, const char_type& c)
+    {
+      r = c;
+    }
+    
+    //*************************************************************************
+    static char_type* assign(char_type* p, size_t n, char_type c)
+    {
+      if (p != 0)
+      {
+        std::fill_n(p, n, c);
+      }
+      
+      return p;
+    }
+    
+    //*************************************************************************
+    static char_type* move(char_type* dest, const char_type* src, size_t count)
+    {
+      if ((dest < src) || (dest > (src + count)))
+      {
+        etl::copy_n(src, src + count, dest);
+      }
+      else
+      {
+        etl::copy_n(std::reverse_iterator<char_type*>(src + count),
+                    count,
+                    std::reverse_iterator<char_type*>(dest + count));
+      }
+      
+      return dest;
+    }
+    
+    //*************************************************************************
+    static char_type* copy(char_type* dest, const char_type* src, size_t count)
+    {
+      etl::copy_n(src, src + count, dest);
+      
+      return dest;
+    }
+    
+    //*************************************************************************
+    static int compare(const char_type* s1, const char_type* s2, size_t count)
+    {       
+      for (size_t i = 0; i < count; ++i)
+      {
+        if (*s1 < *s2)
+        {
+          return -1;
+        }
+          else if (*s1 > *s2)
+        {
+          return 1;
+        }
+        
+        ++s1;
+        ++s2;
+      }
+        
+      return 0;
+    }
+    
+    //*************************************************************************
+    static const char_type* find(const char_type* p, size_t count, const char_type& ch)
+    {     
+      for (size_t i = 0; i < count; ++i)
+      {
+        if (*p == ch)
+        {
+          return p;
+        }
+        
+        ++p;
+      }
+      
+      return 0;
+    }
+    
+    //*************************************************************************
+    static char_type to_char_type(int_type c)
+    {
+      return static_cast<char_type>(c);
+    }
+    
+    //*************************************************************************
+    static int_type to_int_type(char_type c)
+    {
+      return static_cast<int_type>(c);
+    }
+    
+    //*************************************************************************
+    static bool eq_int_type(int_type c1, int_type c2)
+    {
+      return (c1 == c2);
+    }
+    
+    //*************************************************************************
+    static int_type eof()
+    {
+      return -1;
+    }
+    
+    //*************************************************************************
+    static int_type not_eof(int_type e)
+    {
+      return (e == eof()) ? eof() - 1 : e;
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/checksum.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,255 @@
+
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+Copyright(c) 2014 jwellbelove
+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 __ETL_CHECKSUM__
+#define __ETL_CHECKSUM__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "binary.h"
+#include "frame_check_sequence.h"
+
+///\defgroup checksum Checksum calculation
+///\ingroup maths
+
+namespace etl
+{
+  //***************************************************************************
+  /// Standard addition checksum policy.
+  //***************************************************************************
+  template <typename T>
+  struct checksum_policy_sum
+  {
+    typedef T value_type;
+
+    inline T initial() const
+    {
+      return 0;
+    }
+
+    inline T add(T sum, uint8_t value) const
+    {
+      return sum + value;
+    }
+
+    inline T final(T sum) const
+    {
+      return sum;
+    }
+  };
+
+  //***************************************************************************
+  /// BSD checksum policy.
+  //***************************************************************************
+  template <typename T>
+  struct checksum_policy_bsd
+  {
+    typedef T value_type;
+
+    inline T initial() const
+    {
+      return 0;
+    }
+
+    inline T add(T sum, uint8_t value) const
+    {
+      return etl::rotate_right(sum) + value;
+    }
+
+    inline T final(T sum) const
+    {
+      return sum;
+    }
+  };
+
+  //***************************************************************************
+  /// Standard XOR checksum policy.
+  //***************************************************************************
+  template <typename T>
+  struct checksum_policy_xor
+  {
+    typedef T value_type;
+
+    inline T initial() const
+    {
+      return 0;
+    }
+
+    inline T add(T sum, uint8_t value) const
+    {
+      return sum ^ value;
+    }
+
+    inline T final(T sum) const
+    {
+      return sum;
+    }
+  };
+
+  //***************************************************************************
+  /// XOR-rotate checksum policy.
+  //***************************************************************************
+  template <typename T>
+  struct checksum_policy_xor_rotate
+  {
+    typedef T value_type;
+
+    inline T initial() const
+    {
+      return 0;
+    }
+
+    inline T add(T sum, uint8_t value) const
+    {
+      return etl::rotate_left(sum) ^ value;
+    }
+
+    inline T final(T sum) const
+    {
+      return sum;
+    }
+  };
+
+  //*************************************************************************
+  /// Standard Checksum.
+  //*************************************************************************
+  template <typename T>
+  class checksum : public etl::frame_check_sequence<etl::checksum_policy_sum<T> >
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    checksum()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    checksum(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+
+  //*************************************************************************
+  /// BSD Checksum.
+  //*************************************************************************
+  template <typename T>
+  class bsd_checksum : public etl::frame_check_sequence<etl::checksum_policy_bsd<T> >
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    bsd_checksum()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    bsd_checksum(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+
+  //*************************************************************************
+  /// XOR Checksum.
+  //*************************************************************************
+  template <typename T>
+  class xor_checksum : public etl::frame_check_sequence<etl::checksum_policy_xor<T> >
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    xor_checksum()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    xor_checksum(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+
+  //*************************************************************************
+  /// XOR-shift Checksum.
+  //*************************************************************************
+  template <typename T>
+  class xor_rotate_checksum : public etl::frame_check_sequence<etl::checksum_policy_xor_rotate<T> >
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    xor_rotate_checksum()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    xor_rotate_checksum(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compare.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,81 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_COMPARE__
+#define __ETL_COMPARE__
+
+#include <functional>
+
+#include "platform.h"
+#include "parameter_type.h"
+
+//*****************************************************************************
+///\defgroup compare compare
+/// Comparisons only using less than operator
+///\ingroup utilities
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Defines <=, >, >= interms of <
+  /// Default 
+  //***************************************************************************
+  template <typename T, typename TLess = std::less<T> >
+  struct compare
+  {
+    typedef typename etl::parameter_type<T>::type first_argument_type;
+    typedef typename etl::parameter_type<T>::type second_argument_type;
+    typedef bool result_type;
+
+    static result_type lt(first_argument_type lhs, second_argument_type rhs)
+    {
+      return TLess()(lhs, rhs);
+    }
+
+    static result_type gt(first_argument_type lhs, second_argument_type rhs)
+    {
+      return TLess()(rhs, lhs);
+    }
+
+    static result_type lte(first_argument_type lhs, second_argument_type rhs)
+    {
+      return !gt(lhs, rhs);
+    }
+
+    static result_type gte(first_argument_type lhs, second_argument_type rhs)
+    {
+      return !lt(lhs, rhs);
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/constant.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,58 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_CONSTANT__
+#define __ETL_CONSTANT__
+
+#include "platform.h"
+
+//*****************************************************************************
+///\defgroup constant constant
+///\ingroup utilities
+//*****************************************************************************
+
+namespace etl
+{
+  template <typename T, const T VALUE>
+  class constant
+  {
+  public:
+
+    typedef T value_type;
+
+    static const T value = VALUE;
+  };
+
+  template <typename T, const T VALUE>
+  const T constant<T, VALUE>::value;
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/container.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,306 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_CONTAINER__
+#define __ETL_CONTAINER__
+
+#include <stddef.h>
+#include <iterator>
+
+#include "platform.h"
+
+///\defgroup container container
+///\ingroup utilities
+
+namespace etl
+{
+	//*****************************************************************************
+	/// Get the 'begin' iterator.
+  ///\ingroup container
+	//*****************************************************************************
+	template<typename TContainer>
+  ETL_CONSTEXPR typename TContainer::iterator begin(TContainer& container)
+	{
+		return container.begin();
+	}
+
+	//*****************************************************************************
+	/// Get the 'begin' const_iterator for a container.
+  ///\ingroup container
+	//*****************************************************************************
+	template<typename TContainer>
+  ETL_CONSTEXPR typename TContainer::const_iterator begin(const TContainer& container)
+	{
+		return container.begin();
+	}
+
+  //*****************************************************************************
+  /// Get the 'begin' const_iterator for a container.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TContainer>
+  ETL_CONSTEXPR typename TContainer::const_iterator cbegin(const TContainer& container)
+  {
+    return container.cbegin();
+  }
+
+  //*****************************************************************************
+  /// Get the 'begin' reverse_iterator for a container.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TContainer>
+  ETL_CONSTEXPR typename TContainer::reverse_iterator rbegin(const TContainer& container)
+  {
+    return container.rbegin();
+  }
+
+  //*****************************************************************************
+  /// Get the 'begin' reverse_iterator for a container.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TContainer>
+  ETL_CONSTEXPR typename TContainer::reverse_iterator crbegin(const TContainer& container)
+  {
+    return container.crbegin();
+  }
+
+	//*****************************************************************************
+	/// Get the 'end' iterator for a container.
+  ///\ingroup container
+	//*****************************************************************************
+	template<typename TContainer>
+  ETL_CONSTEXPR typename TContainer::iterator end(TContainer& container)
+	{
+		return container.end();
+	}
+
+	//*****************************************************************************
+	/// Get the 'end' const_iterator for a container.
+  ///\ingroup container
+	//*****************************************************************************
+	template<typename TContainer>
+  ETL_CONSTEXPR typename TContainer::const_iterator end(const TContainer& container)
+	{
+		return container.end();
+	}
+
+  //*****************************************************************************
+  /// Get the 'end' const_iterator for a container.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TContainer>
+  ETL_CONSTEXPR typename TContainer::const_iterator cend(const TContainer& container)
+  {
+    return container.cend();
+  }
+
+  //*****************************************************************************
+  /// Get the 'end' reverse_iterator for a container.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TContainer>
+  ETL_CONSTEXPR typename TContainer::const_iterator rend(const TContainer& container)
+  {
+    return container.rend();
+  }
+
+  //*****************************************************************************
+  /// Get the 'end' reverse_iterator for a container.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TContainer>
+  ETL_CONSTEXPR typename TContainer::reverse_iterator crend(const TContainer& container)
+  {
+    return container.crend();
+  }
+
+	//*****************************************************************************
+	/// Get the 'begin' pointer for an array.
+  ///\ingroup container
+	//*****************************************************************************
+	template<typename TValue, const size_t ARRAY_SIZE>
+  ETL_CONSTEXPR TValue* begin(TValue(&data)[ARRAY_SIZE])
+	{
+		return &data[0];
+	}
+
+  //*****************************************************************************
+  /// Get the 'begin' const iterator for an array.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TValue, const size_t ARRAY_SIZE>
+  ETL_CONSTEXPR const TValue* begin(const TValue(&data)[ARRAY_SIZE])
+  {
+    return &data[0];
+  }
+
+  //*****************************************************************************
+  /// Get the 'begin' const iterator for an array.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TValue, const size_t ARRAY_SIZE>
+  ETL_CONSTEXPR const TValue* cbegin(const TValue(&data)[ARRAY_SIZE])
+  {
+    return &data[0];
+  }
+
+  //*****************************************************************************
+  /// Get the 'begin' reverse_iterator for an array.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TValue, const size_t ARRAY_SIZE>
+  ETL_CONSTEXPR std::reverse_iterator<TValue*> rbegin(const TValue(&data)[ARRAY_SIZE])
+  {
+    return std::reverse_iterator<TValue*>(&data[ARRAY_SIZE]);
+  }
+
+  //*****************************************************************************
+  /// Get the 'begin' const reverse_iterator for an array.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TValue, const size_t ARRAY_SIZE>
+  ETL_CONSTEXPR std::reverse_iterator<const TValue*> crbegin(const TValue(&data)[ARRAY_SIZE])
+  {
+    return std::reverse_iterator<const TValue*>(&data[ARRAY_SIZE]);
+  }
+
+	//*****************************************************************************
+	/// Get the 'end' iterator for an array.
+  ///\ingroup container
+	//*****************************************************************************
+	template<typename TValue, const size_t ARRAY_SIZE>
+  ETL_CONSTEXPR TValue* end(TValue(&data)[ARRAY_SIZE])
+	{
+		return &data[ARRAY_SIZE];
+	}
+
+  //*****************************************************************************
+  /// Get the 'end' const iterator for an array.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TValue, const size_t ARRAY_SIZE>
+  ETL_CONSTEXPR const TValue* end(const TValue(&data)[ARRAY_SIZE])
+  {
+    return &data[ARRAY_SIZE];
+  }
+
+  //*****************************************************************************
+  /// Get the 'end' const iterator for an array.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TValue, const size_t ARRAY_SIZE>
+  ETL_CONSTEXPR const TValue* cend(const TValue(&data)[ARRAY_SIZE])
+  {
+    return &data[ARRAY_SIZE];
+  }
+
+  //*****************************************************************************
+  /// Get the 'end' reverse_iterator for an array.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TValue, const size_t ARRAY_SIZE>
+  ETL_CONSTEXPR std::reverse_iterator<TValue*> rend(const TValue(&data)[ARRAY_SIZE])
+  {
+    return std::reverse_iterator<TValue*>(&data[0]);
+  }
+
+  //*****************************************************************************
+  /// Get the 'end' const reverse_iterator for an array.
+  ///\ingroup container
+  //*****************************************************************************
+  template<typename TValue, const size_t ARRAY_SIZE>
+  ETL_CONSTEXPR std::reverse_iterator<const TValue*> crend(const TValue(&data)[ARRAY_SIZE])
+  {
+    return std::reverse_iterator<const TValue*>(&data[0]);
+  }
+
+  //*****************************************************************************
+	/// Get the next iterator.
+  ///\ingroup container
+	//*****************************************************************************
+  template<class TIterator>
+  TIterator next(TIterator iterator, ptrdiff_t n = 1)
+  {
+      std::advance(iterator, n);
+      return iterator;
+  }
+
+  //*****************************************************************************
+	/// Get the previous iterator.
+  ///\ingroup container
+	//*****************************************************************************
+  template<class TIterator>
+  TIterator prev(TIterator iterator, ptrdiff_t n = 1)
+  {
+      std::advance(iterator, -n);
+      return iterator;
+  }
+
+  ///**************************************************************************
+  /// Get the size of a container.
+  /// Expects the container to have defined 'size_type'.
+  ///\ingroup container
+  ///**************************************************************************
+  template<typename TContainer>
+  ETL_CONSTEXPR typename TContainer::size_type size(const TContainer& container)
+  {
+    return container.size();
+  }
+
+  ///**************************************************************************
+  /// Get the size of an array in elements at run time, or compile time if C++11 or above.
+  ///\ingroup container
+  ///**************************************************************************
+  template<typename TValue, const size_t ARRAY_SIZE>
+  ETL_CONSTEXPR size_t size(TValue(&)[ARRAY_SIZE])
+  {
+    return ARRAY_SIZE;
+  }
+
+  ///**************************************************************************
+  /// Get the size of an array in elements at compile time for C++03
+  ///\code
+  /// sizeof(array_size(array))
+  ///\endcode
+  ///\ingroup container
+  ///**************************************************************************
+  template <typename T, const size_t ARRAY_SIZE>
+  char(&array_size(T(&array)[ARRAY_SIZE]))[ARRAY_SIZE];
+}
+
+#if ETL_CPP11_SUPPORTED
+  #define ETL_ARRAY_SIZE(a) (etl::size(a))
+#else
+  #define ETL_ARRAY_SIZE(a) sizeof(etl::array_size(a))
+#endif
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc16.cpp	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,61 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+#include <stdint.h>
+
+#include "platform.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// CRC16 table
+  /// \ingroup crc16
+  //***************************************************************************
+  extern const uint16_t CRC16[] =
+  {
+    0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+    0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+    0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+    0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+    0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+    0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+    0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+    0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+    0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+    0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+    0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+    0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+    0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+    0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+    0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+    0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+  };
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc16.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,109 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_CRC16__
+#define __ETL_CRC16__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup crc16 16 bit CRC calculation
+///\ingroup crc
+
+namespace etl
+{
+  //***************************************************************************
+  /// CRC16 table
+  /// \ingroup crc16
+  //***************************************************************************
+  extern const uint16_t CRC16[];
+
+  //***************************************************************************
+  /// CRC16 policy.
+  /// Calculates CRC16 using polynomial 0x8005.
+  //***************************************************************************
+  struct crc_policy_16
+  {
+    typedef uint16_t value_type;
+
+    inline uint16_t initial() const
+    {
+      return 0;
+    }
+
+    inline uint16_t add(uint16_t crc, uint8_t value) const
+    {
+      return  (crc >> 8) ^ CRC16[(crc ^ value) & 0xFF];
+    }
+
+    inline uint16_t final(uint16_t crc) const
+    {
+      return crc;
+    }
+  };
+
+  //*************************************************************************
+  /// CRC16
+  //*************************************************************************
+  class crc16 : public etl::frame_check_sequence<etl::crc_policy_16>
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    crc16()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    crc16(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc16_ccitt.cpp	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,61 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+#include <stdint.h>
+
+#include "platform.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// CRC-CCITT table
+  /// \ingroup crc16_ccitt
+  //***************************************************************************
+  extern const uint16_t CRC_CCITT[] =
+  {
+    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+    0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+    0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+    0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+    0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+    0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+    0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+    0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+    0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+    0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+    0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+    0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+    0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+    0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+    0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+    0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+  };
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc16_ccitt.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,109 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_CRC16_CCITT__
+#define __ETL_CRC16_CCITT__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup crc16_ccitt 16 bit CRC CCITT calculation
+///\ingroup crc
+
+namespace etl
+{
+  //***************************************************************************
+  /// CRC-CCITT table
+  /// \ingroup crc16_ccitt
+  //***************************************************************************
+  extern const uint16_t CRC_CCITT[];
+
+  //***************************************************************************
+  /// CRC16 CCITT policy.
+  /// Calculates CRC16 CCITT using polynomial 0x1021
+  //***************************************************************************
+  struct crc_policy_16_ccitt
+  {
+    typedef uint16_t value_type;
+
+    inline uint16_t initial() const
+    {
+      return 0xFFFF;
+    }
+
+    inline uint16_t add(uint16_t crc, uint8_t value) const
+    {
+      return  (crc << 8) ^ CRC_CCITT[((crc >> 8) ^ value) & 0xFF];
+    }
+
+    inline uint16_t final(uint16_t crc) const
+    {
+      return crc;
+    }
+  };
+
+  //*************************************************************************
+  /// CRC16 CCITT
+  //*************************************************************************
+  class crc16_ccitt : public etl::frame_check_sequence<etl::crc_policy_16_ccitt>
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    crc16_ccitt()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    crc16_ccitt(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc16_kermit.cpp	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,61 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+#include <stdint.h>
+
+#include "platform.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// CRC Kermit table
+  /// \ingroup crc16_kermit
+  //***************************************************************************
+  extern const uint16_t CRC_KERMIT[] =
+  {
+    0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
+    0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
+    0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
+    0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
+    0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
+    0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
+    0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
+    0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
+    0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
+    0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
+    0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
+    0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
+    0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
+    0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
+    0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
+    0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
+  };
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc16_kermit.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,109 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_CRC16_KERMIT__
+#define __ETL_CRC16_KERMIT__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup crc16_kermit 16 bit CRC Kermit calculation
+///\ingroup crc
+
+namespace etl
+{
+  //***************************************************************************
+  /// CRC Kermit table
+  /// \ingroup crc
+  //***************************************************************************
+  extern const uint16_t CRC_KERMIT[];
+
+  //***************************************************************************
+  /// CRC16 Kermit policy.
+  /// Calculates CRC16 Kermit using polynomial 0x1021
+  //***************************************************************************
+  struct crc_policy_16_kermit
+  {
+    typedef uint16_t value_type;
+
+    inline uint16_t initial() const
+    {
+      return 0;
+    }
+
+    inline uint16_t add(uint16_t crc, uint8_t value) const
+    {
+      return (crc >> 8) ^ CRC_KERMIT[(crc ^ value) & 0xFF];
+    }
+
+    inline uint16_t final(uint16_t crc) const
+    {
+      return crc;
+    }
+  };
+
+  //*************************************************************************
+  /// CRC16 Kermit
+  //*************************************************************************
+  class crc16_kermit : public etl::frame_check_sequence<etl::crc_policy_16_kermit>
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    crc16_kermit()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    crc16_kermit(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc32.cpp	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,77 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+#include <stdint.h>
+
+#include "platform.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// CRC32 table
+  /// \ingroup crc32
+  //***************************************************************************
+  extern const uint32_t CRC32[] =
+  {
+    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+  };
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc32.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,109 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_CRC32__
+#define __ETL_CRC32__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup crc32 32 bit CRC calculation
+///\ingroup crc
+
+namespace etl
+{
+  //***************************************************************************
+  /// CRC32 table
+  /// \ingroup crc32
+  //***************************************************************************
+  extern const uint32_t CRC32[];
+
+  //***************************************************************************
+  /// CRC32 policy.
+  /// Calculates CRC32 using polynomial 0x04C11DB7.
+  //***************************************************************************
+  struct crc_policy_32
+  {
+    typedef uint32_t value_type;
+
+    inline uint32_t initial() const
+    {
+      return 0xFFFFFFFF;
+    }
+
+    inline uint32_t add(uint32_t crc, uint8_t value) const
+    {
+      return  (crc >> 8) ^ CRC32[(crc ^ value) & 0xFF];
+    }
+
+    inline uint32_t final(uint32_t crc) const
+    {
+      return crc ^ 0xFFFFFFFF;
+    }
+  };
+
+  //*************************************************************************
+  /// CRC32
+  //*************************************************************************
+  class crc32 : public etl::frame_check_sequence<etl::crc_policy_32>
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    crc32()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    crc32(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc64_ecma.cpp	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,109 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+#include <stdint.h>
+
+#include "platform.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// CRC64_ECMA table
+  /// \ingroup crc64_ecma
+  //***************************************************************************
+  extern const uint64_t CRC64_ECMA[] =
+  {
+    0x0000000000000000, 0x42F0E1EBA9EA3693, 0x85E1C3D753D46D26, 0xC711223CFA3E5BB5,
+    0x493366450E42ECDF, 0x0BC387AEA7A8DA4C, 0xCCD2A5925D9681F9, 0x8E224479F47CB76A,
+    0x9266CC8A1C85D9BE, 0xD0962D61B56FEF2D, 0x17870F5D4F51B498, 0x5577EEB6E6BB820B,
+    0xDB55AACF12C73561, 0x99A54B24BB2D03F2, 0x5EB4691841135847, 0x1C4488F3E8F96ED4,
+    0x663D78FF90E185EF, 0x24CD9914390BB37C, 0xE3DCBB28C335E8C9, 0xA12C5AC36ADFDE5A,
+    0x2F0E1EBA9EA36930, 0x6DFEFF5137495FA3, 0xAAEFDD6DCD770416, 0xE81F3C86649D3285,
+    0xF45BB4758C645C51, 0xB6AB559E258E6AC2, 0x71BA77A2DFB03177, 0x334A9649765A07E4,
+    0xBD68D2308226B08E, 0xFF9833DB2BCC861D, 0x388911E7D1F2DDA8, 0x7A79F00C7818EB3B,
+    0xCC7AF1FF21C30BDE, 0x8E8A101488293D4D, 0x499B3228721766F8, 0x0B6BD3C3DBFD506B,
+    0x854997BA2F81E701, 0xC7B97651866BD192, 0x00A8546D7C558A27, 0x4258B586D5BFBCB4,
+    0x5E1C3D753D46D260, 0x1CECDC9E94ACE4F3, 0xDBFDFEA26E92BF46, 0x990D1F49C77889D5,
+    0x172F5B3033043EBF, 0x55DFBADB9AEE082C, 0x92CE98E760D05399, 0xD03E790CC93A650A,
+    0xAA478900B1228E31, 0xE8B768EB18C8B8A2, 0x2FA64AD7E2F6E317, 0x6D56AB3C4B1CD584,
+    0xE374EF45BF6062EE, 0xA1840EAE168A547D, 0x66952C92ECB40FC8, 0x2465CD79455E395B,
+    0x3821458AADA7578F, 0x7AD1A461044D611C, 0xBDC0865DFE733AA9, 0xFF3067B657990C3A,
+    0x711223CFA3E5BB50, 0x33E2C2240A0F8DC3, 0xF4F3E018F031D676, 0xB60301F359DBE0E5,
+    0xDA050215EA6C212F, 0x98F5E3FE438617BC, 0x5FE4C1C2B9B84C09, 0x1D14202910527A9A,
+    0x93366450E42ECDF0, 0xD1C685BB4DC4FB63, 0x16D7A787B7FAA0D6, 0x5427466C1E109645,
+    0x4863CE9FF6E9F891, 0x0A932F745F03CE02, 0xCD820D48A53D95B7, 0x8F72ECA30CD7A324,
+    0x0150A8DAF8AB144E, 0x43A04931514122DD, 0x84B16B0DAB7F7968, 0xC6418AE602954FFB,
+    0xBC387AEA7A8DA4C0, 0xFEC89B01D3679253, 0x39D9B93D2959C9E6, 0x7B2958D680B3FF75,
+    0xF50B1CAF74CF481F, 0xB7FBFD44DD257E8C, 0x70EADF78271B2539, 0x321A3E938EF113AA,
+    0x2E5EB66066087D7E, 0x6CAE578BCFE24BED, 0xABBF75B735DC1058, 0xE94F945C9C3626CB,
+    0x676DD025684A91A1, 0x259D31CEC1A0A732, 0xE28C13F23B9EFC87, 0xA07CF2199274CA14,
+    0x167FF3EACBAF2AF1, 0x548F120162451C62, 0x939E303D987B47D7, 0xD16ED1D631917144,
+    0x5F4C95AFC5EDC62E, 0x1DBC74446C07F0BD, 0xDAAD56789639AB08, 0x985DB7933FD39D9B,
+    0x84193F60D72AF34F, 0xC6E9DE8B7EC0C5DC, 0x01F8FCB784FE9E69, 0x43081D5C2D14A8FA,
+    0xCD2A5925D9681F90, 0x8FDAB8CE70822903, 0x48CB9AF28ABC72B6, 0x0A3B7B1923564425,
+    0x70428B155B4EAF1E, 0x32B26AFEF2A4998D, 0xF5A348C2089AC238, 0xB753A929A170F4AB,
+    0x3971ED50550C43C1, 0x7B810CBBFCE67552, 0xBC902E8706D82EE7, 0xFE60CF6CAF321874,
+    0xE224479F47CB76A0, 0xA0D4A674EE214033, 0x67C58448141F1B86, 0x253565A3BDF52D15,
+    0xAB1721DA49899A7F, 0xE9E7C031E063ACEC, 0x2EF6E20D1A5DF759, 0x6C0603E6B3B7C1CA,
+    0xF6FAE5C07D3274CD, 0xB40A042BD4D8425E, 0x731B26172EE619EB, 0x31EBC7FC870C2F78,
+    0xBFC9838573709812, 0xFD39626EDA9AAE81, 0x3A28405220A4F534, 0x78D8A1B9894EC3A7,
+    0x649C294A61B7AD73, 0x266CC8A1C85D9BE0, 0xE17DEA9D3263C055, 0xA38D0B769B89F6C6,
+    0x2DAF4F0F6FF541AC, 0x6F5FAEE4C61F773F, 0xA84E8CD83C212C8A, 0xEABE6D3395CB1A19,
+    0x90C79D3FEDD3F122, 0xD2377CD44439C7B1, 0x15265EE8BE079C04, 0x57D6BF0317EDAA97,
+    0xD9F4FB7AE3911DFD, 0x9B041A914A7B2B6E, 0x5C1538ADB04570DB, 0x1EE5D94619AF4648,
+    0x02A151B5F156289C, 0x4051B05E58BC1E0F, 0x87409262A28245BA, 0xC5B073890B687329,
+    0x4B9237F0FF14C443, 0x0962D61B56FEF2D0, 0xCE73F427ACC0A965, 0x8C8315CC052A9FF6,
+    0x3A80143F5CF17F13, 0x7870F5D4F51B4980, 0xBF61D7E80F251235, 0xFD913603A6CF24A6,
+    0x73B3727A52B393CC, 0x31439391FB59A55F, 0xF652B1AD0167FEEA, 0xB4A25046A88DC879,
+    0xA8E6D8B54074A6AD, 0xEA16395EE99E903E, 0x2D071B6213A0CB8B, 0x6FF7FA89BA4AFD18,
+    0xE1D5BEF04E364A72, 0xA3255F1BE7DC7CE1, 0x64347D271DE22754, 0x26C49CCCB40811C7,
+    0x5CBD6CC0CC10FAFC, 0x1E4D8D2B65FACC6F, 0xD95CAF179FC497DA, 0x9BAC4EFC362EA149,
+    0x158E0A85C2521623, 0x577EEB6E6BB820B0, 0x906FC95291867B05, 0xD29F28B9386C4D96,
+    0xCEDBA04AD0952342, 0x8C2B41A1797F15D1, 0x4B3A639D83414E64, 0x09CA82762AAB78F7,
+    0x87E8C60FDED7CF9D, 0xC51827E4773DF90E, 0x020905D88D03A2BB, 0x40F9E43324E99428,
+    0x2CFFE7D5975E55E2, 0x6E0F063E3EB46371, 0xA91E2402C48A38C4, 0xEBEEC5E96D600E57,
+    0x65CC8190991CB93D, 0x273C607B30F68FAE, 0xE02D4247CAC8D41B, 0xA2DDA3AC6322E288,
+    0xBE992B5F8BDB8C5C, 0xFC69CAB42231BACF, 0x3B78E888D80FE17A, 0x7988096371E5D7E9,
+    0xF7AA4D1A85996083, 0xB55AACF12C735610, 0x724B8ECDD64D0DA5, 0x30BB6F267FA73B36,
+    0x4AC29F2A07BFD00D, 0x08327EC1AE55E69E, 0xCF235CFD546BBD2B, 0x8DD3BD16FD818BB8,
+    0x03F1F96F09FD3CD2, 0x41011884A0170A41, 0x86103AB85A2951F4, 0xC4E0DB53F3C36767,
+    0xD8A453A01B3A09B3, 0x9A54B24BB2D03F20, 0x5D45907748EE6495, 0x1FB5719CE1045206,
+    0x919735E51578E56C, 0xD367D40EBC92D3FF, 0x1476F63246AC884A, 0x568617D9EF46BED9,
+    0xE085162AB69D5E3C, 0xA275F7C11F7768AF, 0x6564D5FDE549331A, 0x279434164CA30589,
+    0xA9B6706FB8DFB2E3, 0xEB46918411358470, 0x2C57B3B8EB0BDFC5, 0x6EA7525342E1E956,
+    0x72E3DAA0AA188782, 0x30133B4B03F2B111, 0xF7021977F9CCEAA4, 0xB5F2F89C5026DC37,
+    0x3BD0BCE5A45A6B5D, 0x79205D0E0DB05DCE, 0xBE317F32F78E067B, 0xFCC19ED95E6430E8,
+    0x86B86ED5267CDBD3, 0xC4488F3E8F96ED40, 0x0359AD0275A8B6F5, 0x41A94CE9DC428066,
+    0xCF8B0890283E370C, 0x8D7BE97B81D4019F, 0x4A6ACB477BEA5A2A, 0x089A2AACD2006CB9,
+    0x14DEA25F3AF9026D, 0x562E43B4931334FE, 0x913F6188692D6F4B, 0xD3CF8063C0C759D8,
+    0x5DEDC41A34BBEEB2, 0x1F1D25F19D51D821, 0xD80C07CD676F8394, 0x9AFCE626CE85B507
+  };
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc64_ecma.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,109 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_CRC64_ECMA__
+#define __ETL_CRC64_ECMA__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup crc64_ecma 64 bit CRC ECMA calculation
+///\ingroup crc
+
+namespace etl
+{
+  //***************************************************************************
+  /// CRC64_ECMA table
+  /// \ingroup crc64_ecma
+  //***************************************************************************
+  extern const uint64_t CRC64_ECMA[];
+
+  //***************************************************************************
+  /// CRC64 policy.
+  /// Calculates CRC64 ECMA using polynomial 0x42F0E1EBA9EA3693.
+  //***************************************************************************
+  struct crc_policy_64_ecma
+  {
+    typedef uint64_t value_type;
+
+    inline uint64_t initial() const
+    {
+      return 0;
+    }
+
+    inline uint64_t add(uint64_t crc, uint8_t value) const
+    {
+      return  (crc << 8) ^ CRC64_ECMA[((crc >> 56) ^ value) & 0xFF];
+    }
+
+    inline uint64_t final(uint64_t crc) const
+    {
+      return crc;
+    }
+  };
+
+  //*************************************************************************
+  /// CRC64 ECMA
+  //*************************************************************************
+  class crc64_ecma : public etl::frame_check_sequence<etl::crc_policy_64_ecma>
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    crc64_ecma()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    crc64_ecma(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc8_ccitt.cpp	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,64 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "static_assert.h"
+
+STATIC_ASSERT(ETL_8BIT_SUPPORT, "This file does not currently support targets with no 8bit type");
+
+namespace etl
+{
+  //***************************************************************************
+  /// CRC8 table
+  /// \ingroup crc8_ccitt
+  //***************************************************************************
+  extern const uint8_t CRC8_CCITT[] =
+  {
+    0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+    0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+    0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+    0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+    0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+    0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+    0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+    0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+    0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+    0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+    0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+    0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+    0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+    0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+    0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+    0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+  };
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc8_ccitt.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,109 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_CRC8_CCITT__
+#define __ETL_CRC8_CCITT__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup crc8_ccitt 8 bit CRC calculation
+///\ingroup crc
+
+namespace etl
+{
+  //***************************************************************************
+  /// CRC8 table
+  /// \ingroup crc8_ccitt
+  //***************************************************************************
+  extern const uint8_t CRC8_CCITT[];
+
+  //***************************************************************************
+  /// CRC8 CCITT policy.
+  /// Calculates CRC8 CCITT using polynomial 0x07.
+  //***************************************************************************
+  struct crc_policy_8_ccitt
+  {
+    typedef uint8_t value_type;
+
+    inline uint8_t initial() const
+    {
+      return 0;
+    }
+
+    inline uint8_t add(uint8_t crc, uint8_t value) const
+    {
+      return  CRC8_CCITT[crc ^ value];
+    }
+
+    inline uint8_t final(uint8_t crc) const
+    {
+      return crc;
+    }
+  };
+
+  //*************************************************************************
+  /// CRC8 CCITT
+  //*************************************************************************
+  class crc8_ccitt : public etl::frame_check_sequence<etl::crc_policy_8_ccitt>
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    crc8_ccitt()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    crc8_ccitt(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cstring.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,220 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_STRING__
+#define __ETL_STRING__
+
+#include "platform.h"
+#include "basic_string.h"
+#include "hash.h"
+
+#if defined(ETL_COMPILER_MICROSOFT)
+#undef min
+#endif
+
+namespace etl
+{
+  typedef etl::ibasic_string<char> istring;
+
+  //***************************************************************************
+  /// A string implementation that uses a fixed size buffer.
+  ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+  ///\ingroup string
+  //***************************************************************************
+  template <const size_t MAX_SIZE_>
+  class string : public istring
+  {
+  public:
+
+    typedef istring::value_type value_type;
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    string()
+      : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      istring::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    ///\param other The other string.
+    //*************************************************************************
+    string(const etl::string<MAX_SIZE_>& other)
+      : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      istring::assign(other.begin(), other.end());
+    }
+
+    //*************************************************************************
+    /// From other string, position, length.
+    ///\param other The other string.
+    ///\param position The position of the first character.
+    ///\param length   The number of characters. Default = npos.
+    //*************************************************************************
+    string(const etl::string<MAX_SIZE_>& other, size_t position, size_t length_ = npos)
+      : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
+
+      // Set the length to the exact amount.
+      length_ = (length_ > MAX_SIZE_) ? MAX_SIZE_ : length_;
+
+      istring::assign(other.begin() + position, other.begin() + position + length_);
+    }
+
+    //*************************************************************************
+    /// Constructor, from null terminated text.
+    ///\param text The initial text of the string.
+    //*************************************************************************
+    string(const value_type* text)
+      : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      istring::assign(text, text + etl::char_traits<value_type>::length(text));
+    }
+
+    //*************************************************************************
+    /// Constructor, from null terminated text and count.
+    ///\param text  The initial text of the string.
+    ///\param count The number of characters to copy.
+    //*************************************************************************
+    string(const value_type* text, size_t count)
+      : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      istring::assign(text, text + count);
+    }
+
+    //*************************************************************************
+    /// Constructor, from initial size and value.
+    ///\param initialSize  The initial size of the string.
+    ///\param value        The value to fill the string with.
+    //*************************************************************************
+    string(size_t count, value_type c)
+      : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      istring::initialise();
+      istring::resize(count, c);
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    string(TIterator first, TIterator last)
+      : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      istring::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Returns a sub-string.
+    ///\param position The position of the first character.  Default = 0.
+    ///\param length   The number of characters. Default = npos.
+    //*************************************************************************
+    etl::string<MAX_SIZE_> substr(size_t position = 0, size_t length_ = npos) const
+    {
+      etl::string<MAX_SIZE_> new_string;
+
+      if (position != this->size())
+      {
+        ETL_ASSERT(position < this->size(), ETL_ERROR(string_out_of_bounds));
+
+        length_ = std::min(length_, this->size() - position);
+
+        new_string.assign(buffer + position, buffer + position + length_);
+      }
+
+      return new_string;
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    string& operator = (const string& rhs)
+    {
+      if (&rhs != this)
+      {
+        istring::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    void repair()
+    {
+      etl::istring::repair(buffer);
+    }
+
+  private:
+
+    value_type buffer[MAX_SIZE + 1];
+  };
+
+  //*************************************************************************
+  /// Hash function.
+  //*************************************************************************
+#if ETL_8BIT_SUPPORT
+  template <>
+  struct hash<etl::istring>
+  {
+    size_t operator()(const etl::istring& text) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]),
+                                                         reinterpret_cast<const uint8_t*>(&text[text.size()]));
+    }
+  };
+
+  template <const size_t SIZE>
+  struct hash<etl::string<SIZE> >
+  {
+    size_t operator()(const etl::string<SIZE>& text) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]),
+                                                         reinterpret_cast<const uint8_t*>(&text[text.size()]));
+    }
+  };
+#endif
+}
+
+#if defined(ETL_COMPILER_MICROSOFT)
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cyclic_value.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,582 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_CYCLIC_VALUE__
+#define __ETL_CYCLIC_VALUE__
+
+#include <stddef.h>
+
+///\defgroup cyclic_value cyclic_value
+/// Provides a value that cycles between two limits.
+/// \ingroup utilities
+
+#include <algorithm>
+
+#include "platform.h"
+#include "static_assert.h"
+#include "exception.h"
+#include "static_assert.h"
+#include "type_traits.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Provides a value that cycles between two limits.
+  /// Supports incrementing and decrementing.
+  ///\tparam T     The type of the variable.
+  ///\tparam FIRST The first value of the range.
+  ///\tparam LAST  The last value of the range.
+  ///\ingroup cyclic_value
+  //***************************************************************************
+  template <typename T, T FIRST = 0, T LAST = 0, typename = void>
+  class cyclic_value
+  {
+  public:
+
+    //*************************************************************************
+    /// Constructor.
+    /// The initial value is set to the first value.
+    //*************************************************************************
+    cyclic_value()
+      : value(FIRST)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    cyclic_value(const cyclic_value<T, FIRST, LAST>& other)
+      : value(other.value)
+    {
+    }
+
+    //*************************************************************************
+    /// Sets the value.
+    ///\param value The value.
+    //*************************************************************************
+    void set(T value_)
+    {
+      if (value_ > LAST)
+      {
+        value_ = LAST;
+      }
+      else if (value_ < FIRST)
+      {
+        value_ = FIRST;
+      }
+
+      value = value_;
+    }
+
+    //*************************************************************************
+    /// Resets the value to the first in the range.
+    //*************************************************************************
+    void to_first()
+    {
+      value = FIRST;
+    }
+
+    //*************************************************************************
+    /// Resets the value to the last in the range.
+    //*************************************************************************
+    void to_last()
+    {
+      value = LAST;
+    }
+
+    //*************************************************************************
+    /// Advances to value by a number of steps.
+    ///\param n The number of steps to advance.
+    //*************************************************************************
+    void advance(int n)
+    {
+      T range = LAST - FIRST + T(1);
+
+      n = n % range;
+
+      if (n > 0)
+      {
+        for (int i = 0; i < n; ++i)
+        {
+          operator ++();
+        }
+      }
+      else
+      {
+        for (int i = 0; i < -n; ++i)
+        {
+          operator --();
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Conversion operator.
+    /// \return The value of the underlying type.
+    //*************************************************************************
+    operator T()
+    {
+      return value;
+    }
+
+    //*************************************************************************
+    /// Const conversion operator.
+    /// \return The value of the underlying type.
+    //*************************************************************************
+    operator const T() const
+    {
+      return value;
+    }
+
+    //*************************************************************************
+    /// ++ operator.
+    //*************************************************************************
+    cyclic_value& operator ++()
+    {
+      if (value >= LAST)
+      {
+        value = FIRST;
+      }
+      else
+      {
+        ++value;
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// ++ operator.
+    //*************************************************************************
+    cyclic_value operator ++(int)
+    {
+      cyclic_value temp(*this);
+
+      operator++();
+
+      return temp;
+    }
+
+    //*************************************************************************
+    /// -- operator.
+    //*************************************************************************
+    cyclic_value& operator --()
+    {
+      if (value <= FIRST)
+      {
+        value = LAST;
+      }
+      else
+      {
+        --value;
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// -- operator.
+    //*************************************************************************
+    cyclic_value operator --(int)
+    {
+      cyclic_value temp(*this);
+
+      operator--();
+
+      return temp;
+    }
+
+    //*************************************************************************
+    /// = operator.
+    //*************************************************************************
+    cyclic_value& operator =(T t)
+    {
+      set(t);
+      return *this;
+    }
+
+    //*************************************************************************
+    /// = operator.
+    //*************************************************************************
+    template <const T FIRST2, const T LAST2>
+    cyclic_value& operator =(const cyclic_value<T, FIRST2, LAST2>& other)
+    {
+      set(other.get());
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Gets the value.
+    //*************************************************************************
+    T get() const
+    {
+      return value;
+    }
+
+    //*************************************************************************
+    /// Gets the first value.
+    //*************************************************************************
+    const T first() const
+    {
+      return FIRST;
+    }
+
+    //*************************************************************************
+    /// Gets the last value.
+    //*************************************************************************
+    const T last() const
+    {
+      return LAST;
+    }
+
+    //*************************************************************************
+    /// Swaps the values.
+    //*************************************************************************
+    void swap(cyclic_value<T, FIRST, LAST>& other)
+    {
+      std::swap(value, other.value);
+    }
+
+    //*************************************************************************
+    /// Swaps the values.
+    //*************************************************************************
+    friend void swap(cyclic_value<T, FIRST, LAST>& lhs, cyclic_value<T, FIRST, LAST>& rhs)
+    {
+      lhs.swap(rhs);
+    }
+
+    //*************************************************************************
+    /// Operator ==.
+    //*************************************************************************
+    friend bool operator == (const cyclic_value<T, FIRST, LAST>& lhs, const cyclic_value<T, FIRST, LAST>& rhs)
+    {
+      return lhs.value == rhs.value;
+    }
+
+    //*************************************************************************
+    /// Operator !=.
+    //*************************************************************************
+    friend bool operator != (const cyclic_value<T, FIRST, LAST>& lhs, const cyclic_value<T, FIRST, LAST>& rhs)
+    {
+      return !(lhs == rhs);
+    }
+
+  private:
+
+    T value; ///< The current value.
+  };
+
+  //***************************************************************************
+  /// Provides a value that cycles between two limits.
+  /// Supports incrementing and decrementing.
+  ///\tparam T     The type of the variable.
+  ///\tparam FIRST The first value of the range.
+  ///\tparam LAST  The last value of the range.
+  ///\ingroup cyclic_value
+  //***************************************************************************
+  template <typename T, const T FIRST, const T LAST>
+  class cyclic_value<T, FIRST, LAST, typename etl::enable_if<(FIRST == 0) && (LAST == 0)>::type>
+  {
+  public:
+
+    //*************************************************************************
+    /// Constructor.
+    /// Sets 'first' and 'last' to the template parameter values.
+    /// The initial value is set to the first value.
+    //*************************************************************************
+    cyclic_value()
+      : value(FIRST),
+        first_value(FIRST),
+        last_value(LAST)
+    {
+    }
+
+    //*************************************************************************
+    /// Constructor.
+    /// Sets the value to the first of the range.
+    ///\param first The first value in the range.
+    ///\param last  The last value in the range.
+    //*************************************************************************
+    cyclic_value(T first_, T last_)
+      : value(first_),
+        first_value(first_),
+        last_value(last_)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    cyclic_value(const cyclic_value& other)
+      : value(other.value),
+        first_value(other.first_value),
+        last_value(other.last_value)
+    {
+    }
+
+    //*************************************************************************
+    /// Sets the range.
+    /// Sets the value to the first of the range.
+    ///\param first The first value in the range.
+    ///\param last  The last value in the range.
+    //*************************************************************************
+    void set(T first_, T last_)
+    {
+      first_value = first_;
+      last_value  = last_;
+      value       = first_;
+    }
+
+    //*************************************************************************
+    /// Sets the value.
+    ///\param value The value.
+    //*************************************************************************
+    void set(T value_)
+    {
+      if (value_ > last_value)
+      {
+        value_ = last_value;
+      }
+      else if (value_ < first_value)
+      {
+        value_ = first_value;
+      }
+
+      value = value_;
+    }
+
+    //*************************************************************************
+    /// Resets the value to the first in the range.
+    //*************************************************************************
+    void to_first()
+    {
+      value = first_value;
+    }
+
+    //*************************************************************************
+    /// Resets the value to the last in the range.
+    //*************************************************************************
+    void to_last()
+    {
+      value = last_value;
+    }
+
+    //*************************************************************************
+    /// Advances to value by a number of steps.
+    ///\param n The number of steps to advance.
+    //*************************************************************************
+    void advance(int n)
+    {
+      T range = last_value - first_value + T(1);
+
+      n = n % range;
+
+      if (n > 0)
+      {
+        for (int i = 0; i < n; ++i)
+        {
+          operator ++();
+        }
+      }
+      else
+      {
+        for (int i = 0; i < -n; ++i)
+        {
+          operator --();
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Conversion operator.
+    /// \return The value of the underlying type.
+    //*************************************************************************
+    operator T()
+    {
+      return value;
+    }
+
+    //*************************************************************************
+    /// Const conversion operator.
+    /// \return The value of the underlying type.
+    //*************************************************************************
+    operator const T() const
+    {
+      return value;
+    }
+
+    //*************************************************************************
+    /// ++ operator.
+    //*************************************************************************
+    cyclic_value& operator ++()
+    {
+      if (value >= last_value)
+      {
+        value = first_value;
+      }
+      else
+      {
+        ++value;
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// ++ operator.
+    //*************************************************************************
+    cyclic_value operator ++(int)
+    {
+      cyclic_value temp(*this);
+
+      operator++();
+
+      return temp;
+    }
+
+    //*************************************************************************
+    /// -- operator.
+    //*************************************************************************
+    cyclic_value& operator --()
+    {
+      if (value <= first_value)
+      {
+        value = last_value;
+      }
+      else
+      {
+        --value;
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// -- operator.
+    //*************************************************************************
+    cyclic_value operator --(int)
+    {
+      cyclic_value temp(*this);
+
+      operator--();
+
+      return temp;
+    }
+
+    //*************************************************************************
+    /// = operator.
+    //*************************************************************************
+    cyclic_value& operator =(T t)
+    {
+      set(t);
+      return *this;
+    }
+
+    //*************************************************************************
+    /// = operator.
+    //*************************************************************************
+    cyclic_value& operator =(const cyclic_value& other)
+    {
+      value       = other.value;
+      first_value = other.first_value;
+      last_value  = other.last_value;
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Gets the value.
+    //*************************************************************************
+    T get() const
+    {
+      return value;
+    }
+
+    //*************************************************************************
+    /// Gets the first value.
+    //*************************************************************************
+    T first() const
+    {
+      return first_value;
+    }
+
+    //*************************************************************************
+    /// Gets the last value.
+    //*************************************************************************
+    T last() const
+    {
+      return last_value;
+    }
+
+    //*************************************************************************
+    /// Swaps the values.
+    //*************************************************************************
+    void swap(cyclic_value<T, FIRST, LAST>& other)
+    {
+      std::swap(first_value, other.first_value);
+      std::swap(last_value, other.last_value);
+      std::swap(value, other.value);
+    }
+
+    //*************************************************************************
+    /// Swaps the values.
+    //*************************************************************************
+    friend void swap(cyclic_value<T, FIRST, LAST>& lhs, cyclic_value<T, FIRST, LAST>& rhs)
+    {
+      lhs.swap(rhs);
+    }
+
+    //*************************************************************************
+    /// Operator ==.
+    //*************************************************************************
+    friend bool operator == (const cyclic_value<T, FIRST, LAST>& lhs, const cyclic_value<T, FIRST, LAST>& rhs)
+    {
+      return (lhs.value       == rhs.value) &&
+             (lhs.first_value == rhs.first_value) &&
+             (lhs.last_value  == rhs.last_value);
+    }
+
+    //*************************************************************************
+    /// Operator !=.
+    //*************************************************************************
+    friend bool operator != (const cyclic_value<T, FIRST, LAST>& lhs, const cyclic_value<T, FIRST, LAST>& rhs)
+    {
+      return !(lhs == rhs);
+    }
+
+  private:
+
+    T value;       ///< The current value.
+    T first_value; ///< The first value in the range.
+    T last_value;  ///< The last value in the range.
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debounce.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,490 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_DEBOUNCE__
+#define __ETL_DEBOUNCE__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "static_assert.h"
+
+namespace etl
+{
+  namespace __private_debounce__
+  {
+    class debounce_base
+    {
+    public:
+
+      void add(bool sample)
+      {
+        state &= ~CHANGED;
+
+        // Changed from last time?
+        if (sample != bool((state & LAST) != 0))
+        {
+          count = START_COUNT;
+        }
+      }
+
+      //*************************************************************************
+      /// Gets the current debouncer change state.
+      ///\return 'true' if the debouncer has changed state.
+      //*************************************************************************
+      bool has_changed() const
+      {
+        return (state & CHANGED) != 0;
+      }
+
+      //*************************************************************************
+      /// Gets the current debouncer state.
+      ///\return 'true' if the debouncer is in the true state.
+      //*************************************************************************
+      bool is_set() const
+      {
+        return (state & CURRENT) != 0;
+      }
+
+      //*************************************************************************
+      /// Gets the debouncer hold state.
+      ///\return 'true' if the debouncer is in the hold state.
+      //*************************************************************************
+      bool is_held() const
+      {
+        return (state & HELD) != 0;
+      }
+
+      //*************************************************************************
+      /// Gets the debouncer repeat state.
+      ///\return 'true' if the debouncer is repeating.
+      //*************************************************************************
+      bool is_repeating() const
+      {
+        return (state & REPEATING) != 0;
+      }
+
+    protected:
+
+      //*************************************************************************
+      /// Constructor.
+      ///\param initial_state The initial state. Default = false.
+      //*************************************************************************
+      debounce_base(bool initial_state = false)
+        : state(initial_state ? (CURRENT | LAST) : 0),
+          count(START_COUNT)
+      {
+      }
+
+      enum
+      {
+        START_COUNT = 0
+      };
+
+      enum
+      {
+        CURRENT   = 1,
+        LAST      = 2,
+        HELD      = 4,
+        CHANGED   = 8,
+        REPEATING = 16
+      };
+
+      uint_least8_t state;
+
+      /// The state count.
+      uint16_t count;
+    };
+  }
+
+  //***************************************************************************
+  /// A class to debounce signals.
+  /// The state is decided over N samples, defined by the VALID_COUNT value.
+  /// If the samples are consistent for VALID_COUNT times then the debouncer state is defined.
+  /// If the samples change then the debouncer will change state after VALID_COUNT samples.
+  /// If the samples are true for a count of HOLD_COUNT then the debouncer input is 'held'.
+  /// The debouncer may be constructed in either state.
+  //***************************************************************************
+  template <const uint16_t VALID_COUNT = 0, const uint16_t HOLD_COUNT = 0, const uint16_t REPEAT_COUNT = 0>
+  class debounce : public __private_debounce__::debounce_base
+  {
+  private:
+
+      enum
+      {
+        VALID_THRESHOLD  = VALID_COUNT,
+        HOLD_THRESHOLD   = VALID_THRESHOLD + HOLD_COUNT,
+        REPEAT_THRESHOLD = HOLD_THRESHOLD + REPEAT_COUNT
+      };
+
+      using debounce_base::add;
+
+  public:
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param initial_state The initial state. Default = false.
+    //*************************************************************************
+    debounce(bool initial_state = false)
+      : debounce_base(initial_state)
+    {
+    }
+
+    //*************************************************************************
+    /// Adds a new sample.
+    /// Returns 'true' if the debouncer changes state from...
+    /// 1. Clear to Set.
+    /// 2. Set to Clear.
+    /// 3. Not Held to Held.
+    /// 4. Key repeats.
+    ///\param sample The new sample.
+    ///\return 'true' if the debouncer changed state.
+    //*************************************************************************
+    bool add(bool sample)
+    {
+      debounce_base::add(sample);
+
+      if (count < REPEAT_THRESHOLD)
+      {
+        ++count;
+
+        if (sample)
+        {
+          if (count == VALID_THRESHOLD)
+          {
+            // Set.
+            state |= CHANGED;
+            state |= CURRENT;
+          }
+          else if (count == HOLD_THRESHOLD)
+          {
+            // Held.
+            state |= CHANGED;
+            state |= HELD;
+          }
+          else if (count == REPEAT_THRESHOLD)
+          {
+            // Repeat.
+            state |= CHANGED;
+            state |= REPEATING;
+            count = HOLD_THRESHOLD;
+          }
+
+          state |= LAST;        
+        }
+        else
+        {
+          if (count == VALID_THRESHOLD)
+          {
+            // Clear.
+            state |= CHANGED;
+            state &= ~CURRENT;
+            state &= ~HELD;
+            state &= ~REPEATING;
+          }
+
+          state &= ~LAST;
+        }
+      }
+
+      return (state & CHANGED) != 0;
+    }
+  };
+  
+  template <const uint16_t VALID_COUNT, const uint16_t HOLD_COUNT>
+  class debounce<VALID_COUNT, HOLD_COUNT, 0> : public __private_debounce__::debounce_base
+  {
+  private:
+
+    enum
+    {
+      VALID_THRESHOLD = VALID_COUNT,
+      HOLD_THRESHOLD  = VALID_THRESHOLD + HOLD_COUNT
+    };
+
+    using debounce_base::add;
+
+  public:   
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param initial_state The initial state. Default = false.
+    //*************************************************************************
+    debounce(bool initial_state = false)
+      : debounce_base(initial_state)
+    {
+    }
+
+    //*************************************************************************
+    /// Adds a new sample.
+    /// Returns 'true' if the debouncer changes state from...
+    /// 1. Clear to Set.
+    /// 2. Set to Clear.
+    /// 3. Not Held to Held.
+    ///\param sample The new sample.
+    ///\return 'true' if the debouncer changed state.
+    //*************************************************************************
+    bool add(bool sample)
+    {
+      debounce_base::add(sample);
+
+      if (count < HOLD_THRESHOLD)
+      {
+        ++count;
+
+        if (sample)
+        {
+          if (count == VALID_THRESHOLD)
+          {
+            // Set.
+            state |= CHANGED;
+            state |= CURRENT;
+          }
+          else if (count == HOLD_THRESHOLD)
+          {
+            // Held.
+            state |= CHANGED;
+            state |= HELD;
+          }
+
+          state |= LAST;
+        }
+        else
+        {
+          if (count == VALID_THRESHOLD)
+          {
+            // Clear.
+            state |= CHANGED;
+            state &= ~CURRENT;
+            state &= ~HELD;
+            state &= ~REPEATING;
+          }
+
+          state &= ~LAST;
+        }
+      }
+
+      return (state & CHANGED) != 0;
+    }
+  };
+
+  template <const uint16_t VALID_COUNT>
+  class debounce<VALID_COUNT, 0, 0> : public __private_debounce__::debounce_base
+  {
+  private:
+
+    enum
+    {
+      VALID_THRESHOLD = VALID_COUNT
+    };
+    
+    using debounce_base::add;
+
+  public:
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param initial_state The initial state. Default = false.
+    //*************************************************************************
+    debounce(bool initial_state = false)
+      : debounce_base(initial_state)
+    {
+    }
+
+    //*************************************************************************
+    /// Adds a new sample.
+    /// Returns 'true' if the debouncer changes state from...
+    /// 1. Clear to Set.
+    /// 2. Set to Clear.
+    ///\param sample The new sample.
+    ///\return 'true' if the debouncer changed state.
+    //*************************************************************************
+    bool add(bool sample)
+    {
+      debounce_base::add(sample);
+
+      if (count < VALID_THRESHOLD)
+      {
+        ++count;
+
+        if (sample)
+        {
+          if (count == VALID_THRESHOLD)
+          {
+            // Set.
+            state |= CHANGED;
+            state |= CURRENT;
+          }
+
+          state |= LAST;
+        }
+        else
+        {
+          if (count == VALID_THRESHOLD)
+          {
+            // Clear.
+            state |= CHANGED;
+            state &= ~CURRENT;
+            state &= ~HELD;
+            state &= ~REPEATING;
+          }
+
+          state &= ~LAST;
+        }
+      }
+
+      return (state & CHANGED) != 0;
+    }
+  };
+
+  template <>
+  class debounce<0, 0, 0> : public __private_debounce__::debounce_base
+  {
+  public:
+
+    using debounce_base::add;
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param initial_state The initial state. Default = false.
+    //*************************************************************************
+    debounce()
+      : debounce_base(false),
+        valid_threshold(1),
+        hold_threshold(0),
+        repeat_threshold(0)
+    {
+    }
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param initial_state The initial state.
+    ///\param valid_count   The count for a valid state. Default = 1.
+    ///\param hold_count    The count after valid_count for a hold state. Default = 0.
+    ///\param repeat_count  The count after hold_count for a key repeat. Default = 0.
+    //*************************************************************************
+    debounce(bool initial_state, uint16_t valid_count = 1, uint16_t hold_count = 0, uint16_t repeat_count = 0)
+      : debounce_base(initial_state)
+    {
+      set(valid_count, hold_count, repeat_count);
+    }
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param initial_state The initial state. Default = false.
+    //*************************************************************************
+    void set(uint16_t valid_count, uint16_t hold_count = 0, uint16_t repeat_count = 0)
+    {
+      valid_threshold  = valid_count;
+      hold_threshold   = valid_threshold + hold_count;
+      repeat_threshold = hold_threshold + repeat_count;
+    }
+
+    //*************************************************************************
+    /// Adds a new sample.
+    /// Returns 'true' if the debouncer changes state from...
+    /// 1. Clear to Set.
+    /// 2. Set to Clear.
+    /// 3. Not Held to Held.
+    /// 4. Key repeats.
+    ///\param sample The new sample.
+    ///\return 'true' if the debouncer changed state.
+    //*************************************************************************
+    bool add(bool sample)
+    {
+      debounce_base::add(sample);
+
+      if (count < repeat_threshold)
+      {
+        ++count;
+
+        if (sample)
+        {
+          if (count == valid_threshold)
+          {
+            if (sample)
+            {
+              // Set.
+              state |= CHANGED;
+              state |= CURRENT;
+            }
+          }
+
+          if (hold_threshold != valid_threshold)
+          {
+            if ((count == hold_threshold) && sample)
+            {
+              // Held.
+              state |= CHANGED;
+              state |= HELD;
+            }
+          }
+
+          if (repeat_threshold != hold_threshold)
+          {
+            if ((count == repeat_threshold) && sample)
+            {
+              // Repeat.
+              state |= CHANGED;
+              state |= REPEATING;
+              count = hold_threshold;
+            }
+          }
+
+          state |= LAST;
+        }
+        else
+        {
+          if (count == valid_threshold)
+          {
+            // Clear.
+            state |= CHANGED;
+            state &= ~CURRENT;
+            state &= ~HELD;
+            state &= ~REPEATING;
+          }
+
+          state &= ~LAST;
+        }
+      }
+
+      return (state & CHANGED) != 0;
+    }
+
+  private:
+
+    uint16_t valid_threshold;
+    uint16_t hold_threshold;
+    uint16_t repeat_threshold;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debug_count.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,148 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_DEBUG_COUNT__
+#define __ETL_DEBUG_COUNT__
+
+#include <stdint.h>
+#include <assert.h>
+
+#include "platform.h"
+
+///\defgroup debug_count debug count
+///\ingroup utilities
+
+namespace etl
+{
+  //***************************************************************************
+  /// Used to count instances.
+  /// Asserts if the count is decremented below zero.
+  /// Asserts if the count is not zero when destructed.
+  /// Does nothing in a non-debug build.
+  ///\ingroup reference
+  //***************************************************************************
+  class debug_count
+  {
+  public:
+    
+#if defined(ETL_DEBUG)
+    inline debug_count()
+      : count(0)
+    {
+    }
+
+    inline ~debug_count()
+    {
+      assert(count == 0);
+    }
+
+    inline debug_count& operator ++()
+    {
+      ++count;
+      return *this;
+    }
+
+    inline debug_count& operator --()
+    {
+      --count;
+      assert(count >= 0);
+      return *this;
+    }
+
+    inline debug_count& operator +=(int32_t n)
+    {
+      count += n;
+      return *this;
+    }
+
+    inline debug_count& operator -=(int32_t n)
+    {
+      count -= n;
+      return *this;
+    }
+
+    inline operator int32_t()
+    {
+      return count;
+    }
+
+    inline void clear()
+    {
+      count = 0;
+    }
+
+  private:
+
+    int32_t count;
+#else
+    inline debug_count()
+    {
+    }
+
+    inline ~debug_count()
+    {
+    }
+
+    inline debug_count& operator ++()
+    {
+      return *this;
+    }
+
+    inline debug_count& operator --()
+    {
+      return *this;
+    }
+
+    inline debug_count& operator +=(int32_t /*n*/)
+    {
+      return *this;
+    }
+
+    inline debug_count& operator -=(int32_t /*n*/)
+    {
+      return *this;
+    }
+
+    inline operator int32_t()
+    {
+      return 0;
+    }
+
+    inline void clear()
+    {
+    }
+
+#endif
+  };
+}
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/deque.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,2157 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_DEQUE__
+#define __ETL_DEQUE__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <iterator>
+#include <algorithm>
+
+#include "platform.h"
+#include "container.h"
+#include "alignment.h"
+#include "array.h"
+#include "memory.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "debug_count.h"
+#include "algorithm.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#undef ETL_FILE
+#define ETL_FILE "1"
+
+//*****************************************************************************
+///\defgroup deque deque
+/// A double ended queue with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception base for deques
+  ///\ingroup deque
+  //***************************************************************************
+  class deque_exception : public etl::exception
+  {
+  public:
+
+    deque_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Deque full exception.
+  ///\ingroup deque
+  //***************************************************************************
+  class deque_full : public etl::deque_exception
+  {
+  public:
+
+    deque_full(string_type file_name_, numeric_type line_number_)
+      : etl::deque_exception(ETL_ERROR_TEXT("deque:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Deque empty exception.
+  ///\ingroup deque
+  //***************************************************************************
+  class deque_empty : public etl::deque_exception
+  {
+  public:
+
+    deque_empty(string_type file_name_, numeric_type line_number_)
+      : etl::deque_exception(ETL_ERROR_TEXT("deque:empty", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Deque out of bounds exception.
+  ///\ingroup deque
+  //***************************************************************************
+  class deque_out_of_bounds : public etl::deque_exception
+  {
+  public:
+
+    deque_out_of_bounds(string_type file_name_, numeric_type line_number_)
+      : etl::deque_exception(ETL_ERROR_TEXT("deque:bounds", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup vector
+  /// Deque incompatible type exception.
+  //***************************************************************************
+  class deque_incompatible_type : public deque_exception
+  {
+  public:
+
+    deque_incompatible_type(string_type file_name_, numeric_type line_number_)
+      : deque_exception(ETL_ERROR_TEXT("deque:type", ETL_FILE"D"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for all templated deque types.
+  ///\ingroup deque
+  //***************************************************************************
+  class deque_base
+  {
+  public:
+
+    typedef size_t size_type;
+
+    //*************************************************************************
+    /// Gets the current size of the deque.
+    ///\return The current size of the deque.
+    //*************************************************************************
+    size_type size() const
+    {
+      return current_size;
+    }
+
+    //*************************************************************************
+    /// Checks the 'empty' state of the deque.
+    ///\return <b>true</b> if empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return (current_size == 0);
+    }
+
+    //*************************************************************************
+    /// Checks the 'full' state of the deque.
+    ///\return <b>true</b> if full.
+    //*************************************************************************
+    bool full() const
+    {
+      return current_size == CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the deque.
+    ///\return The maximum size of the deque.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return max_size() - size();
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    deque_base(size_t max_size_, size_t buffer_size_)
+      : current_size(0),
+        CAPACITY(max_size_),
+        BUFFER_SIZE(buffer_size_)
+    {
+    }
+
+    size_type       current_size;     ///< The current number of elements in the deque.
+    const size_type CAPACITY;         ///< The maximum number of elements in the deque.
+    const size_type BUFFER_SIZE;      ///< The number of elements in the buffer.
+    etl::debug_count construct_count; ///< Internal debugging.
+  };
+
+  //***************************************************************************
+  /// The base class for all etl::deque classes.
+  ///\tparam T The type of values this deque should hold.
+  ///\ingroup deque
+  //***************************************************************************
+  template <typename T>
+  class ideque : public etl::deque_base
+  {
+  public:
+
+    typedef T        value_type;
+    typedef size_t   size_type;
+    typedef T&       reference;
+    typedef const T& const_reference;
+    typedef T*       pointer;
+    typedef const T* const_pointer;
+    typedef typename std::iterator_traits<pointer>::difference_type difference_type;
+
+  protected:
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+
+    //*************************************************************************
+    /// Test for an iterator.
+    //*************************************************************************
+    template <typename TIterator>
+    struct is_iterator : public etl::integral_constant<bool, !etl::is_integral<TIterator>::value && !etl::is_floating_point<TIterator>::value>
+    {
+    };
+
+  public:
+
+    //*************************************************************************
+    /// Iterator
+    //*************************************************************************
+    struct iterator : public std::iterator<std::random_access_iterator_tag, T>
+    {
+      friend class ideque;
+
+      //***************************************************
+      iterator()
+        : index(0),
+        p_deque(0),
+        p_buffer(0)
+      {
+      }
+
+      //***************************************************
+      iterator(const iterator& other)
+        : index(other.index),
+        p_deque(other.p_deque),
+        p_buffer(other.p_buffer)
+      {
+      }
+
+      //***************************************************
+      iterator& operator ++()
+      {
+        index = (static_cast<size_t>(index) == p_deque->BUFFER_SIZE - 1) ? 0 : index + 1;
+
+        return *this;
+      }
+
+      //***************************************************
+      iterator operator ++(int)
+      {
+        iterator previous(*this);
+        index = (static_cast<size_t>(index) == p_deque->BUFFER_SIZE - 1) ? 0 : index + 1;
+
+        return previous;
+      }
+
+      //***************************************************
+      iterator& operator +=(difference_type offset)
+      {
+        if (offset > 0)
+        {
+          index += offset;
+          index = (static_cast<size_t>(index) > p_deque->BUFFER_SIZE - 1) ? index - p_deque->BUFFER_SIZE : index;
+        }
+        else if (offset < 0)
+        {
+          operator -= (-offset);
+        }
+
+        return *this;
+      }
+
+      //***************************************************
+      iterator& operator -=(difference_type offset)
+      {
+        if (offset > 0)
+        {
+          index -= offset;
+          index = (index < 0) ? index + p_deque->BUFFER_SIZE : index;
+        }
+        else if (offset < 0)
+        {
+          operator += (-offset);
+        }
+
+        return *this;
+      }
+
+      //***************************************************
+      iterator& operator --()
+      {
+        index = (index == 0) ? p_deque->BUFFER_SIZE - 1 : index - 1;
+
+        return *this;
+      }
+
+      //***************************************************
+      iterator operator --(int)
+      {
+        iterator previous(*this);
+        index = (index == 0) ? p_deque->BUFFER_SIZE - 1 : index - 1;
+
+        return previous;
+      }
+
+      //***************************************************
+      reference operator *()
+      {
+        return p_buffer[index];
+      }
+
+      //***************************************************
+      const_reference operator *() const
+      {
+        return p_buffer[index];
+      }
+
+      //***************************************************
+      pointer operator ->()
+      {
+        return &p_buffer[index];
+      }
+
+      //***************************************************
+      const_pointer operator ->() const
+      {
+        return &p_buffer[index];
+      }
+
+      //***************************************************
+      bool operator <(const iterator& other) const
+      {
+        return ideque::distance(*this, other) > 0;
+      }
+
+      //***************************************************
+      friend iterator operator +(const iterator& lhs, difference_type offset)
+      {
+        iterator result(lhs);
+        result += offset;
+        return result;
+      }
+
+      //***************************************************
+      friend iterator operator -(const iterator& lhs, difference_type offset)
+      {
+        iterator result(lhs);
+        result -= offset;
+        return result;
+      }
+
+      //***************************************************
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.index == rhs.index;
+      }
+
+      //***************************************************
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+      //***************************************************
+      difference_type get_index() const
+      {
+        return index;
+      }
+
+      //***************************************************
+      ideque& get_deque() const
+      {
+        return *p_deque;
+      }
+
+      //***************************************************
+      pointer get_buffer() const
+      {
+        return p_buffer;
+      }
+
+      //***************************************************
+      void swap(iterator& other)
+      {
+        std::swap(index, other.index);
+      }
+
+    private:
+
+      //***************************************************
+      iterator(difference_type index_, ideque& the_deque, pointer p_buffer_)
+        : index(index_),
+          p_deque(&the_deque),
+          p_buffer(p_buffer_)
+      {
+      }
+
+      difference_type index;
+      ideque*         p_deque;
+      pointer         p_buffer;
+    };
+
+    //*************************************************************************
+    /// Const Iterator
+    //*************************************************************************
+    struct const_iterator : public std::iterator<std::random_access_iterator_tag, const T>
+    {
+      friend class ideque;
+
+      //***************************************************
+      const_iterator()
+        : index(0),
+        p_deque(0),
+        p_buffer(0)
+      {
+      }
+
+      //***************************************************
+      const_iterator(const const_iterator& other)
+        : index(other.index),
+        p_deque(other.p_deque),
+        p_buffer(other.p_buffer)
+      {
+      }
+
+      //***************************************************
+      const_iterator(const typename ideque::iterator& other)
+        : index(other.index),
+        p_deque(other.p_deque),
+        p_buffer(other.p_buffer)
+      {
+      }
+
+      //***************************************************
+      const_iterator& operator ++()
+      {
+        index = (static_cast<size_t>(index) == p_deque->BUFFER_SIZE - 1) ? 0 : index + 1;
+
+        return *this;
+      }
+
+      //***************************************************
+      const_iterator operator ++(int)
+      {
+        const_iterator previous(*this);
+        index = (static_cast<size_t>(index) == p_deque->BUFFER_SIZE - 1) ? 0 : index + 1;
+
+        return previous;
+      }
+
+      //***************************************************
+      const_iterator& operator +=(difference_type offset)
+      {
+        if (offset > 0)
+        {
+          index += offset;
+          index = (static_cast<size_t>(index) > p_deque->BUFFER_SIZE - 1) ? index - p_deque->BUFFER_SIZE : index;
+        }
+        else if (offset < 0)
+        {
+          operator -= (-offset);
+        }
+
+        return *this;
+      }
+
+      //***************************************************
+      const_iterator& operator -=(difference_type offset)
+      {
+        if (offset > 0)
+        {
+          index -= offset;
+          index = (index < 0) ? static_cast<size_t>(index) + p_deque->BUFFER_SIZE : index;
+        }
+        else if (offset < 0)
+        {
+          operator += (-offset);
+        }
+
+        return *this;
+      }
+
+      //***************************************************
+      const_iterator& operator --()
+      {
+        index = (index == 0) ? p_deque->BUFFER_SIZE - 1 : index - 1;
+
+        return *this;
+      }
+
+      //***************************************************
+      const_iterator operator --(int)
+      {
+        const_iterator previous(*this);
+        index = (index == 0) ? p_deque->BUFFER_SIZE - 1 : index - 1;
+
+        return previous;
+      }
+
+      //***************************************************
+      const_reference operator *() const
+      {
+        return p_buffer[index];
+      }
+
+      //***************************************************
+      const_pointer operator ->() const
+      {
+        return &p_buffer[index];
+      }
+
+      //***************************************************
+      bool operator <(const const_iterator& other) const
+      {
+        return ideque::distance(*this, other) > 0;
+      }
+
+      //***************************************************
+      friend const_iterator operator +(const const_iterator& lhs, difference_type offset)
+      {
+        const_iterator result(lhs);
+        result += offset;
+        return result;
+      }
+
+      //***************************************************
+      friend const_iterator operator -(const const_iterator& lhs, difference_type offset)
+      {
+        const_iterator result(lhs);
+        result -= offset;
+        return result;
+      }
+
+      //***************************************************
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.index == rhs.index;
+      }
+
+      //***************************************************
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+      //***************************************************
+      difference_type get_index() const
+      {
+        return index;
+      }
+
+      //***************************************************
+      ideque& get_deque() const
+      {
+        return *p_deque;
+      }
+
+      //***************************************************
+      pointer get_buffer() const
+      {
+        return p_buffer;
+      }
+
+      //***************************************************
+      void swap(const_iterator& other)
+      {
+        std::swap(index, other.index);
+      }
+
+    private:
+
+      //***************************************************
+      difference_type distance(difference_type firstIndex, difference_type index_)
+      {
+        if (index_ < firstIndex)
+        {
+          return p_deque->BUFFER_SIZE + index_ - firstIndex;
+        }
+        else
+        {
+          return index_ - firstIndex;
+        }
+      }
+
+      //***************************************************
+      const_iterator(difference_type index_, ideque& the_deque, pointer p_buffer_)
+        : index(index_),
+          p_deque(&the_deque),
+          p_buffer(p_buffer_)
+      {
+      }
+
+      difference_type index;
+      ideque*         p_deque;
+      pointer         p_buffer;
+    };
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+    //*************************************************************************
+    /// Assigns a range to the deque.
+    //*************************************************************************
+    template<typename TIterator>
+    typename etl::enable_if<is_iterator<TIterator>::value, void>::type
+      assign(TIterator range_begin, TIterator range_end)
+    {
+      initialise();
+
+      while (range_begin != range_end)
+      {
+        push_back(*range_begin++);
+      }
+    }
+
+    //*************************************************************************
+    /// Assigns 'n' copies of a value to the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full is 'n' is too large.
+    ///\param n     The number of copies to assign.
+    ///\param value The value to add.<
+    //*************************************************************************
+    void assign(size_type n, const value_type& value)
+    {
+      ETL_ASSERT(n <= CAPACITY, ETL_ERROR(deque_full));
+
+      initialise();
+
+      _begin.index = 0;
+      _end.index = 0;
+
+      while (n > 0)
+      {
+        create_element_back(value);
+        --n;
+      }
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the item at the index.
+    /// If asserts or exceptions are enabled, throws an etl::deque_out_of_bounds if the index is out of range.
+    ///\return A reference to the item at the index.
+    //*************************************************************************
+    reference at(size_t index)
+    {
+      ETL_ASSERT(index < current_size, ETL_ERROR(deque_out_of_bounds));
+
+      iterator result(_begin);
+      result += index;
+
+      return *result;
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the item at the index.
+    /// If asserts or exceptions are enabled, throws an etl::deque_out_of_bounds if the index is out of range.
+    ///\return A const reference to the item at the index.
+    //*************************************************************************
+    const_reference at(size_t index) const
+    {
+      ETL_ASSERT(index < current_size, ETL_ERROR(deque_out_of_bounds));
+
+      iterator result(_begin);
+      result += index;
+
+      return *result;
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the item at the index.
+    ///\return A reference to the item at the index.
+    //*************************************************************************
+    reference operator [](size_t index)
+    {
+      iterator result(_begin);
+      result += index;
+
+      return *result;
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the item at the index.
+    ///\return A const reference to the item at the index.
+    //*************************************************************************
+    const_reference operator [](size_t index) const
+    {
+      iterator result(_begin);
+      result += index;
+
+      return *result;
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the item at the front of the deque.
+    ///\return A reference to the item at the front of the deque.
+    //*************************************************************************
+    reference front()
+    {
+      return *_begin;
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the item at the front of the deque.
+    ///\return A const reference to the item at the front of the deque.
+    //*************************************************************************
+    const_reference front() const
+    {
+      return *_begin;
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the item at the back of the deque.
+    ///\return A reference to the item at the back of the deque.
+    //*************************************************************************
+    reference back()
+    {
+      return *(_end - 1);
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the item at the back of the deque.
+    ///\return A const reference to the item at the back of the deque.
+    //*************************************************************************
+    const_reference back() const
+    {
+      return *(_end - 1);
+    }
+
+    //*************************************************************************
+    /// Gets an iterator to the beginning of the deque.
+    //*************************************************************************
+    iterator begin()
+    {
+      return _begin;
+    }
+
+    //*************************************************************************
+    /// Gets a const iterator to the beginning of the deque.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return _begin;
+    }
+
+    //*************************************************************************
+    /// Gets a const iterator to the beginning of the deque.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return _begin;
+    }
+
+    //*************************************************************************
+    /// Gets an iterator to the end of the deque.
+    //*************************************************************************
+    iterator end()
+    {
+      return iterator(_end);
+    }
+
+    //*************************************************************************
+    /// Gets a const iterator to the end of the deque.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return iterator(_end);
+    }
+
+    //*************************************************************************
+    /// Gets a const iterator to the end of the deque.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(_end);
+    }
+
+    //*************************************************************************
+    /// Gets a reverse iterator to the end of the deque.
+    //*************************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(end());
+    }
+
+    //*************************************************************************
+    /// Gets a const reverse iterator to the end of the deque.
+    //*************************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(end());
+    }
+
+    //*************************************************************************
+    /// Gets a const reverse iterator to the end of the deque.
+    //*************************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(cend());
+    }
+
+    //*************************************************************************
+    /// Gets a reverse iterator to the beginning of the deque.
+    //*************************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(begin());
+    }
+
+    //*************************************************************************
+    /// Gets a const reverse iterator to the beginning of the deque.
+    //*************************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(begin());
+    }
+
+    //*************************************************************************
+    /// Gets a const reverse iterator to the beginning of the deque.
+    //*************************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(cbegin());
+    }
+
+    //*************************************************************************
+    /// Clears the deque.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*************************************************************************
+    /// Inserts data into the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full.
+    ///\param insert_position>The insert position.
+    ///\param value>The value to insert.
+    //*************************************************************************
+    iterator insert(const_iterator insert_position, const value_type& value)
+    {
+      iterator position(insert_position.index, *this, p_buffer);
+
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+
+      if (insert_position == begin())
+      {
+        create_element_front(value);
+        position = _begin;
+      }
+      else if (insert_position == end())
+      {
+        create_element_back(value);
+        position = _end - 1;
+      }
+      else
+      {
+        // Are we closer to the front?
+        if (std::distance(_begin, position) < std::distance(position, _end - 1))
+        {
+          // Construct the _begin.
+          create_element_front(*_begin);
+
+          // Move the values.
+          std::copy(_begin + 1, position, _begin);
+
+          // Write the new value.
+          *--position = value;
+        }
+        else
+        {
+          // Construct the _end.
+          create_element_back(*(_end - 1));
+
+          // Move the values.
+          std::copy_backward(position, _end - 2, _end - 1);
+
+          // Write the new value.
+          *position = value;
+        }
+      }
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// Emplaces data into the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full.
+    ///\param insert_position>The insert position.
+    //*************************************************************************
+    template <typename T1>
+    iterator emplace(const_iterator insert_position, const T1& value1)
+    {
+      iterator position(insert_position.index, *this, p_buffer);
+
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+
+      void* p;
+
+      if (insert_position == begin())
+      {
+        --_begin;
+        p = etl::addressof(*_begin);
+        ++current_size;
+        ++construct_count;
+        position = _begin;
+      }
+      else if (insert_position == end())
+      {
+        p = etl::addressof(*_end);
+        ++_end;
+        ++current_size;
+        ++construct_count;
+        position = _end - 1;
+      }
+      else
+      {
+        // Are we closer to the front?
+        if (std::distance(_begin, position) < std::distance(position, _end - 1))
+        {
+          // Construct the _begin.
+          create_element_front(*_begin);
+
+          // Move the values.
+          std::copy(_begin + 1, position, _begin);
+
+          // Write the new value.
+          --position;
+          (*position).~T();
+          p = etl::addressof(*position);
+        }
+        else
+        {
+          // Construct the _end.
+          create_element_back(*(_end - 1));
+
+          // Move the values.
+          std::copy_backward(position, _end - 2, _end - 1);
+
+          // Write the new value.
+          (*position).~T();
+          p = etl::addressof(*position);
+        }
+      }
+
+      ::new (p) T(value1);
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// Emplaces data into the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full.
+    ///\param insert_position>The insert position.
+    //*************************************************************************
+    template <typename T1, typename T2>
+    iterator emplace(const_iterator insert_position, const T1& value1, const T2& value2)
+    {
+      iterator position(insert_position.index, *this, p_buffer);
+
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+
+      void* p;
+
+      if (insert_position == begin())
+      {
+        --_begin;
+        p = etl::addressof(*_begin);
+        ++current_size;
+        ++construct_count;
+        position = _begin;
+      }
+      else if (insert_position == end())
+      {
+        p = etl::addressof(*_end);
+        ++_end;
+        ++current_size;
+        ++construct_count;
+        position = _end - 1;
+      }
+      else
+      {
+        // Are we closer to the front?
+        if (std::distance(_begin, position) < std::distance(position, _end - 1))
+        {
+          // Construct the _begin.
+          create_element_front(*_begin);
+
+          // Move the values.
+          std::copy(_begin + 1, position, _begin);
+
+          // Write the new value.
+          --position;
+          (*position).~T();
+          p = etl::addressof(*position);
+        }
+        else
+        {
+          // Construct the _end.
+          create_element_back(*(_end - 1));
+
+          // Move the values.
+          std::copy_backward(position, _end - 2, _end - 1);
+
+          // Write the new value.
+          (*position).~T();
+          p = etl::addressof(*position);
+        }
+      }
+
+      ::new (p) T(value1, value2);
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// Emplaces data into the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full.
+    ///\param insert_position>The insert position.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3>
+    iterator emplace(const_iterator insert_position, const T1& value1, const T2& value2, const T3& value3)
+    {
+      iterator position(insert_position.index, *this, p_buffer);
+
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+
+      void* p;
+
+      if (insert_position == begin())
+      {
+        --_begin;
+        p = etl::addressof(*_begin);
+        ++current_size;
+        ++construct_count;
+        position = _begin;
+      }
+      else if (insert_position == end())
+      {
+        p = etl::addressof(*_end);
+        ++_end;
+        ++current_size;
+        ++construct_count;
+        position = _end - 1;
+      }
+      else
+      {
+        // Are we closer to the front?
+        if (std::distance(_begin, position) < std::distance(position, _end - 1))
+        {
+          // Construct the _begin.
+          create_element_front(*_begin);
+
+          // Move the values.
+          std::copy(_begin + 1, position, _begin);
+
+          // Write the new value.
+          --position;
+          (*position).~T();
+          p = etl::addressof(*position);
+        }
+        else
+        {
+          // Construct the _end.
+          create_element_back(*(_end - 1));
+
+          // Move the values.
+          std::copy_backward(position, _end - 2, _end - 1);
+
+          // Write the new value.
+          (*position).~T();
+          p = etl::addressof(*position);
+        }
+      }
+
+      ::new (p) T(value1, value2, value3);
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// Emplaces data into the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full.
+    ///\param insert_position>The insert position.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    iterator emplace(const_iterator insert_position, const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+      iterator position(insert_position.index, *this, p_buffer);
+
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+
+      void* p;
+
+      if (insert_position == begin())
+      {
+        --_begin;
+        p = etl::addressof(*_begin);
+        ++current_size;
+        ++construct_count;
+        position = _begin;
+      }
+      else if (insert_position == end())
+      {
+        p = etl::addressof(*_end);
+        ++_end;
+        ++current_size;
+        ++construct_count;
+        position = _end - 1;
+      }
+      else
+      {
+        // Are we closer to the front?
+        if (std::distance(_begin, position) < std::distance(position, _end - 1))
+        {
+          // Construct the _begin.
+          create_element_front(*_begin);
+
+          // Move the values.
+          std::copy(_begin + 1, position, _begin);
+
+          // Write the new value.
+          --position;
+          (*position).~T();
+          p = etl::addressof(*position);
+        }
+        else
+        {
+          // Construct the _end.
+          create_element_back(*(_end - 1));
+
+          // Move the values.
+          std::copy_backward(position, _end - 2, _end - 1);
+
+          // Write the new value.
+          (*position).~T();
+          p = etl::addressof(*position);
+        }
+      }
+
+      ::new (p) T(value1, value2, value3, value4);
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// Inserts 'n' copies of a value into the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full.
+    ///\param insert_position The insert position.
+    ///\param n               The number of values to insert.
+    ///\param value           The value to insert.
+    //*************************************************************************
+    iterator insert(const_iterator insert_position, size_type n, const value_type& value)
+    {
+      iterator position;
+
+      ETL_ASSERT((current_size + n) <= CAPACITY, ETL_ERROR(deque_full));
+
+      if (insert_position == begin())
+      {
+        for (size_t i = 0; i < n; ++i)
+        {
+          create_element_front(value);
+        }
+
+        position = _begin;
+      }
+      else if (insert_position == end())
+      {
+        for (size_t i = 0; i < n; ++i)
+        {
+          create_element_back(value);
+        }
+
+        position = _end - n;
+      }
+      else
+      {
+        // Non-const insert iterator.
+        position = iterator(insert_position.index, *this, p_buffer);
+
+        // Are we closer to the front?
+        if (distance(_begin, insert_position) <= difference_type(current_size / 2))
+        {
+          size_t n_insert = n;
+          size_t n_move = std::distance(begin(), position);
+          size_t n_create_copy = std::min(n_insert, n_move);
+          size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+          size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+          size_t n_copy_old = n_move - n_create_copy;
+
+          // Remember the original start.
+          iterator from = _begin + n_create_copy - 1;
+          iterator to;
+
+          // Create new.
+          for (size_t i = 0; i < n_create_new; ++i)
+          {
+            create_element_front(value);
+          }
+
+          // Create copy.
+          for (size_t i = 0; i < n_create_copy; ++i)
+          {
+            create_element_front(*from--);
+          }
+
+          // Copy old.
+          from = position - n_copy_old;
+          to = _begin + n_create_copy;
+          etl::copy_n(from, n_copy_old, to);
+
+          // Copy new.
+          to = position - n_create_copy;
+          std::fill_n(to, n_copy_new, value);
+
+          position = _begin + n_move;
+        }
+        else
+        {
+          size_t n_insert = n;
+          size_t n_move = std::distance(position, end());
+          size_t n_create_copy = std::min(n_insert, n_move);
+          size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+          size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+          size_t n_copy_old = n_move - n_create_copy;
+
+          // Create new.
+          for (size_t i = 0; i < n_create_new; ++i)
+          {
+            create_element_back(value);
+          }
+
+          // Create copy.
+          const_iterator from = position + n_copy_old;
+
+          for (size_t i = 0; i < n_create_copy; ++i)
+          {
+            create_element_back(*from++);
+          }
+
+          // Copy old.
+          std::copy_backward(position, position + n_copy_old, position + n_insert + n_copy_old);
+
+          // Copy new.
+          std::fill_n(position, n_copy_new, value);
+        }
+      }
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// Inserts a range into the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_empty if the deque is full.
+    ///\param insert_position>The insert position.
+    ///\param range_begin The beginning of the range to insert.
+    ///\param range_end   The end of the range to insert.
+    //*************************************************************************
+    template<typename TIterator>
+    typename enable_if<is_iterator<TIterator>::value, iterator>::type
+      insert(const_iterator insert_position, TIterator range_begin, TIterator range_end)
+    {
+      iterator position;
+
+      difference_type n = std::distance(range_begin, range_end);
+
+      ETL_ASSERT((current_size + n) <= CAPACITY, ETL_ERROR(deque_full));
+
+      if (insert_position == begin())
+      {
+        create_element_front(n, range_begin);
+
+        position = _begin;
+      }
+      else if (insert_position == end())
+      {
+        for (difference_type i = 0; i < n; ++i)
+        {
+          create_element_back(*range_begin++);
+        }
+
+        position = _end - n;
+      }
+      else
+      {
+        // Non-const insert iterator.
+        position = iterator(insert_position.index, *this, p_buffer);
+
+        // Are we closer to the front?
+        if (distance(_begin, insert_position) < difference_type(current_size / 2))
+        {
+          size_t n_insert = n;
+          size_t n_move = std::distance(begin(), position);
+          size_t n_create_copy = std::min(n_insert, n_move);
+          size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+          size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+          size_t n_copy_old = n_move - n_create_copy;
+
+          // Remember the original start.
+          iterator from;
+          iterator to;
+
+          // Create new.
+          create_element_front(n_create_new, range_begin);
+
+          // Create copy.
+          create_element_front(n_create_copy, _begin + n_create_new);
+
+          // Copy old.
+          from = position - n_copy_old;
+          to = _begin + n_create_copy;
+          etl::copy_n(from, n_copy_old, to);
+
+          // Copy new.
+          to = position - n_create_copy;
+          range_begin += n_create_new;
+          etl::copy_n(range_begin, n_copy_new, to);
+
+          position = _begin + n_move;
+        }
+        else
+        {
+          size_t n_insert = n;
+          size_t n_move = std::distance(position, end());
+          size_t n_create_copy = std::min(n_insert, n_move);
+          size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0;
+          size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0;
+          size_t n_copy_old = n_move - n_create_copy;
+
+          // Create new.
+          TIterator item = range_begin + (n - n_create_new);
+          for (size_t i = 0; i < n_create_new; ++i)
+          {
+            create_element_back(*item++);
+          }
+
+          // Create copy.
+          const_iterator from = position + n_copy_old;
+
+          for (size_t i = 0; i < n_create_copy; ++i)
+          {
+            create_element_back(*from++);
+          }
+
+          // Copy old.
+          std::copy_backward(position, position + n_copy_old, position + n_insert + n_copy_old);
+
+          // Copy new.
+          item = range_begin;
+          etl::copy_n(item, n_copy_new, position);
+        }
+      }
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// Erase an item.
+    /// If asserts or exceptions are enabled, throws an etl::deque_out_of_bounds if the position is out of range.
+    ///\param erase_position The position to erase.
+    //*************************************************************************
+    iterator erase(const_iterator erase_position)
+    {
+      iterator position(erase_position.index, *this, p_buffer);
+
+      ETL_ASSERT(distance(position) <= difference_type(current_size), ETL_ERROR(deque_out_of_bounds));
+
+      if (position == _begin)
+      {
+        destroy_element_front();
+        position = begin();
+      }
+      else if (position == _end - 1)
+      {
+        destroy_element_back();
+        position = end();
+      }
+      else
+      {
+        // Are we closer to the front?
+        if (distance(_begin, position) < difference_type(current_size / 2))
+        {
+          std::copy_backward(_begin, position, position + 1);
+          destroy_element_front();
+          ++position;
+        }
+        else
+        {
+          std::copy(position + 1, _end, position);
+          destroy_element_back();
+        }
+      }
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// erase a range.
+    /// If asserts or exceptions are enabled, throws an etl::deque_out_of_bounds if the iterators are out of range.
+    ///\param range_begin The beginning of the range to erase.
+    ///\param range_end   The end of the range to erase.
+    //*************************************************************************
+    iterator erase(const_iterator range_begin, const_iterator range_end)
+    {
+      iterator position(range_begin.index, *this, p_buffer);
+
+      ETL_ASSERT((distance(range_begin) <= difference_type(current_size)) && (distance(range_end) <= difference_type(current_size)), ETL_ERROR(deque_out_of_bounds));
+
+      // How many to erase?
+      size_t length = std::distance(range_begin, range_end);
+
+      // At the beginning?
+      if (position == _begin)
+      {
+        for (size_t i = 0; i < length; ++i)
+        {
+          destroy_element_front();
+        }
+
+        position = begin();
+      }
+      // At the end?
+      else if (position == _end - length)
+      {
+        for (size_t i = 0; i < length; ++i)
+        {
+          destroy_element_back();
+        }
+
+        position = end();
+      }
+      else
+      {
+        // Copy the smallest number of items.
+        // Are we closer to the front?
+        if (distance(_begin, position) < difference_type(current_size / 2))
+        {
+          // Move the items.
+          std::copy_backward(_begin, position, position + length);
+
+          for (size_t i = 0; i < length; ++i)
+          {
+            destroy_element_front();
+          }
+
+          position += length;
+        }
+        else
+          // Must be closer to the back.
+        {
+          // Move the items.
+          std::copy(position + length, _end, position);
+
+          for (size_t i = 0; i < length; ++i)
+          {
+            destroy_element_back();
+          }
+        }
+      }
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// Adds an item to the back of the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+    ///\param item The item to push to the deque.
+    //*************************************************************************
+    void push_back(parameter_t item)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+      create_element_back(item);
+    }
+
+    //*************************************************************************
+    /// Adds one to the front of the deque and returns a reference to the new element.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+    ///\return A reference to the item to assign to.
+    //*************************************************************************
+    reference push_back()
+    {
+      reference r = *_end;
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+      create_element_back();
+
+      return r;
+    }
+
+    //*************************************************************************
+    /// Emplaces an item to the back of the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+    //*************************************************************************
+    template <typename T1>
+    void emplace_back(const T1& value1)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+
+      ::new (&(*_end)) T(value1);
+      ++_end;
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*************************************************************************
+    /// Emplaces an item to the back of the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+    //*************************************************************************
+    template <typename T1, typename T2>
+    void emplace_back(const T1& value1, const T2& value2)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+
+      ::new (&(*_end)) T(value1, value2);
+      ++_end;
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*************************************************************************
+    /// Emplaces an item to the back of the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3>
+    void emplace_back(const T1& value1, const T2& value2, const T3& value3)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+
+      ::new (&(*_end)) T(value1, value2, value3);
+      ++_end;
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*************************************************************************
+    /// Emplaces an item to the back of the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    void emplace_back(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+
+      ::new (&(*_end)) T(value1, value2, value3, value4);
+      ++_end;
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*************************************************************************
+    /// Removes the oldest item from the deque.
+    //*************************************************************************
+    void pop_back()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(deque_empty));
+#endif
+      destroy_element_back();
+    }
+
+    //*************************************************************************
+    /// Adds an item to the front of the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+    ///\param item The item to push to the deque.
+    //*************************************************************************
+    void push_front(parameter_t item)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+      create_element_front(item);
+    }
+
+    //*************************************************************************
+    /// Adds one to the front of the deque and returns a reference to the new element.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+    ///\return A reference to the item to assign to.
+    //*************************************************************************
+    reference push_front()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+      create_element_front();
+
+      return *_begin;
+    }
+
+    //*************************************************************************
+    /// Emplaces an item to the front of the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+    //*************************************************************************
+    template <typename T1>
+    void emplace_front(const T1& value1)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+
+      --_begin;
+      ::new (&(*_begin)) T(value1);
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*************************************************************************
+    /// Emplaces an item to the front of the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+    //*************************************************************************
+    template <typename T1, typename T2>
+    void emplace_front(const T1& value1, const T2& value2)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+
+      --_begin;
+      ::new (&(*_begin)) T(value1, value2);
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*************************************************************************
+    /// Emplaces an item to the front of the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3>
+    void emplace_front(const T1& value1, const T2& value2, const T3& value3)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+
+      --_begin;
+      ::new (&(*_begin)) T(value1, value2, value3);
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*************************************************************************
+    /// Emplaces an item to the front of the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    void emplace_front(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(deque_full));
+#endif
+
+      --_begin;
+      ::new (&(*_begin)) T(value1, value2, value3, value4);
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*************************************************************************
+    /// Removes the oldest item from the deque.
+    //*************************************************************************
+    void pop_front()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(deque_empty));
+#endif
+      destroy_element_front();
+    }
+
+    //*************************************************************************
+    /// Resizes the deque.
+    /// If asserts or exceptions are enabled, throws an etl::deque_full is 'new_size' is too large.
+    ///\param new_size The new size of the deque.
+    ///\param value   The value to assign if the new size is larger. Default = Default constructed value.
+    //*************************************************************************
+    void resize(size_t new_size, const value_type& value = value_type())
+    {
+      ETL_ASSERT(new_size <= CAPACITY, ETL_ERROR(deque_out_of_bounds));
+
+      // Make it smaller?
+      if (new_size < current_size)
+      {
+        while (current_size > new_size)
+        {
+          destroy_element_back();
+        }
+      }
+      // Make it larger?
+      else if (new_size > current_size)
+      {
+        size_t count = new_size - current_size;
+
+        for (size_t i = 0; i < count; ++i)
+        {
+          create_element_back(value);
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// - operator for iterator
+    //*************************************************************************
+    friend difference_type operator -(const iterator& lhs, const iterator& rhs)
+    {
+      return distance(rhs, lhs);
+    }
+
+    //*************************************************************************
+    /// - operator for const_iterator
+    //*************************************************************************
+    friend difference_type operator -(const const_iterator& lhs, const const_iterator& rhs)
+    {
+      return distance(rhs, lhs);
+    }
+
+    //*************************************************************************
+    /// - operator for reverse_iterator
+    //*************************************************************************
+    friend difference_type operator -(const reverse_iterator& lhs, const reverse_iterator& rhs)
+    {
+      return distance(lhs.base(), rhs.base());
+    }
+
+    //*************************************************************************
+    /// - operator for const_reverse_iterator
+    //*************************************************************************
+    friend difference_type operator -(const const_reverse_iterator& lhs, const const_reverse_iterator& rhs)
+    {
+      return distance(lhs.base(), rhs.base());
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    ideque& operator =(const ideque& rhs)
+    {
+      if (&rhs != this)
+      {
+        assign(rhs.begin(), rhs.end());
+      }
+
+      return *this;
+    }
+
+#ifdef ETL_IDEQUE_REPAIR_ENABLE
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    virtual void repair() = 0;
+#endif
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    ideque(pointer p_buffer_, size_t max_size_, size_t buffer_size_)
+      : deque_base(max_size_, buffer_size_),
+        p_buffer(p_buffer_)
+    {
+    }
+
+    //*********************************************************************
+    /// Initialise the deque.
+    //*********************************************************************
+    void initialise()
+    {
+      while (current_size > 0)
+      {
+        destroy_element_back();
+      }
+
+      _begin = iterator(0, *this, p_buffer);
+      _end   = iterator(0, *this, p_buffer);
+    }
+
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    void repair(pointer p_buffer_)
+    {
+      p_buffer = p_buffer_;
+
+      _begin = iterator(_begin.index, *this, p_buffer);
+      _end   = iterator(_end.index,   *this, p_buffer);
+    }
+
+    iterator _begin;   ///Iterator to the _begin item in the deque.
+    iterator _end;     ///Iterator to the _end item in the deque.
+    pointer  p_buffer; ///The buffer for the deque.
+
+  private:
+
+    //*********************************************************************
+    /// Create a new element with a default value at the front.
+    //*********************************************************************
+    void create_element_front()
+    {
+      --_begin;
+      ::new (&(*_begin)) T();
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*********************************************************************
+    /// Create a new elements from a range at the front.
+    //*********************************************************************
+    template <typename TIterator>
+    void create_element_front(size_t n, TIterator from)
+    {
+      if (n == 0)
+      {
+        return;
+      }
+
+      if (!empty())
+      {
+        --_begin;
+        --n;
+      }
+
+      if (n > 0)
+      {
+        _begin -= n;
+      }
+
+      iterator item = _begin;
+
+      do
+      {
+        ::new (&(*item++)) T(*from);
+        ++from;
+        ++current_size;
+        ++construct_count;
+      } while (n-- != 0);
+    }
+
+    //*********************************************************************
+    /// Create a new element with a default value at the back.
+    //*********************************************************************
+    void create_element_back()
+    {
+      ::new (&(*_end)) T();
+      ++_end;
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*********************************************************************
+    /// Create a new element with a default value at the front.
+    //*********************************************************************
+    void create_element_front(parameter_t value)
+    {
+      --_begin;
+      ::new (&(*_begin)) T(value);
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*********************************************************************
+    /// Create a new element with a value at the back
+    //*********************************************************************
+    void create_element_back(parameter_t value)
+    {
+      ::new (&(*_end)) T(value);
+      ++_end;
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*********************************************************************
+    /// Destroy an element at the front.
+    //*********************************************************************
+    void destroy_element_front()
+    {
+      (*_begin).~T();
+      --current_size;
+      --construct_count;
+      ++_begin;
+    }
+
+    //*********************************************************************
+    /// Destroy an element at the back.
+    //*********************************************************************
+    void destroy_element_back()
+    {
+      --_end;
+      (*_end).~T();
+      --current_size;
+      --construct_count;
+    }
+
+    //*************************************************************************
+    /// Measures the distance between two iterators.
+    //*************************************************************************
+    template <typename TIterator1, typename TIterator2>
+    static difference_type distance(const TIterator1& range_begin, const TIterator2& range_end)
+    {
+      difference_type distance1 = distance(range_begin);
+      difference_type distance2 = distance(range_end);
+
+      return distance2 - distance1;
+    }
+
+    //*************************************************************************
+    /// Measures the distance from the _begin iterator to the specified iterator.
+    //*************************************************************************
+    template <typename TIterator>
+    static difference_type distance(const TIterator& other)
+    {
+      const difference_type index = other.get_index();
+      const difference_type reference_index = other.get_deque()._begin.index;
+      const size_t buffer_size = other.get_deque().BUFFER_SIZE;
+
+      if (index < reference_index)
+      {
+        return buffer_size + index - reference_index;
+      }
+      else
+      {
+        return index - reference_index;
+      }
+    }
+
+    // Disable copy construction.
+    ideque(const ideque&);
+  };
+
+  //***************************************************************************
+  /// A fixed capacity double ended queue.
+  ///\note The deque allocates one more element than the specified maximum size.
+  ///\tparam T         The type of items this deque holds.
+  ///\tparam MAX_SIZE_ The capacity of the deque
+  ///\ingroup deque
+  //***************************************************************************
+  template <typename T, const size_t MAX_SIZE_>
+  class deque : public etl::ideque<T>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+  private:
+
+    static const size_t BUFFER_SIZE = MAX_SIZE + 1;
+
+  public:
+
+    typedef T        value_type;
+    typedef T*       pointer;
+    typedef const T* const_pointer;
+    typedef T&       reference;
+    typedef const T& const_reference;
+    typedef size_t   size_type;
+    typedef typename std::iterator_traits<pointer>::difference_type difference_type;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    deque()
+      : etl::ideque<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, BUFFER_SIZE)
+    {
+      etl::ideque<T>::initialise();
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~deque()
+    {
+      etl::ideque<T>::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    deque(const deque& other)
+      : etl::ideque<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, BUFFER_SIZE)
+    {
+      if (this != &other)
+      {
+        etl::ideque<T>::assign(other.begin(), other.end());
+      }
+    }
+
+    //*************************************************************************
+    /// Assigns data to the deque.
+    //*************************************************************************
+    template <typename TIterator>
+    deque(TIterator begin_, TIterator end_)
+      : etl::ideque<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, BUFFER_SIZE)
+    {
+      etl::ideque<T>::assign(begin_, end_);
+    }
+
+    //*************************************************************************
+    /// Assigns data to the deque.
+    //*************************************************************************
+    explicit deque(size_t n, typename etl::ideque<T>::parameter_t value = value_type())
+      : etl::ideque<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, BUFFER_SIZE)
+    {
+      etl::ideque<T>::assign(n, value);
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    deque& operator =(const deque& rhs)
+    {
+      if (&rhs != this)
+      {
+        etl::ideque<T>::assign(rhs.begin(), rhs.end());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    void repair()
+    {
+#if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED
+      ETL_ASSERT(std::is_trivially_copyable<T>::value, ETL_ERROR(etl::deque_incompatible_type));
+#endif
+
+      etl::ideque<T>::repair(reinterpret_cast<T*>(&buffer[0]));
+    }
+
+  private:
+
+    /// The uninitialised buffer of T used in the deque.
+    typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[BUFFER_SIZE];
+  };
+}
+
+//***************************************************************************
+/// Equal operator.
+///\param lhs  Reference to the _begin deque.
+///\param rhs  Reference to the second deque.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+///\ingroup deque
+//***************************************************************************
+template <typename T>
+bool operator ==(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs)
+{
+  return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//***************************************************************************
+/// Not equal operator.
+///\param lhs  Reference to the _begin deque.
+///\param rhs  Reference to the second deque.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+///\ingroup deque
+//***************************************************************************
+template <typename T>
+bool operator !=(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs)
+{
+  return !(lhs == rhs);
+}
+
+//***************************************************************************
+/// Less than operator.
+///\param lhs  Reference to the _begin deque.
+///\param rhs  Reference to the second deque.
+///\return <b>true</b> if the _begin deque is lexicographically less than the second, otherwise <b>false</b>
+///\ingroup deque
+//***************************************************************************
+template <typename T>
+bool operator <(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs)
+{
+  return std::lexicographical_compare(lhs.begin(),
+    lhs.end(),
+    rhs.begin(),
+    rhs.end());
+}
+
+//***************************************************************************
+/// Less than or equal operator.
+///\param lhs  Reference to the _begin deque.
+///\param rhs  Reference to the second deque.
+///\return <b>true</b> if the _begin deque is lexicographically less than or equal to the second, otherwise <b>false</b>
+///\ingroup deque
+//***************************************************************************
+template <typename T>
+bool operator <=(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs)
+{
+  return !(lhs > rhs);
+}
+
+//***************************************************************************
+/// Greater than operator.
+///\param lhs  Reference to the _begin deque.
+///\param rhs  Reference to the second deque.
+///\return <b>true</b> if the _begin deque is lexicographically greater than the second, otherwise <b>false</b>
+///\ingroup deque
+//***************************************************************************
+template <typename T>
+bool operator >(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs)
+{
+  return (rhs < lhs);
+}
+
+//***************************************************************************
+/// Greater than or equal operator.
+///\param "lhs  Reference to the _begin deque.
+///\param "rhs  Reference to the second deque.
+///\return <b>true</b> if the _begin deque is lexicographically greater than or equal to the second, otherwise <b>false</b>
+///\ingroup deque
+//***************************************************************************
+template <typename T>
+bool operator >=(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs)
+{
+  return !(lhs < rhs);
+}
+
+#undef ETL_FILE
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doxygen.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,56 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+///\defgroup etl Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+///\defgroup containers Containers
+///\ingroup etl
+
+///\defgroup utilities Utilities
+/// A set of utility templates.
+///\ingroup etl
+
+///\defgroup maths Maths
+/// A set of mathematical templates.
+///\ingroup etl
+
+///\defgroup patterns Patterns
+/// A set of templated design patterns.
+///\ingroup etl
+
+///\defgroup crc CRC
+/// A set of CRC calculations
+///\ingroup maths
+
+///\ingroup etl
+namespace etl {}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ecl_user.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,49 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ECL_USER__
+#define __ECL_USER__
+
+#include <stdint.h>
+
+#if defined(_MSC_VER)
+  #include <Windows.h>
+
+  #define ECL_TIMER_TIMER_SEMAPHORE       uint32_t
+  #define ECL_TIMER_DISABLE_PROCESSING(x) InterlockedIncrement((volatile long*)&x)
+  #define ECL_TIMER_ENABLE_PROCESSING(x)  InterlockedDecrement((volatile long*)&x)
+  #define ECL_TIMER_PROCESSING_ENABLED(x) (InterlockedAdd((volatile long*)&x, 0) == 0)
+#else
+  #define ECL_TIMER_TIMER_SEMAPHORE       uint32_t
+  #define ECL_TIMER_DISABLE_PROCESSING(x) __sync_fetch_and_add(&x, 1)
+  #define ECL_TIMER_ENABLE_PROCESSING(x)  __sync_fetch_and_sub(&x, 1)
+  #define ECL_TIMER_PROCESSING_ENABLED(x) (__sync_fetch_and_add(&x, 0) == 0)
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/endianness.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,93 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_ENDIAN__
+#define __ETL_ENDIAN__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "enum_type.h"
+
+///\defgroup endian endian
+/// Constants & utilities for endianess
+///\ingroup utilities
+
+namespace etl
+{
+  //***************************************************************************
+  /// Constants to denote endianness of operations.
+  ///\ingroup endian
+  //***************************************************************************
+  struct endian
+  {
+    enum enum_type
+    {
+      little,
+      big,
+      native
+    };
+
+    ETL_DECLARE_ENUM_TYPE(endian, int)
+    ETL_ENUM_TYPE(little, "little")
+    ETL_ENUM_TYPE(big,    "big")
+    ETL_ENUM_TYPE(native, "native")
+    ETL_END_ENUM_TYPE
+  };
+
+  //***************************************************************************
+  /// Checks the endianness of the platform.
+  ///\ingroup endian
+  //***************************************************************************
+  struct endianness
+  {
+    endianness()
+      : ETL_ENDIAN_TEST(0x0011223344556677)
+    {
+    }
+
+    endian operator ()() const
+    {
+      return endian(*this);
+    }
+
+    operator endian() const
+    {
+      return (*reinterpret_cast<const uint32_t*>(&ETL_ENDIAN_TEST) == 0x44556677) ? endian::little : endian::big;
+    }
+
+  private:
+
+    const uint64_t ETL_ENDIAN_TEST;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/enum_type.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,119 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_ENUM_TYPE__
+#define __ETL_ENUM_TYPE__
+
+#include "platform.h"
+
+///\defgroup enum_type enum_type
+/// Smart enumerations.<br>
+/// A method of declaring enumerations that allow grouping within a structure.
+/// Avoids the problem of clashing names that can occur with standard enumerations.
+/// One way to think of the code is as a type with built-in constants and an optional conversion to a string.<br><br>
+/// <b>Declaring the enumeration.</b>
+///\code
+/// struct CompassDirection
+/// {
+///   enum enum_type
+///   {
+///     North = 0,
+///     South = 180,
+///     East  = 90,
+///     West  = 270
+///   };
+///
+///   ETL_DECLARE_ENUM_TYPE(CompassDirection, int)
+///   ETL_ENUM_TYPE(North, "North")
+///   ETL_ENUM_TYPE(South, "South")
+///   ETL_ENUM_TYPE(East,  "East")
+///   ETL_ENUM_TYPE(West,  "West")
+///   ETL_END_ENUM_TYPE
+/// };
+///\endcode
+/// <b>Using the enumeration.</b>
+///\code
+/// CompassDirection direction;          // Default construction.
+///
+/// direction = CompassDirection::North; // Assignment from an enumeration constant;
+///
+/// int value = direction;               // Implicit conversion to 'int'.
+///
+/// direction = CompassDirection(value); // Explicit conversion from 'int'.
+///
+/// direction = CompassDirection(3);     // Explicit conversion from an invalid value. This unfortunately cannot be avoided. Caveat emptor!
+///
+/// direction = value;                   // Implicit conversion from 'int'. **** Compilation error ****
+///
+/// std::cout << "Direction = " << direction.c_str(); // Prints "Direction = North"
+///\endcode
+/// If a conversion to a string is not required then the 'ETL_ENUM_TYPE' declaration may be omitted.
+/// In that case the c_str() function will return a "?". This will also be the case for any
+/// enumeration value that does not have an ETL_ENUM_TYPE entry.
+///\ingroup utilities
+
+//*****************************************************************************
+// The declaration of the member functions and the first section of the 'c_str' function.
+//*****************************************************************************
+#define ETL_DECLARE_ENUM_TYPE(TypeName, ValueType) \
+  typedef ValueType value_type; \
+	TypeName() {} \
+	TypeName(const TypeName &other) : value(other.value) {} \
+	TypeName(enum_type value_) : value(value_) {} \
+  TypeName& operator=(const TypeName &other) {value = other.value; return *this;} \
+  explicit TypeName(value_type value_) : value(static_cast<enum_type>(value_)) {} \
+	operator value_type() const {return static_cast<value_type>(value);} \
+  value_type get_value() const {return static_cast<value_type>(value);} \
+  enum_type get_enum() const {return value;} \
+  const char* c_str() const \
+  { \
+    switch (value) \
+    {
+
+//*****************************************************************************
+// A case in the 'c_str' function's switch statement.
+//*****************************************************************************
+#define ETL_ENUM_TYPE(value, name) \
+      case value: \
+        return name; \
+
+//*****************************************************************************
+// The final section of the 'c_str' function and the value declaration.
+//*****************************************************************************
+#define ETL_END_ENUM_TYPE \
+      default: \
+        return "?"; \
+    } \
+  } \
+private: \
+  enum_type value;
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/error_handler.cpp	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,61 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+#include "platform.h"
+#include "error_handler.h"
+#include "nullptr.h"
+
+//*****************************************************************************
+/// The error function callback pointer.
+//*****************************************************************************
+etl::ifunction<const etl::exception&>* etl::error_handler::p_ifunction = std::nullptr;
+
+//*****************************************************************************
+/// Sets the error callback function.
+///\param f A reference to an etl::function object that will handler errors.
+//*****************************************************************************
+void etl::error_handler::set_callback(ifunction<const etl::exception&>& f)
+{
+  p_ifunction = &f;
+}
+
+//*****************************************************************************
+/// Sends the exception error to the user's handler function.
+///\param e The exception error.
+//*****************************************************************************
+void etl::error_handler::error(const etl::exception& e)
+{
+  if (p_ifunction != std::nullptr)
+  {
+    (*p_ifunction)(e);
+  }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/error_handler.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,135 @@
+
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_ERROR_HANDLER__
+#define __ETL_ERROR_HANDLER__
+
+///\defgroup error_handler error_handler
+/// Error handler for when throwing exceptions is not required.
+///\ingroup utilities
+
+#include <assert.h>
+
+#include "platform.h"
+#include "exception.h"
+#include "function.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Error handler for when throwing exceptions is not required.
+  ///\ingroup error_handler
+  //***************************************************************************
+  class error_handler
+  {
+  public:
+
+    //*************************************************************************
+    /// Callback class for free handler functions.
+    //*************************************************************************
+    struct free_function : public etl::function<void, const etl::exception&>
+    {
+      free_function(void (*p_function_)(const etl::exception&))
+        : etl::function<void, const etl::exception&>(p_function_)
+      {
+      }
+    };
+
+    //*************************************************************************
+    /// Callback class for member handler functions.
+    //*************************************************************************
+    template <typename TObject>
+    struct member_function : public etl::function<TObject, const etl::exception&>
+    {
+      member_function(TObject& object_, void(TObject::*p_function_)(const etl::exception&))
+        : etl::function<TObject, const etl::exception&>(object_, p_function_)
+      {
+      }
+    };
+
+    static void set_callback(ifunction<const etl::exception&>& f);
+    static void error(const etl::exception& e);
+
+  private:
+
+    static ifunction<const etl::exception&>* p_ifunction;
+  };
+}
+
+//***************************************************************************
+/// Asserts a condition.
+/// Versions of the macro that return a constant value of 'true' will allow the compiler to optimise away
+/// any 'if' statements that it is contained within.
+/// If ETL_NO_CHECKS is defined then no runtime checks are executed at all.
+/// If asserts or exceptions are enabled then the error is thrown if the assert fails. The return value is always 'true'.
+/// If ETL_LOG_ERRORS is defined then the error is logged if the assert fails. The return value is the value of the boolean test.
+/// Otherwise 'assert' is called. The return value is always 'true'.
+///\ingroup error_handler
+//***************************************************************************
+#if defined(ETL_NO_CHECKS)
+  #define ETL_ASSERT(b, e)                                                             // Does nothing.
+#elif defined(ETL_THROW_EXCEPTIONS)
+  #if defined(ETL_LOG_ERRORS)
+    #define ETL_ASSERT(b, e) {if (!(b)) {etl::error_handler::error((e)); throw((e);)}} // If the condition fails, calls the error handler then throws an exception.
+  #else
+    #define ETL_ASSERT(b, e) {if (!(b)) {throw((e));}}                                 // If the condition fails, throws an exception.
+  #endif
+#else
+  #if defined(ETL_LOG_ERRORS)
+    #if defined(NDEBUG)
+      #define ETL_ASSERT(b, e) {if(!(b)) {etl::error_handler::error((e));}}              // If the condition fails, calls the error handler
+    #else
+      #define ETL_ASSERT(b, e) {if(!(b)) {etl::error_handler::error((e));} assert((b));} // If the condition fails, calls the error handler then asserts.
+    #endif
+  #else
+    #if defined(NDEBUG)
+      #define ETL_ASSERT(b, e)                                                         // Does nothing.
+    #else
+      #define ETL_ASSERT(b, e) assert((b))                                             // If the condition fails, asserts.
+    #endif
+  #endif
+#endif
+
+#if defined(ETL_VERBOSE_ERRORS)
+  #define ETL_ERROR(e) (e(__FILE__, __LINE__)) // Make an exception with the file name and line number.
+#else
+  #define ETL_ERROR(e) (e("", __LINE__))       // Make an exception with the line number.
+#endif
+
+#if defined(ETL_VERBOSE_ERRORS)
+  #define ETL_ERROR_TEXT(verbose_text, terse_text) (verbose_text) // Use the verbose text.
+#else
+  #define ETL_ERROR_TEXT(verbose_text, terse_text) (terse_text)   // Use the terse text.
+#endif
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etl_profile.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,47 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_PROFILE_H__
+#define __ETL_PROFILE_H__
+
+#undef ETL_THROW_EXCEPTIONS
+#undef ETL_CPP11_SUPPORTED
+#define ETL_VERBOSE_ERRORS
+#define ETL_CHECK_PUSH_POP
+#undef ETL_ISTRING_REPAIR_ENABLE
+#undef ETL_IVECTOR_REPAIR_ENABLE
+#undef ETL_IDEQUE_REPAIR_ENABLE
+#undef ETL_IN_UNIT_TEST
+#undef CAPACITY
+
+#include "profiles/gcc_generic.h"
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/exception.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,118 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_EXCEPTION__
+#define __ETL_EXCEPTION__
+
+#include "platform.h"
+
+///\defgroup exception exception
+/// The base class for all ETL exceptions.
+///\ingroup utilities
+
+namespace etl
+{
+  //***************************************************************************
+  ///\ingroup exception
+  /// A low overhead exception base class.
+  //***************************************************************************
+  class exception
+  {
+  public:
+
+    typedef const char* string_type;
+    typedef int         numeric_type;
+
+#if defined(ETL_VERBOSE_ERRORS)
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    exception(string_type reason_, string_type file_, numeric_type line_)
+      : reason_text(reason_),
+        file_text(file_),
+        line(line_)
+    {
+    }
+#else
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    exception(string_type reason_, string_type file_, numeric_type line_)
+      : reason_text(reason_),
+        line(line_)
+    {
+    (void)file_;
+    }
+#endif
+
+    //***************************************************************************
+    /// Gets the reason for the exception.
+    /// \return const char* to the reason.
+    //***************************************************************************
+    string_type what() const
+    {
+      return reason_text;
+    }
+
+
+    //***************************************************************************
+    /// Gets the file for the exception.
+    /// \return const char* to the file.
+    //***************************************************************************
+    string_type file_name() const
+    {
+#if defined(ETL_VERBOSE_ERRORS)
+      return file_text;
+#else
+      return "";
+#endif
+    }
+
+    //***************************************************************************
+    /// Gets the line for the exception.
+    /// \return const char* to the line.
+    //***************************************************************************
+    numeric_type line_number() const
+    {
+      return line;
+    }
+
+  private:
+
+    string_type  reason_text; ///< The reason for the exception.
+#if defined(ETL_VERBOSE_ERRORS)
+    string_type  file_text;   ///< The file for the exception.
+#endif
+    numeric_type line;   ///< The line for the exception.
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/factorial.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,66 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_FACTORIAL__
+#define __ETL_FACTORIAL__
+
+#include <stddef.h>
+
+#include "platform.h"
+
+///\defgroup factorial factorial
+/// fibonacci<N> : Calculates the Nth factorial value.
+///\ingroup maths
+
+namespace etl 
+{
+  //***************************************************************************
+  ///\ingroup fibonacci
+  /// Defines <b>value</b> as the Nth factorial number.
+  ///\tparam N The number to find the factorial value of.
+  //***************************************************************************
+  template <size_t N>
+  struct factorial
+  {
+    static const size_t value = N * factorial<N - 1>::value;
+  };
+
+  //***************************************************************************
+  // Specialisation for N = 0
+  //***************************************************************************
+  template <>
+  struct factorial<0>
+  {
+    static const size_t value = 1;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/factory.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,469 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_FACTORY__
+#define __ETL_FACTORY__
+
+#include <stdint.h>
+#include <utility>
+
+#include "platform.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "largest.h"
+#include "type_traits.h"
+#include "alignment.h"
+#include "static_assert.h"
+#include "type_lookup.h"
+#include <pool.h>
+
+#if defined(ETL_COMPILER_GCC)
+  #warning THIS CLASS IS DEPRECATED!USE VARIANT_POOL INSTEAD.
+#elif defined(ETL_COMPILER_MICROSOFT)
+  #pragma message ("THIS CLASS IS DEPRECATED! USE VARIANT_POOL INSTEAD.")
+#endif
+
+#undef ETL_FILE
+#define ETL_FILE "40"
+
+namespace etl
+{
+  //***************************************************************************
+  class factory_exception : public etl::exception
+  {
+  public:
+
+    factory_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  class factory_cannot_create : public etl::factory_exception
+  {
+  public:
+
+    factory_cannot_create(string_type file_name_, numeric_type line_number_)
+      : factory_exception(ETL_ERROR_TEXT("factory:cannot create", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  class factory_did_not_create : public etl::factory_exception
+  {
+  public:
+
+    factory_did_not_create(string_type file_name_, numeric_type line_number_)
+      : factory_exception(ETL_ERROR_TEXT("factory:did not create", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  template <const size_t MAX_SIZE_,
+            typename T1,
+            typename T2  = etl::type_id_pair<etl::null_type, -2>,
+            typename T3  = etl::type_id_pair<etl::null_type, -3>,
+            typename T4  = etl::type_id_pair<etl::null_type, -4>,
+            typename T5  = etl::type_id_pair<etl::null_type, -5>,
+            typename T6  = etl::type_id_pair<etl::null_type, -6>,
+            typename T7  = etl::type_id_pair<etl::null_type, -7>,
+            typename T8  = etl::type_id_pair<etl::null_type, -8>,
+            typename T9  = etl::type_id_pair<etl::null_type, -9>,
+            typename T10 = etl::type_id_pair<etl::null_type, -10>,
+            typename T11 = etl::type_id_pair<etl::null_type, -11>,
+            typename T12 = etl::type_id_pair<etl::null_type, -12>,
+            typename T13 = etl::type_id_pair<etl::null_type, -13>,
+            typename T14 = etl::type_id_pair<etl::null_type, -14>,
+            typename T15 = etl::type_id_pair<etl::null_type, -15>,
+            typename T16 = etl::type_id_pair<etl::null_type, -16> >
+  class factory
+  {
+  private:
+
+    typedef typename T1::type  TT1;
+    typedef typename T2::type  TT2;
+    typedef typename T3::type  TT3;
+    typedef typename T4::type  TT4;
+    typedef typename T5::type  TT5;
+    typedef typename T6::type  TT6;
+    typedef typename T7::type  TT7;
+    typedef typename T8::type  TT8;
+    typedef typename T9::type  TT9;
+    typedef typename T10::type TT10;
+    typedef typename T11::type TT11;
+    typedef typename T12::type TT12;
+    typedef typename T13::type TT13;
+    typedef typename T14::type TT14;
+    typedef typename T15::type TT15;
+    typedef typename T16::type TT16;
+
+    typedef etl::type_id_lookup<T1, T2,  T3,  T4,  T5,  T6,  T7,  T8,
+                                T9, T10, T11, T12, T13, T14, T15, T16> lookup_t;
+
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    factory()
+    {
+    }
+
+#if !ETL_CPP11_SUPPORTED
+    //*************************************************************************
+    /// Creates the object. Default constructor.
+    //*************************************************************************
+    template <typename T>
+    T* create_from_type()
+    {
+      STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type");
+
+      T* p = std::nullptr;
+
+      if (pool.full())
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create));
+      }
+      else
+      {
+        p = pool.template allocate<T>();
+
+        if (p != std::nullptr)
+        {
+          new (p) T();
+        }
+      }
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Creates the object. One parameter constructor.
+    //*************************************************************************
+    template <typename T, typename TP1>
+    T* create_from_type(const TP1& p1)
+    {
+      STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type");
+
+      T* p = std::nullptr;
+
+      if (pool.full())
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create));
+      }
+      else
+      {
+        p = pool.template allocate<T>();
+
+        if (p != std::nullptr)
+        {
+          new (p) T(p1);
+        }
+      }
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Creates the object. Two parameter constructor.
+    //*************************************************************************
+    template <typename T, typename TP1, typename TP2>
+    T* create_from_type(const TP1& p1, const TP2& p2)
+    {
+      STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type");
+
+      T* p = std::nullptr;
+
+      if (pool.full())
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create));
+      }
+      else
+      {
+        p = pool.template allocate<T>();
+
+        if (p != std::nullptr)
+        {
+          new (p) T(p1, p2);
+        }
+      }
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Creates the object. Three parameter constructor.
+    //*************************************************************************
+    template <typename T, typename TP1, typename TP2, typename TP3>
+    T* create_from_type(const TP1& p1, const TP2& p2, const TP3& p3)
+    {
+      STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type");
+
+      T* p = std::nullptr;
+
+      if (pool.full())
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create));
+      }
+      else
+      {
+        p = pool.template allocate<T>();
+
+        if (p != std::nullptr)
+        {
+          new (p) T(p1, p2, p3);
+        }
+      }
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Creates the object. Four parameter constructor.
+    //*************************************************************************
+    template <typename T, typename TP1, typename TP2, typename TP3, typename TP4>
+    T* create_from_type(const TP1& p1, const TP2& p2, const TP3& p3, const TP4& p4)
+    {
+      STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type");
+
+      T* p = std::nullptr;
+
+      if (pool.full())
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create));
+      }
+      else
+      {
+        p = pool.template allocate<T>();
+
+        if (p != std::nullptr)
+        {
+          new (p) T(p1, p2, p3, p4);
+        }
+      }
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Creates the object from an index. Default constructor.
+    //*************************************************************************
+    template <size_t ID>
+    typename lookup_t::template type_from_id<ID>::type* create_from_id()
+    {
+      typedef typename lookup_t::template type_from_id<ID>::type type;
+      STATIC_ASSERT((!etl::is_same<void, type>::value), "Invalid index");
+      return create_from_type<type>();
+    }
+
+    //*************************************************************************
+    /// Creates the object from an index. One parameter constructor.
+    //*************************************************************************
+    template <size_t ID, typename TP1>
+    typename lookup_t::template type_from_id<ID>::type* create_from_id(const TP1& p1)
+    {
+      typedef typename lookup_t::template type_from_id<ID>::type type;
+      STATIC_ASSERT((!etl::is_same<void, type>::value), "Invalid index");
+      return create_from_type<type>(p1);
+    }
+
+    //*************************************************************************
+    /// Creates the object from an index. Two parameter constructor.
+    //*************************************************************************
+    template <size_t ID, typename TP1, typename TP2>
+    typename lookup_t::template type_from_id<ID>::type* create_from_id(const TP1& p1, const TP2& p2)
+    {
+      typedef typename lookup_t::template type_from_id<ID>::type type;
+      STATIC_ASSERT((!etl::is_same<void, type>::value), "Invalid index");
+      return create_from_type<type>(p1, p2);
+    }
+
+    //*************************************************************************
+    /// Creates the object from an index. Three parameter constructor.
+    //*************************************************************************
+    template <size_t ID, typename TP1, typename TP2, typename TP3>
+    typename lookup_t::template type_from_id<ID>::type* create_from_id(const TP1& p1, const TP2& p2, const TP3& p3)
+    {
+      typedef typename lookup_t::template type_from_id<ID>::type type;
+      STATIC_ASSERT((!etl::is_same<void, type>::value), "Invalid index");
+      return create_from_type<type>(p1, p2, p3);
+    }
+
+    //*************************************************************************
+    /// Creates the object from an index. Three parameter constructor.
+    //*************************************************************************
+    template <size_t ID, typename TP1, typename TP2, typename TP3, typename TP4>
+    typename lookup_t::template type_from_id<ID>::type* create_from_id(const TP1& p1, const TP2& p2, const TP3& p3, const TP4& p4)
+    {
+      typedef typename lookup_t::template type_from_id<ID>::type type;
+      STATIC_ASSERT((!etl::is_same<void, type>::value), "Invalid index");
+      return create_from_type<type>(p1, p2, p3, p4);
+    }
+#else
+    //*************************************************************************
+    /// Creates the object from a type. Variadic parameter constructor.
+    //*************************************************************************
+    template <typename T, typename... Args>
+    T* create_from_type(Args&&... args)
+    {
+      STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type");
+
+      T* p = std::nullptr;
+
+      if (pool.full())
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create));
+      }
+      else
+      {
+        p = pool.template allocate<T>();
+
+        if (p != std::nullptr)
+        {
+          new (p) T(std::forward<Args>(args)...);
+        }
+      }
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Creates the object from an index. Variadic parameter constructor.
+    //*************************************************************************
+    template <size_t ID, typename... Args>
+    typename lookup_t::template type_from_id<ID>::type* create_from_id(Args&&... args)
+    {
+      typedef typename lookup_t::template type_from_id<ID>::type type;
+      STATIC_ASSERT((!etl::is_same<void, type>::value), "Invalid index");
+      return create_from_type<type>(std::forward<Args>(args)...);
+    }
+#endif
+
+    //*************************************************************************
+    /// Destroys the object.
+    //*************************************************************************
+    template <typename T>
+    bool destroy(const T* const p)
+    {
+      STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value ||
+                     etl::is_base_of<T, TT1>::value  ||
+                     etl::is_base_of<T, TT2>::value  ||
+                     etl::is_base_of<T, TT3>::value  ||
+                     etl::is_base_of<T, TT4>::value  ||
+                     etl::is_base_of<T, TT5>::value  ||
+                     etl::is_base_of<T, TT6>::value  ||
+                     etl::is_base_of<T, TT7>::value  ||
+                     etl::is_base_of<T, TT8>::value  ||
+                     etl::is_base_of<T, TT9>::value  ||
+                     etl::is_base_of<T, TT10>::value ||
+                     etl::is_base_of<T, TT11>::value ||
+                     etl::is_base_of<T, TT12>::value ||
+                     etl::is_base_of<T, TT13>::value ||
+                     etl::is_base_of<T, TT14>::value ||
+                     etl::is_base_of<T, TT15>::value ||
+                     etl::is_base_of<T, TT16>::value), "Invalid type");
+
+      p->~T();
+
+      void* vp = reinterpret_cast<char*>(const_cast<T*>(p));
+
+      if (pool.is_in_pool(vp))
+      {
+        pool.release(vp);
+        return true;
+      }
+      else
+      {
+        ETL_ASSERT(false, ETL_ERROR(factory_did_not_create));
+        return false;
+      }
+    }
+
+    //*************************************************************************
+    /// Returns the maximum number of items in the factory.
+    //*************************************************************************
+    size_t max_size() const
+    {
+      return MAX_SIZE;
+    }
+
+    //*************************************************************************
+    /// Returns the number of free items in the factory.
+    //*************************************************************************
+    size_t available() const
+    {
+      return pool.available();
+    }
+
+    //*************************************************************************
+    /// Returns the number of allocated items in the factory.
+    //*************************************************************************
+    size_t size() const
+    {
+      return pool.size();
+    }
+
+    //*************************************************************************
+    /// Checks to see if there are no allocated items in the factory.
+    /// \return <b>true</b> if there are none allocated.
+    //*************************************************************************
+    bool empty() const
+    {
+      return pool.empty();
+    }
+
+    //*************************************************************************
+    /// Checks to see if there are no free items in the factory.
+    /// \return <b>true</b> if there are none free.
+    //*************************************************************************
+    bool full() const
+    {
+      return pool.full();
+    }
+
+  private:
+
+    factory(const factory&);
+    factory& operator =(const factory&);
+
+    // The pool.
+    etl::generic_pool<etl::largest<TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::size,
+                      etl::largest<TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::alignment,
+                      MAX_SIZE> pool;
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fibonacci.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,75 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_FIBONACCI__
+#define __ETL_FIBONACCI__
+
+#include <stddef.h>
+
+#include "platform.h"
+
+///\defgroup fibonacci fibonacci
+/// fibonacci<N> : Calculates the Nth Fibonacci value.
+///\ingroup maths
+
+namespace etl 
+{
+  //***************************************************************************
+  ///\ingroup fibonacci
+  /// Defines <b>value</b> as the Nth Fibbonacci number.
+  ///\tparam N The number to find the Fibbonacci value of.
+  //***************************************************************************
+  template <size_t N>
+  struct fibonacci
+  {
+    static const size_t value = fibonacci<N - 1>::value + fibonacci<N - 2>::value;
+  };
+
+  //***************************************************************************
+  // Specialisation for N = 1
+  //***************************************************************************
+  template <>
+  struct fibonacci<1>
+  {
+    static const size_t value = 1;
+  };
+
+  //***************************************************************************
+  // Specialisation for N = 0
+  //***************************************************************************
+  template <>
+  struct fibonacci<0>
+  {
+    static const size_t value = 0;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fixed_iterator.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,271 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+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 __ETL_FIXED_ITERATOR__
+#define __ETL_FIXED_ITERATOR__
+
+#include <iterator>
+
+#include "platform.h"
+
+///\defgroup iterator Iterator types
+
+namespace etl
+{
+  /// A fixed iterator class.
+  /// This iterator can be given an iterator value, which will not be allowed to be incremented or decremented.
+  /// This can be useful when using STL algorithms to interact with fixed memory locations such as registers.
+  ///\ingroup iterator
+  template <typename TIterator>
+  class fixed_iterator : std::iterator<typename std::iterator_traits<TIterator>::iterator_category, typename std::iterator_traits<TIterator>::value_type>
+  {
+  public:
+
+    //***************************************************************************
+    /// Default constructor.
+    //***************************************************************************
+    fixed_iterator()
+      : it(TIterator())
+    {
+    }
+
+    //***************************************************************************
+    /// Construct from iterator.
+    //***************************************************************************
+    fixed_iterator(TIterator it_)
+      : it(it_)
+    {
+    }
+
+    //***************************************************************************
+    /// Increment (Does nothing).
+    //***************************************************************************
+    fixed_iterator& operator ++()
+    {
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Increment (Does nothing).
+    //***************************************************************************
+    fixed_iterator operator ++(int)
+    {
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Decrement (Does nothing).
+    //***************************************************************************
+    fixed_iterator& operator --()
+    {
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Decrement (Does nothing).
+    //***************************************************************************
+    fixed_iterator operator --(int)
+    {
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Dereference operator.
+    //***************************************************************************
+    typename std::iterator_traits<TIterator>::value_type operator *()
+    {
+      return *it;
+    }
+
+    //***************************************************************************
+    /// Dereference operator.
+    //***************************************************************************
+    const typename std::iterator_traits<TIterator>::value_type operator *() const
+    {
+      return *it;
+    }
+
+    //***************************************************************************
+    /// -> operator.
+    //***************************************************************************
+    TIterator operator ->()
+    {
+      return it;
+    }
+
+    //***************************************************************************
+    /// -> operator.
+    //***************************************************************************
+    const TIterator operator ->() const
+    {
+      return it;
+    }
+
+    //***************************************************************************
+    /// Conversion operator.
+    //***************************************************************************
+    operator TIterator() const
+    {
+      return it;
+    }
+
+    //***************************************************************************
+    /// += operator.
+    //***************************************************************************
+    fixed_iterator& operator +=(typename std::iterator_traits<TIterator>::difference_type /*offset*/)
+    {
+      return *this;
+    }
+
+    //***************************************************************************
+    /// -= operator.
+    //***************************************************************************
+    fixed_iterator& operator -=(typename std::iterator_traits<TIterator>::difference_type /*offset*/)
+    {
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Assignment from iterator.
+    //***************************************************************************
+    fixed_iterator& operator =(TIterator new_it)
+    {
+      it = new_it;
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Assignment from fixed_iterator.
+    //***************************************************************************
+    fixed_iterator& operator =(fixed_iterator other)
+    {
+      it = other.it;
+      return *this;
+    }
+
+  private:
+
+    TIterator it; ///< The underlying iterator.
+  };
+}
+
+//*****************************************************************************
+/// + difference operator.
+//*****************************************************************************
+template <typename TIterator>
+etl::fixed_iterator<TIterator>& operator +(etl::fixed_iterator<TIterator>& lhs,
+                                           typename std::iterator_traits<TIterator>::difference_type /*rhs*/)
+{
+  return lhs;
+}
+
+//*****************************************************************************
+/// - difference operator.
+//*****************************************************************************
+template <typename TIterator>
+etl::fixed_iterator<TIterator>& operator -(etl::fixed_iterator<TIterator>& lhs,
+                                           typename std::iterator_traits<TIterator>::difference_type /*rhs*/)
+{
+  return lhs;
+}
+
+//*****************************************************************************
+/// - fixed_iterator operator.
+//*****************************************************************************
+template <typename TIterator>
+typename std::iterator_traits<TIterator>::difference_type operator -(etl::fixed_iterator<TIterator>& lhs,
+                                                                     etl::fixed_iterator<TIterator>& rhs)
+{
+  return TIterator(lhs) - TIterator(rhs);
+}
+
+//*****************************************************************************
+/// Equality operator. fixed_iterator == fixed_iterator.
+//*****************************************************************************
+template <typename TIterator>
+bool operator ==(const etl::fixed_iterator<TIterator>& lhs,
+                 const etl::fixed_iterator<TIterator>& rhs)
+{
+  return TIterator(lhs) == TIterator(rhs);
+}
+
+//*****************************************************************************
+/// Equality operator. fixed_iterator == iterator.
+//*****************************************************************************
+template <typename TIterator>
+bool operator ==(const etl::fixed_iterator<TIterator>& lhs,
+                 TIterator rhs)
+{
+  return TIterator(lhs) == rhs;
+}
+
+//*****************************************************************************
+/// Equality operator. iterator == fixed_iterator.
+//*****************************************************************************
+template <typename TIterator>
+bool operator ==(TIterator lhs,
+                 const etl::fixed_iterator<TIterator>& rhs)
+{
+  return lhs == TIterator(rhs);
+}
+
+
+//*****************************************************************************
+/// Inequality operator. fixed_iterator == fixed_iterator.
+//*****************************************************************************
+template <typename TIterator>
+bool operator !=(const etl::fixed_iterator<TIterator>& lhs,
+                 const etl::fixed_iterator<TIterator>& rhs)
+{
+  return !(lhs == rhs);
+}
+
+//*****************************************************************************
+/// Inequality operator. fixed_iterator == iterator.
+//*****************************************************************************
+template <typename TIterator>
+bool operator !=(const etl::fixed_iterator<TIterator>& lhs,
+                 TIterator rhs)
+{
+  return !(lhs == rhs);
+}
+
+//*****************************************************************************
+/// Inequality operator. iterator == fixed_iterator.
+//*****************************************************************************
+template <typename TIterator>
+bool operator !=(TIterator& lhs,
+                 const etl::fixed_iterator<TIterator>& rhs)
+{
+  return !(lhs == rhs);
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flat_map.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,690 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+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 __ETL_FLAT_MAP__
+#define __ETL_FLAT_MAP__
+
+#include "platform.h"
+#include "reference_flat_map.h"
+#include "pool.h"
+
+#undef ETL_FILE
+#define ETL_FILE "2"
+
+//*****************************************************************************
+///\defgroup flat_map flat_map
+/// A flat_map with the capacity defined at compile time.
+/// Has insertion of O(N) and flat_map of O(logN)
+/// Duplicate entries are not allowed.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for specifically sized flat_maps.
+  /// Can be used as a reference type for all flat_maps containing a specific type.
+  ///\ingroup flat_map
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare = std::less<TKey> >
+  class iflat_map : private etl::ireference_flat_map<TKey, TMapped, TKeyCompare>
+  {
+  private:
+
+    typedef etl::ireference_flat_map<TKey, TMapped, TKeyCompare> refmap_t;
+    typedef typename refmap_t::lookup_t lookup_t;
+    typedef etl::ipool storage_t;
+
+  public:
+
+
+    typedef std::pair<const TKey, TMapped> value_type;
+    typedef TKey              key_type;
+    typedef TMapped           mapped_type;
+    typedef TKeyCompare       key_compare;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef size_t            size_type;
+
+    typedef typename refmap_t::iterator       iterator;
+    typedef typename refmap_t::const_iterator const_iterator;
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+  protected:
+
+    typedef typename etl::parameter_type<TKey>::type key_parameter_t;
+
+  private:
+
+    //*********************************************************************
+    /// How to compare elements and keys.
+    //*********************************************************************
+    class compare
+    {
+    public:
+
+      bool operator ()(const value_type& element, key_type key) const
+      {
+        return key_compare()(element.first, key);
+      }
+
+      bool operator ()(key_type key, const value_type& element) const
+      {
+        return key_compare()(key, element.first);
+      }
+    };
+
+  public:
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the flat_map.
+    ///\return An iterator to the beginning of the flat_map.
+    //*********************************************************************
+    iterator begin()
+    {
+      return refmap_t::begin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the flat_map.
+    ///\return A const iterator to the beginning of the flat_map.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return refmap_t::begin();
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the flat_map.
+    ///\return An iterator to the end of the flat_map.
+    //*********************************************************************
+    iterator end()
+    {
+      return refmap_t::end();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the flat_map.
+    ///\return A const iterator to the end of the flat_map.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return refmap_t::end();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the flat_map.
+    ///\return A const iterator to the beginning of the flat_map.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return refmap_t::cbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the flat_map.
+    ///\return A const iterator to the end of the flat_map.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return refmap_t::cend();
+    }
+
+    //*********************************************************************
+    /// Returns an reverse iterator to the reverse beginning of the flat_map.
+    ///\return Iterator to the reverse beginning of the flat_map.
+    //*********************************************************************
+    reverse_iterator rbegin()
+    {
+      return refmap_t::rbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the flat_map.
+    ///\return Const iterator to the reverse beginning of the flat_map.
+    //*********************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return refmap_t::rbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a reverse iterator to the end + 1 of the flat_map.
+    ///\return Reverse iterator to the end + 1 of the flat_map.
+    //*********************************************************************
+    reverse_iterator rend()
+    {
+      return refmap_t::rend();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the flat_map.
+    ///\return Const reverse iterator to the end + 1 of the flat_map.
+    //*********************************************************************
+    const_reverse_iterator rend() const
+    {
+      return refmap_t::rend();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the flat_map.
+    ///\return Const reverse iterator to the reverse beginning of the flat_map.
+    //*********************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return refmap_t::crbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the flat_map.
+    ///\return Const reverse iterator to the end + 1 of the flat_map.
+    //*********************************************************************
+    const_reverse_iterator crend() const
+    {
+      return refmap_t::crend();
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'key'
+    ///\param i The index.
+    ///\return A reference to the value at index 'key'
+    //*********************************************************************
+    mapped_type& operator [](key_parameter_t key)
+    {
+      iterator i_element = lower_bound(key);
+
+      // Doesn't already exist?
+      if (i_element == end())
+      {
+        value_type* pvalue = storage.allocate<value_type>();
+        ::new (pvalue) value_type();
+        ++construct_count;
+
+        std::pair<iterator, bool> result = refmap_t::insert_at(i_element, *pvalue);
+        i_element->second = result.first->second;
+      }
+
+      return i_element->second;
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'key'
+    /// If asserts or exceptions are enabled, emits an etl::flat_map_out_of_bounds if the key is not in the range.
+    ///\param i The index.
+    ///\return A reference to the value at index 'key'
+    //*********************************************************************
+    mapped_type& at(key_parameter_t key)
+    {
+      return refmap_t::at(key);
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'key'
+    /// If asserts or exceptions are enabled, emits an etl::flat_map_out_of_bounds if the key is not in the range.
+    ///\param i The index.
+    ///\return A const reference to the value at index 'key'
+    //*********************************************************************
+    const mapped_type& at(key_parameter_t key) const
+    {
+      return refmap_t::at(key);
+    }
+
+    //*********************************************************************
+    /// Assigns values to the flat_map.
+    /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined, emits flat_map_full if the flat_map does not have enough free space.
+    /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined, emits flat_map_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_map_full));
+#endif
+
+      clear();
+
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the flat_map.
+    /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map is already full.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(const_reference value)
+    {
+      iterator i_element = lower_bound(value.first);
+
+      std::pair<iterator, bool> result(i_element, false);
+
+      // Doesn't already exist?
+      if ((i_element == end() || (i_element->first != value.first)))
+      {
+        ETL_ASSERT(!refmap_t::full(), ETL_ERROR(flat_map_full));
+
+        value_type* pvalue = storage.allocate<value_type>();
+        ::new (pvalue) value_type(value);
+        ++construct_count;
+        result = refmap_t::insert_at(i_element, *pvalue);
+      }
+
+      return result;
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the flat_map.
+    /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map is already full.
+    ///\param position The position to insert at.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator position, const_reference value)
+    {
+      return insert(value).first;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the flat_map.
+    /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param key The key to erase.
+    ///\return The number of elements erased. 0 or 1.
+    //*********************************************************************
+    size_t erase(key_parameter_t key)
+    {
+      iterator i_element = find(key);
+
+      if (i_element == end())
+      {
+        return 0;
+      }
+      else
+      {
+        i_element->~value_type();
+        storage.release(etl::addressof(*i_element));
+        refmap_t::erase(i_element);
+        --construct_count;
+        return 1;
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param i_element Iterator to the element.
+    //*********************************************************************
+    void erase(iterator i_element)
+    {
+      i_element->~value_type();
+      storage.release(etl::addressof(*i_element));
+      refmap_t::erase(i_element);
+      --construct_count;
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    //*********************************************************************
+    void erase(iterator first, iterator last)
+    {
+      iterator itr = first;
+
+      while (itr != last)
+      {
+        itr->~value_type();
+        storage.release(etl::addressof(*itr));
+        ++itr;
+        --construct_count;
+      }
+
+      refmap_t::erase(first, last);
+    }
+
+    //*************************************************************************
+    /// Clears the flat_map.
+    //*************************************************************************
+    void clear()
+    {
+      erase(begin(), end());
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    iterator find(key_parameter_t key)
+    {
+      return refmap_t::find(key);
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    const_iterator find(key_parameter_t key) const
+    {
+      return refmap_t::find(key);
+    }
+
+    //*********************************************************************
+    /// Counts an element.
+    ///\param key The key to search for.
+    ///\return 1 if the key exists, otherwise 0.
+    //*********************************************************************
+    size_t count(key_parameter_t key) const
+    {
+      return refmap_t::count(key);
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator lower_bound(key_parameter_t key)
+    {
+      return refmap_t::lower_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator lower_bound(key_parameter_t key) const
+    {
+      return refmap_t::lower_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator upper_bound(key_parameter_t key)
+    {
+      return refmap_t::upper_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator upper_bound(key_parameter_t key) const
+    {
+      return refmap_t::upper_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<iterator, iterator> equal_range(key_parameter_t key)
+    {
+      return refmap_t::equal_range(key);
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
+    {
+      return refmap_t::equal_range(key);
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    iflat_map& operator = (const iflat_map& rhs)
+    {
+      if (&rhs != this)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Gets the current size of the flat_map.
+    ///\return The current size of the flat_map.
+    //*************************************************************************
+    size_type size() const
+    {
+      return refmap_t::size();
+    }
+
+    //*************************************************************************
+    /// Checks the 'empty' state of the flat_map.
+    ///\return <b>true</b> if empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return refmap_t::empty();
+    }
+
+    //*************************************************************************
+    /// Checks the 'full' state of the flat_map.
+    ///\return <b>true</b> if full.
+    //*************************************************************************
+    bool full() const
+    {
+      return refmap_t::full();
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the flat_map.
+    ///\return The capacity of the flat_map.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return refmap_t::capacity();
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the flat_map.
+    ///\return The maximum size of the flat_map.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return refmap_t::max_size();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return refmap_t::available();
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    iflat_map(lookup_t& lookup_, storage_t& storage_)
+      : refmap_t(lookup_),
+        storage(storage_)
+    {
+    }
+
+  private:
+
+    // Disable copy construction.
+    iflat_map(const iflat_map&);
+
+    storage_t& storage;
+
+    /// Internal debugging.
+    etl::debug_count construct_count;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first flat_map.
+  ///\param rhs Reference to the second flat_map.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup flat_map
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator ==(const etl::iflat_map<TKey, TMapped, TKeyCompare>& lhs, const etl::iflat_map<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first flat_map.
+  ///\param rhs Reference to the second flat_map.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup flat_map
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator !=(const etl::iflat_map<TKey, TMapped, TKeyCompare>& lhs, const etl::iflat_map<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //***************************************************************************
+  /// A flat_map implementation that uses a fixed size buffer.
+  ///\tparam TKey     The key type.
+  ///\tparam TValue   The value type.
+  ///\tparam TCompare The type to compare keys. Default = std::less<TKey>
+  ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+  ///\ingroup flat_map
+  //***************************************************************************
+  template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> >
+  class flat_map : public etl::iflat_map<TKey, TValue, TCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    flat_map()
+      : etl::iflat_map<TKey, TValue, TCompare>(lookup, storage)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    flat_map(const flat_map& other)
+      : etl::iflat_map<TKey, TValue, TCompare>(lookup, storage)
+    {
+      etl::iflat_map<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    flat_map(TIterator first, TIterator last)
+      : etl::iflat_map<TKey, TValue, TCompare>(lookup, storage)
+    {
+      etl::iflat_map<TKey, TValue, TCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~flat_map()
+    {
+      etl::iflat_map<TKey, TValue, TCompare>::clear();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    flat_map& operator = (const flat_map& rhs)
+    {
+      if (&rhs != this)
+      {
+        etl::iflat_map<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    typedef typename etl::iflat_map<TKey, TValue, TCompare>::value_type node_t;
+
+    /// The pool of nodes.
+    etl::pool<node_t, MAX_SIZE> storage;
+
+    /// The vector that stores pointers to the nodes.
+    etl::vector<node_t*, MAX_SIZE> lookup;
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flat_multimap.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,641 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+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 __ETL_FLAT_MULTMAP__
+#define __ETL_FLAT_MULTMAP__
+
+#include "platform.h"
+#include "reference_flat_multimap.h"
+#include "pool.h"
+
+#undef ETL_FILE
+#define ETL_FILE "3"
+
+//*****************************************************************************
+///\defgroup flat_multimap flat_multimap
+/// A flat_multimapmap with the capacity defined at compile time.
+/// Has insertion of O(N) and find of O(logN)
+/// Duplicate entries and not allowed.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for specifically sized flat_multimaps.
+  /// Can be used as a reference type for all flat_multimaps containing a specific type.
+  ///\ingroup flat_multimap
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare = std::less<TKey> >
+  class iflat_multimap : public etl::ireference_flat_multimap<TKey, TMapped, TKeyCompare>
+  {
+  public:
+
+    typedef std::pair<const TKey, TMapped> value_type;
+
+  private:
+
+    typedef etl::ireference_flat_multimap<TKey, TMapped, TKeyCompare> refmap_t;
+    typedef typename refmap_t::lookup_t lookup_t;
+    typedef etl::ipool         storage_t;
+
+  public:
+
+    typedef TKey              key_type;
+    typedef TMapped           mapped_type;
+    typedef TKeyCompare       key_compare;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef size_t            size_type;
+
+    typedef typename refmap_t::iterator       iterator;
+    typedef typename refmap_t::const_iterator const_iterator;
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+  protected:
+
+    typedef typename etl::parameter_type<TKey>::type key_parameter_t;
+
+  private:
+
+    //*********************************************************************
+    /// How to compare elements and keys.
+    //*********************************************************************
+    class compare
+    {
+    public:
+
+      bool operator ()(const value_type& element, key_type key) const
+      {
+        return key_compare()(element.first, key);
+      }
+
+      bool operator ()(key_type key, const value_type& element) const
+      {
+        return key_compare()(key, element.first);
+      }
+    };
+
+  public:
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the flat_multimap.
+    ///\return An iterator to the beginning of the flat_multimap.
+    //*********************************************************************
+    iterator begin()
+    {
+      return refmap_t::begin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the flat_multimap.
+    ///\return A const iterator to the beginning of the flat_multimap.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return refmap_t::begin();
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the flat_multimap.
+    ///\return An iterator to the end of the flat_multimap.
+    //*********************************************************************
+    iterator end()
+    {
+      return refmap_t::end();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the flat_multimap.
+    ///\return A const iterator to the end of the flat_multimap.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return refmap_t::end();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the flat_multimap.
+    ///\return A const iterator to the beginning of the flat_multimap.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return refmap_t::cbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the flat_multimap.
+    ///\return A const iterator to the end of the flat_multimap.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return refmap_t::cend();
+    }
+
+    //*********************************************************************
+    /// Returns an reverse iterator to the reverse beginning of the flat_multimap.
+    ///\return Iterator to the reverse beginning of the flat_multimap.
+    //*********************************************************************
+    reverse_iterator rbegin()
+    {
+      return refmap_t::rbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the flat_multimap.
+    ///\return Const iterator to the reverse beginning of the flat_multimap.
+    //*********************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return refmap_t::rbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a reverse iterator to the end + 1 of the flat_multimap.
+    ///\return Reverse iterator to the end + 1 of the flat_multimap.
+    //*********************************************************************
+    reverse_iterator rend()
+    {
+      return refmap_t::rend();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the flat_multimap.
+    ///\return Const reverse iterator to the end + 1 of the flat_multimap.
+    //*********************************************************************
+    const_reverse_iterator rend() const
+    {
+      refmap_t::rend();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the flat_multimap.
+    ///\return Const reverse iterator to the reverse beginning of the flat_multimap.
+    //*********************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return refmap_t::crbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the flat_multimap.
+    ///\return Const reverse iterator to the end + 1 of the flat_multimap.
+    //*********************************************************************
+    const_reverse_iterator crend() const
+    {
+      return refmap_t::crend();
+    }
+
+    //*********************************************************************
+    /// Assigns values to the flat_multimap.
+    /// If asserts or exceptions are enabled, emits flat_multimap_full if the flat_multimap does not have enough free space.
+    /// If asserts or exceptions are enabled, emits flat_multimap_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_multimap_full));
+#endif
+
+      clear();
+
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the flat_multimap.
+    /// If asserts or exceptions are enabled, emits flat_multimap_full if the flat_multimap is already full.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(const value_type& value)
+    {
+      ETL_ASSERT(!refmap_t::full(), ETL_ERROR(flat_multimap_full));
+
+      std::pair<iterator, bool> result(end(), false);
+
+      iterator i_element = lower_bound(value.first);
+
+      value_type* pvalue = storage.allocate<value_type>();
+      ::new (pvalue) value_type(value);
+      ++construct_count;
+      result = refmap_t::insert_at(i_element, *pvalue);
+
+      return result;
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the flast_multi.
+    /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map is already full.
+    ///\param position The position to insert at.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator position, const value_type& value)
+    {
+      return insert(value).first;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the flat_multimap.
+    /// If asserts or exceptions are enabled, emits flat_multimap_full if the flat_multimap does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param key The key to erase.
+    ///\return The number of elements erased. 0 or 1.
+    //*********************************************************************
+    size_t erase(key_parameter_t key)
+    {
+      std::pair<iterator, iterator> range = equal_range(key);
+
+      if (range.first == end())
+      {
+        return 0;
+      }
+      else
+      {
+        size_t d = std::distance(range.first, range.second);
+        erase(range.first, range.second);
+        return d;
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param i_element Iterator to the element.
+    //*********************************************************************
+    void erase(iterator i_element)
+    {
+      i_element->~value_type();
+      storage.release(etl::addressof(*i_element));
+      refmap_t::erase(i_element);
+      --construct_count;
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    //*********************************************************************
+    void erase(iterator first, iterator last)
+    {
+      iterator itr = first;
+
+      while (itr != last)
+      {
+        itr->~value_type();
+        storage.release(etl::addressof(*itr));
+        ++itr;
+        --construct_count;
+      }
+
+      refmap_t::erase(first, last);
+    }
+
+    //*************************************************************************
+    /// Clears the flat_multimap.
+    //*************************************************************************
+    void clear()
+    {
+      erase(begin(), end());
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    iterator find(key_parameter_t key)
+    {
+      return refmap_t::find(key);
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    const_iterator find(key_parameter_t key) const
+    {
+      return refmap_t::find(key);
+    }
+
+    //*********************************************************************
+    /// Counts an element.
+    ///\param key The key to search for.
+    ///\return 1 if the key exists, otherwise 0.
+    //*********************************************************************
+    size_t count(key_parameter_t key) const
+    {
+      return refmap_t::count(key);;
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator lower_bound(key_parameter_t key)
+    {
+      return refmap_t::lower_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator lower_bound(key_parameter_t key) const
+    {
+      return refmap_t::lower_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator upper_bound(key_parameter_t key)
+    {
+      return refmap_t::upper_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator upper_bound(key_parameter_t key) const
+    {
+      return refmap_t::upper_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<iterator, iterator> equal_range(key_parameter_t key)
+    {
+      return refmap_t::equal_range(key);
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
+    {
+      return refmap_t::equal_range(key);
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    iflat_multimap& operator = (const iflat_multimap& rhs)
+    {
+      if (&rhs != this)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Gets the current size of the flat_multiset.
+    ///\return The current size of the flat_multiset.
+    //*************************************************************************
+    size_type size() const
+    {
+      return refmap_t::size();
+    }
+
+    //*************************************************************************
+    /// Checks the 'empty' state of the flat_multiset.
+    ///\return <b>true</b> if empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return refmap_t::empty();
+    }
+
+    //*************************************************************************
+    /// Checks the 'full' state of the flat_multiset.
+    ///\return <b>true</b> if full.
+    //*************************************************************************
+    bool full() const
+    {
+      return refmap_t::full();
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the flat_multiset.
+    ///\return The capacity of the flat_multiset.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return refmap_t::capacity();
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the flat_multiset.
+    ///\return The maximum size of the flat_multiset.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return refmap_t::max_size();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return refmap_t::available();
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    iflat_multimap(lookup_t& lookup_, storage_t& storage_)
+      : refmap_t(lookup_),
+        storage(storage_)
+    {
+    }
+
+  private:
+
+    // Disable copy construction.
+    iflat_multimap(const iflat_multimap&);
+
+    storage_t& storage;
+
+    /// Internal debugging.
+    etl::debug_count construct_count;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first flat_multimap.
+  ///\param rhs Reference to the second flat_multimap.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup flat_multimap
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator ==(const etl::iflat_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iflat_multimap<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first flat_multimap.
+  ///\param rhs Reference to the second flat_multimap.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup flat_multimap
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator !=(const etl::iflat_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iflat_multimap<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //***************************************************************************
+  /// A flat_multimap implementation that uses a fixed size buffer.
+  ///\tparam TKey     The key type.
+  ///\tparam TValue   The value type.
+  ///\tparam TCompare The type to compare keys. Default = std::less<TKey>
+  ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+  ///\ingroup flat_multimap
+  //***************************************************************************
+  template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> >
+  class flat_multimap : public etl::iflat_multimap<TKey, TValue, TCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    flat_multimap()
+      : etl::iflat_multimap<TKey, TValue, TCompare>(lookup, storage)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    flat_multimap(const flat_multimap& other)
+      : etl::iflat_multimap<TKey, TValue, TCompare>(lookup, storage)
+    {
+      etl::iflat_multimap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    flat_multimap(TIterator first, TIterator last)
+      : etl::iflat_multimap<TKey, TValue, TCompare>(lookup, storage)
+    {
+      etl::iflat_multimap<TKey, TValue, TCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~flat_multimap()
+    {
+      etl::iflat_multimap<TKey, TValue, TCompare>::clear();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    flat_multimap& operator = (const flat_multimap& rhs)
+    {
+      if (&rhs != this)
+      {
+        etl::iflat_multimap<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    typedef typename etl::iflat_multimap<TKey, TValue, TCompare>::value_type node_t;
+
+    // The pool of nodes.
+    etl::pool<node_t, MAX_SIZE> storage;
+
+    // The vector that stores pointers to the nodes.
+    etl::vector<node_t*, MAX_SIZE> lookup;
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flat_multiset.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,618 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+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 __ETL_FLAT_MULTISET__
+#define __ETL_FLAT_MULTISET__
+
+#include "platform.h"
+#include "reference_flat_multiset.h"
+#include "pool.h"
+
+#undef ETL_FILE
+#define ETL_FILE "4"
+
+//*****************************************************************************
+///\defgroup flat_multiset flat_multiset
+/// A flat_multiset with the capacity defined at compile time.
+/// Has insertion of O(N) and flat_multiset of O(logN)
+/// Duplicate entries and not allowed.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for specifically sized flat_multisets.
+  /// Can be used as a reference type for all flat_multisets containing a specific type.
+  ///\ingroup flat_multiset
+  //***************************************************************************
+  template <typename T, typename TKeyCompare = std::less<T> >
+  class iflat_multiset : private etl::ireference_flat_multiset<T, TKeyCompare>
+  {
+  private:
+
+    typedef etl::ireference_flat_multiset<T, TKeyCompare> refset_t;
+    typedef typename refset_t::lookup_t lookup_t;
+    typedef etl::ipool storage_t;
+
+  public:
+
+    typedef T                 key_type;
+    typedef T                 value_type;
+    typedef TKeyCompare       key_compare;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef size_t            size_type;
+
+    typedef typename refset_t::iterator       iterator;
+    typedef typename refset_t::const_iterator const_iterator;
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+  protected:
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+
+  public:
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the flat_multiset.
+    ///\return An iterator to the beginning of the flat_multiset.
+    //*********************************************************************
+    iterator begin()
+    {
+      return refset_t::begin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the flat_multiset.
+    ///\return A const iterator to the beginning of the flat_multiset.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return refset_t::begin();
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the flat_multiset.
+    ///\return An iterator to the end of the flat_multiset.
+    //*********************************************************************
+    iterator end()
+    {
+      return refset_t::end();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the flat_multiset.
+    ///\return A const iterator to the end of the flat_multiset.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return refset_t::end();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the flat_multiset.
+    ///\return A const iterator to the beginning of the flat_multiset.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return refset_t::cbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the flat_multiset.
+    ///\return A const iterator to the end of the flat_multiset.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return refset_t::cend();
+    }
+
+    //*********************************************************************
+    /// Returns an reverse iterator to the reverse beginning of the flat_multiset.
+    ///\return Iterator to the reverse beginning of the flat_multiset.
+    //*********************************************************************
+    reverse_iterator rbegin()
+    {
+      return refset_t::rbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the flat_multiset.
+    ///\return Const iterator to the reverse beginning of the flat_multiset.
+    //*********************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return refset_t::rbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a reverse iterator to the end + 1 of the flat_multiset.
+    ///\return Reverse iterator to the end + 1 of the flat_multiset.
+    //*********************************************************************
+    reverse_iterator rend()
+    {
+      return refset_t::rend();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the flat_multiset.
+    ///\return Const reverse iterator to the end + 1 of the flat_multiset.
+    //*********************************************************************
+    const_reverse_iterator rend() const
+    {
+      return refset_t::rend();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the flat_multiset.
+    ///\return Const reverse iterator to the reverse beginning of the flat_multiset.
+    //*********************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return refset_t::crbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the flat_multiset.
+    ///\return Const reverse iterator to the end + 1 of the flat_multiset.
+    //*********************************************************************
+    const_reverse_iterator crend() const
+    {
+      return refset_t::crend();
+    }
+
+    //*********************************************************************
+    /// Assigns values to the flat_multiset.
+    /// If asserts or exceptions are enabled, emits flat_multiset_full if the flat_multiset does not have enough free space.
+    /// If asserts or exceptions are enabled, emits flat_multiset_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_multiset_full));
+#endif
+
+      clear();
+
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the flat_multiset.
+    /// If asserts or exceptions are enabled, emits flat_multiset_full if the flat_multiset is already full.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(parameter_t value)
+    {
+      std::pair<iterator, bool> result(end(), false);
+
+      ETL_ASSERT(!full(), ETL_ERROR(flat_multiset_full));
+
+      iterator i_element = std::lower_bound(begin(), end(), value, TKeyCompare());
+
+      ETL_ASSERT(!full(), ETL_ERROR(flat_multiset_full));
+
+      value_type* pvalue = storage.allocate<value_type>();
+      ::new (pvalue) value_type(value);
+      ++construct_count;
+      result = refset_t::insert_at(i_element, *pvalue);
+
+      return result;
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the flat_multiset.
+    /// If asserts or exceptions are enabled, emits flat_multiset_full if the flat_multiset is already full.
+    ///\param position The position to insert at.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator position, parameter_t value)
+    {
+      return insert(value).first;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the flat_multiset.
+    /// If asserts or exceptions are enabled, emits flat_multiset_full if the flat_multiset does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param key The key to erase.
+    ///\return The number of elements erased. 0 or 1.
+    //*********************************************************************
+    size_t erase(parameter_t key)
+    {
+      std::pair<iterator, iterator> range = equal_range(key);
+
+      if (range.first == end())
+      {
+        return 0;
+      }
+      else
+      {
+        size_t d = std::distance(range.first, range.second);
+        erase(range.first, range.second);
+        return d;
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param i_element Iterator to the element.
+    //*********************************************************************
+    void erase(iterator i_element)
+    {
+      i_element->~value_type();
+      storage.release(etl::addressof(*i_element));
+      refset_t::erase(i_element);
+      --construct_count;
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    //*********************************************************************
+    void erase(iterator first, iterator last)
+    {
+      iterator itr = first;
+
+      while (itr != last)
+      {
+        itr->~value_type();
+        storage.release(etl::addressof(*itr));
+        ++itr;
+        --construct_count;
+      }
+
+      refset_t::erase(first, last);
+    }
+
+    //*************************************************************************
+    /// Clears the flat_multiset.
+    //*************************************************************************
+    void clear()
+    {
+      erase(begin(), end());
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    iterator find(parameter_t key)
+    {
+      return refset_t::find(key);
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    const_iterator find(parameter_t key) const
+    {
+      return refset_t::find(key);
+    }
+
+    //*********************************************************************
+    /// Counts an element.
+    ///\param key The key to search for.
+    ///\return 1 if the key exists, otherwise 0.
+    //*********************************************************************
+    size_t count(parameter_t key) const
+    {
+      return refset_t::count(key);
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator lower_bound(parameter_t key)
+    {
+      return refset_t::lower_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator lower_bound(parameter_t key) const
+    {
+      return refset_t::lower_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator upper_bound(parameter_t key)
+    {
+      return refset_t::upper_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator upper_bound(parameter_t key) const
+    {
+      return refset_t::upper_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<iterator, iterator> equal_range(parameter_t key)
+    {
+      return refset_t::equal_range(key);
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(parameter_t key) const
+    {
+      return refset_t::equal_range(key);
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    iflat_multiset& operator = (const iflat_multiset& rhs)
+    {
+      if (&rhs != this)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Gets the current size of the flat_multiset.
+    ///\return The current size of the flat_multiset.
+    //*************************************************************************
+    size_type size() const
+    {
+      return refset_t::size();
+    }
+
+    //*************************************************************************
+    /// Checks the 'empty' state of the flat_multiset.
+    ///\return <b>true</b> if empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return refset_t::empty();
+    }
+
+    //*************************************************************************
+    /// Checks the 'full' state of the flat_multiset.
+    ///\return <b>true</b> if full.
+    //*************************************************************************
+    bool full() const
+    {
+      return refset_t::full();
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the flat_multiset.
+    ///\return The capacity of the flat_multiset.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return refset_t::capacity();
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the flat_multiset.
+    ///\return The maximum size of the flat_multiset.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return refset_t::max_size();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return refset_t::available();
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    iflat_multiset(lookup_t& lookup_, storage_t& storage_)
+      : refset_t(lookup_),
+        storage(storage_)
+    {
+    }
+
+  private:
+
+    // Disable copy construction.
+    iflat_multiset(const iflat_multiset&);
+
+    storage_t& storage;
+
+    /// Internal debugging.
+    etl::debug_count construct_count;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first flat_multiset.
+  ///\param rhs Reference to the second flat_multiset.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup flat_multiset
+  //***************************************************************************
+  template <typename T, typename TKeyCompare>
+  bool operator ==(const etl::iflat_multiset<T, TKeyCompare>& lhs, const etl::iflat_multiset<T, TKeyCompare>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first flat_multiset.
+  ///\param rhs Reference to the second flat_multiset.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup flat_multiset
+  //***************************************************************************
+  template <typename T, typename TKeyCompare>
+  bool operator !=(const etl::iflat_multiset<T, TKeyCompare>& lhs, const etl::iflat_multiset<T, TKeyCompare>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //***************************************************************************
+  /// A flat_multiset implementation that uses a fixed size buffer.
+  ///\tparam T        The value type.
+  ///\tparam TCompare The type to compare keys. Default = std::less<T>
+  ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+  ///\ingroup flat_multiset
+  //***************************************************************************
+  template <typename T, const size_t MAX_SIZE_, typename TCompare = std::less<T> >
+  class flat_multiset : public etl::iflat_multiset<T, TCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    flat_multiset()
+      : etl::iflat_multiset<T, TCompare>(lookup, storage)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    flat_multiset(const flat_multiset& other)
+      : iflat_multiset<T, TCompare>(lookup, storage)
+    {
+      etl::iflat_multiset<T, TCompare>::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    flat_multiset(TIterator first, TIterator last)
+      : iflat_multiset<T, TCompare>(lookup, storage)
+    {
+      etl::iflat_multiset<T, TCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~flat_multiset()
+    {
+      etl::iflat_multiset<T, TCompare>::clear();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    flat_multiset& operator = (const flat_multiset& rhs)
+    {
+      if (&rhs != this)
+      {
+        etl::iflat_multiset<T, TCompare>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    typedef typename etl::iflat_multiset<T, TCompare>::value_type node_t;
+
+    // The pool of nodes.
+    etl::pool<node_t, MAX_SIZE> storage;
+
+    // The vector that stores pointers to the nodes.
+    etl::vector<node_t*, MAX_SIZE> lookup;
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flat_set.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,622 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+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 __ETL_FLAT_SET__
+#define __ETL_FLAT_SET__
+
+#include "platform.h"
+#include "reference_flat_set.h"
+#include "pool.h"
+
+#undef ETL_FILE
+#define ETL_FILE "5"
+
+//*****************************************************************************
+///\defgroup flat_set flat_set
+/// A flat_set with the capacity defined at compile time.
+/// Has insertion of O(N) and flat_set of O(logN)
+/// Duplicate entries and not allowed.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for specifically sized flat_sets.
+  /// Can be used as a reference type for all flat_sets containing a specific type.
+  ///\ingroup flat_set
+  //***************************************************************************
+  template <typename T, typename TKeyCompare = std::less<T> >
+  class iflat_set : private etl::ireference_flat_set<T, TKeyCompare>
+  {
+  private:
+
+    typedef etl::ireference_flat_set<T, TKeyCompare> refset_t;
+    typedef typename refset_t::lookup_t lookup_t;
+    typedef etl::ipool storage_t;
+
+  public:
+
+    typedef T                 key_type;
+    typedef T                 value_type;
+    typedef TKeyCompare       key_compare;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef size_t            size_type;
+
+    typedef typename refset_t::iterator       iterator;
+    typedef typename refset_t::const_iterator const_iterator;
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+  protected:
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+
+  public:
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the flat_set.
+    ///\return An iterator to the beginning of the flat_set.
+    //*********************************************************************
+    iterator begin()
+    {
+      return refset_t::begin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the flat_set.
+    ///\return A const iterator to the beginning of the flat_set.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return refset_t::begin();
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the flat_set.
+    ///\return An iterator to the end of the flat_set.
+    //*********************************************************************
+    iterator end()
+    {
+      return refset_t::end();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the flat_set.
+    ///\return A const iterator to the end of the flat_set.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return refset_t::end();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the flat_set.
+    ///\return A const iterator to the beginning of the flat_set.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return refset_t::cbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the flat_set.
+    ///\return A const iterator to the end of the flat_set.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return refset_t::cend();
+    }
+
+    //*********************************************************************
+    /// Returns an reverse iterator to the reverse beginning of the flat_set.
+    ///\return Iterator to the reverse beginning of the flat_set.
+    //*********************************************************************
+    reverse_iterator rbegin()
+    {
+      return refset_t::rbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the flat_set.
+    ///\return Const iterator to the reverse beginning of the flat_set.
+    //*********************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return refset_t::rbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a reverse iterator to the end + 1 of the flat_set.
+    ///\return Reverse iterator to the end + 1 of the flat_set.
+    //*********************************************************************
+    reverse_iterator rend()
+    {
+      return refset_t::rend();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the flat_set.
+    ///\return Const reverse iterator to the end + 1 of the flat_set.
+    //*********************************************************************
+    const_reverse_iterator rend() const
+    {
+      return refset_t::rend();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the flat_set.
+    ///\return Const reverse iterator to the reverse beginning of the flat_set.
+    //*********************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return refset_t::crbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the flat_set.
+    ///\return Const reverse iterator to the end + 1 of the flat_set.
+    //*********************************************************************
+    const_reverse_iterator crend() const
+    {
+      return refset_t::crend();
+    }
+
+    //*********************************************************************
+    /// Assigns values to the flat_set.
+    /// If asserts or exceptions are enabled, emits flat_set_full if the flat_set does not have enough free space.
+    /// If asserts or exceptions are enabled, emits flat_set_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_set_full));
+#endif
+
+      clear();
+
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the flat_set.
+    /// If asserts or exceptions are enabled, emits flat_set_full if the flat_set is already full.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(parameter_t value)
+    {
+      iterator i_element = lower_bound(value);
+
+      std::pair<iterator, bool> result(i_element, false);
+
+      // Doesn't already exist?
+      if ((i_element == end() || (*i_element != value)))
+      {
+        ETL_ASSERT(!refset_t::full(), ETL_ERROR(flat_set_full));
+
+        value_type* pvalue = storage.allocate<value_type>();
+        ::new (pvalue) value_type(value);
+        ++construct_count;
+        result = refset_t::insert_at(i_element, *pvalue);
+      }
+
+      return result;
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the flat_set.
+    /// If asserts or exceptions are enabled, emits flat_set_full if the flat_set is already full.
+    ///\param position The position to insert at.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator position, parameter_t value)
+    {
+      return insert(value).first;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the flat_set.
+    /// If asserts or exceptions are enabled, emits flat_set_full if the flat_set does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param key The key to erase.
+    ///\return The number of elements erased. 0 or 1.
+    //*********************************************************************
+    size_t erase(parameter_t key)
+    {
+      iterator i_element = find(key);
+
+      if (i_element == end())
+      {
+        return 0;
+      }
+      else
+      {
+        i_element->~value_type();
+        storage.release(etl::addressof(*i_element));
+        refset_t::erase(i_element);
+        --construct_count;
+        return 1;
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param i_element Iterator to the element.
+    //*********************************************************************
+    void erase(iterator i_element)
+    {
+      i_element->~value_type();
+      storage.release(etl::addressof(*i_element));
+      refset_t::erase(i_element);
+      --construct_count;
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    //*********************************************************************
+    void erase(iterator first, iterator last)
+    {
+      iterator itr = first;
+
+      while (itr != last)
+      {
+        itr->~value_type();
+        storage.release(etl::addressof(*itr));
+        ++itr;
+        --construct_count;
+      }
+
+      refset_t::erase(first, last);
+    }
+
+    //*************************************************************************
+    /// Clears the flat_set.
+    //*************************************************************************
+    void clear()
+    {
+      erase(begin(), end());
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    iterator find(parameter_t key)
+    {
+      return refset_t::find(key);
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    const_iterator find(parameter_t key) const
+    {
+      return refset_t::find(key);
+    }
+
+    //*********************************************************************
+    /// Counts an element.
+    ///\param key The key to search for.
+    ///\return 1 if the key exists, otherwise 0.
+    //*********************************************************************
+    size_t count(parameter_t key) const
+    {
+      return refset_t::count(key);
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator lower_bound(parameter_t key)
+    {
+      return refset_t::lower_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator lower_bound(parameter_t key) const
+    {
+      return refset_t::lower_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator upper_bound(parameter_t key)
+    {
+      return refset_t::upper_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator upper_bound(parameter_t key) const
+    {
+      return refset_t::upper_bound(key);
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<iterator, iterator> equal_range(parameter_t key)
+    {
+      return refset_t::equal_range(key);
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(parameter_t key) const
+    {
+      return refset_t::upper_bound(key);
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    iflat_set& operator = (const iflat_set& rhs)
+    {
+      if (&rhs != this)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Gets the current size of the flat_set.
+    ///\return The current size of the flat_set.
+    //*************************************************************************
+    size_type size() const
+    {
+      return refset_t::size();
+    }
+
+    //*************************************************************************
+    /// Checks the 'empty' state of the flat_set.
+    ///\return <b>true</b> if empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return refset_t::empty();
+    }
+
+    //*************************************************************************
+    /// Checks the 'full' state of the flat_set.
+    ///\return <b>true</b> if full.
+    //*************************************************************************
+    bool full() const
+    {
+      return refset_t::full();
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the flat_set.
+    ///\return The capacity of the flat_set.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return refset_t::capacity();
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the flat_set.
+    ///\return The maximum size of the flat_set.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return refset_t::max_size();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return refset_t::available();
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    iflat_set(lookup_t& lookup_, storage_t& storage_)
+      : refset_t(lookup_),
+        storage(storage_)
+    {
+    }
+
+  private:
+
+    // Disable copy construction.
+    iflat_set(const iflat_set&);
+
+    storage_t& storage;
+
+    /// Internal debugging.
+    etl::debug_count construct_count;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first flat_set.
+  ///\param rhs Reference to the second flat_set.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup flat_set
+  //***************************************************************************
+  template <typename T, typename TKeyCompare>
+  bool operator ==(const etl::iflat_set<T, TKeyCompare>& lhs, const etl::iflat_set<T, TKeyCompare>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first flat_set.
+  ///\param rhs Reference to the second flat_set.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup flat_set
+  //***************************************************************************
+  template <typename T, typename TKeyCompare>
+  bool operator !=(const etl::iflat_set<T, TKeyCompare>& lhs, const etl::iflat_set<T, TKeyCompare>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //***************************************************************************
+  /// A flat_set implementation that uses a fixed size buffer.
+  ///\tparam T        The value type.
+  ///\tparam TCompare The type to compare keys. Default = std::less<T>
+  ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+  ///\ingroup flat_set
+  //***************************************************************************
+  template <typename T, const size_t MAX_SIZE_, typename TCompare = std::less<T> >
+  class flat_set : public etl::iflat_set<T, TCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    flat_set()
+      : etl::iflat_set<T, TCompare>(lookup, storage)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    flat_set(const flat_set& other)
+      : etl::iflat_set<T, TCompare>(lookup, storage)
+    {
+      etl::iflat_set<T, TCompare>::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    flat_set(TIterator first, TIterator last)
+      : etl::iflat_set<T, TCompare>(lookup, storage)
+    {
+      etl::iflat_set<T, TCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~flat_set()
+    {
+      etl::iflat_set<T, TCompare>::clear();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    flat_set& operator = (const flat_set& rhs)
+    {
+      if (&rhs != this)
+      {
+        etl::iflat_set<T, TCompare>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    typedef typename etl::iflat_set<T, TCompare>::value_type node_t;
+
+    // The pool of nodes.
+    etl::pool<node_t, MAX_SIZE> storage;
+
+    // The vector that stores pointers to the nodes.
+    etl::vector<node_t*, MAX_SIZE> lookup;
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fnv_1.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,286 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_FNV_1__
+#define __ETL_FNV_1__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "static_assert.h"
+#include "type_traits.h"
+#include "ihash.h"
+#include "frame_check_sequence.h"
+
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300 
+#endif
+
+///\defgroup fnv_1 FNV-1 & FNV-1a 32 & 64 bit hash calculations
+///\ingroup maths
+
+namespace etl
+{
+  //***************************************************************************
+  /// fnv_1 policy.
+  /// Calculates FNV1.
+  //***************************************************************************
+  struct fnv_1_policy_64
+  {
+    typedef uint64_t value_type;
+
+    inline uint64_t initial() const
+    {
+      return OFFSET_BASIS;
+    }
+
+    inline uint64_t add(uint64_t hash, uint8_t value) const
+    {
+      hash *= PRIME;
+      hash ^= value;
+      return  hash;
+    }
+
+    inline uint64_t final(uint64_t hash) const
+    {
+      return hash;
+    }
+
+    static const uint64_t OFFSET_BASIS = 0xCBF29CE484222325;
+    static const uint64_t PRIME        = 0x00000100000001b3;
+  };
+  
+  //***************************************************************************
+  /// Calculates the fnv_1_64 hash.
+  ///\ingroup fnv_1_64
+  //***************************************************************************
+  class fnv_1_64 : public etl::frame_check_sequence<fnv_1_policy_64>
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    fnv_1_64()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    fnv_1_64(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+
+  //***************************************************************************
+  /// fnv_1a policy.
+  /// Calculates FNV1A.
+  //***************************************************************************
+  struct fnv_1a_policy_64
+    {
+    typedef uint64_t value_type;
+
+    inline uint64_t initial() const
+      {
+      return OFFSET_BASIS;
+    }
+
+    inline uint64_t add(uint64_t hash, uint8_t value) const
+    {
+      hash ^= value;
+      hash *= PRIME;
+      return hash;
+    }
+
+    inline uint64_t final(uint64_t hash) const
+    {
+      return hash;
+    }
+
+    static const uint64_t OFFSET_BASIS = 0xCBF29CE484222325;
+    static const uint64_t PRIME        = 0x00000100000001b3;
+  };
+
+  //***************************************************************************
+  /// Calculates the fnv_1a_64 hash.
+  ///\ingroup fnv_1a_64
+  //***************************************************************************
+  class fnv_1a_64 : public etl::frame_check_sequence<fnv_1a_policy_64>
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    fnv_1a_64()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    fnv_1a_64(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+
+  //***************************************************************************
+  /// fnv_1 policy.
+  /// Calculates FNV1.
+  //***************************************************************************
+  struct fnv_1_policy_32
+    {
+    typedef uint32_t value_type;
+      
+    inline uint32_t initial() const
+      {
+      return OFFSET_BASIS;
+    }
+
+    inline uint32_t add(uint32_t hash, uint8_t value) const
+    {
+      hash *= PRIME;
+      hash ^= value;
+      return hash;
+    }
+
+    inline uint32_t final(uint32_t hash) const
+    {
+      return hash;
+    }
+
+    static const uint32_t OFFSET_BASIS = 0x811C9DC5;
+    static const uint32_t PRIME        = 0x01000193;
+  };
+
+  //***************************************************************************
+  /// Calculates the fnv_1_32 hash.
+  ///\ingroup fnv_1_32
+  //***************************************************************************
+  class fnv_1_32 : public etl::frame_check_sequence<fnv_1_policy_32>
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    fnv_1_32()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    fnv_1_32(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+
+  //***************************************************************************
+  /// fnv_1a policy.
+  /// Calculates FNV1A.
+  //***************************************************************************
+  struct fnv_1a_policy_32
+    {
+    typedef uint32_t value_type;
+
+    inline uint32_t initial() const
+      {
+      return OFFSET_BASIS;
+    }
+
+    inline uint32_t add(uint32_t hash, uint8_t value) const
+    {
+      hash ^= value;
+      hash *= PRIME;
+      return hash;
+    }
+
+    inline uint32_t final(uint32_t hash) const
+    {
+      return hash;
+    }
+
+    static const uint32_t OFFSET_BASIS = 0x811C9DC5;
+    static const uint32_t PRIME        = 0x01000193;
+  };
+
+  //***************************************************************************
+  /// Calculates the fnv_1a_32 hash.
+  ///\ingroup fnv_1a_32
+  //***************************************************************************
+  class fnv_1a_32 : public etl::frame_check_sequence<fnv_1a_policy_32>
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    fnv_1a_32()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    fnv_1a_32(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/forward_list.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1494 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_FORWARD_LIST__
+#define __ETL_FORWARD_LIST__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "platform.h"
+#include "pool.h"
+#include "container.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "debug_count.h"
+#include "nullptr.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#undef ETL_FILE
+#define ETL_FILE "6"
+
+//*****************************************************************************
+///\defgroup forward_list forward_list
+/// A linked forward_list with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the forward_list.
+  ///\ingroup forward_list
+  //***************************************************************************
+  class forward_list_exception : public etl::exception
+  {
+  public:
+
+    forward_list_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Full exception for the forward_list.
+  ///\ingroup forward_list
+  //***************************************************************************
+  class forward_list_full : public etl::forward_list_exception
+  {
+  public:
+
+    forward_list_full(string_type file_name_, numeric_type line_number_)
+      : etl::forward_list_exception(ETL_ERROR_TEXT("forward_list:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Empty exception for the forward_list.
+  ///\ingroup forward_list
+  //***************************************************************************
+  class forward_list_empty : public etl::forward_list_exception
+  {
+  public:
+
+    forward_list_empty(string_type file_name_, numeric_type line_number_)
+      : etl::forward_list_exception(ETL_ERROR_TEXT("forward_list:empty", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the forward_list.
+  ///\ingroup forward_list
+  //***************************************************************************
+  class forward_list_iterator : public etl::forward_list_exception
+  {
+  public:
+
+    forward_list_iterator(string_type file_name_, numeric_type line_number_)
+      : etl::forward_list_exception(ETL_ERROR_TEXT("forward_list:iterator", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for all forward_lists.
+  ///\ingroup forward_list
+  //***************************************************************************
+  class forward_list_base
+  {
+  protected:
+
+    //*************************************************************************
+    /// The node element in the forward_list.
+    //*************************************************************************
+    struct node_t
+    {
+      node_t()
+        : next(std::nullptr)
+      {
+      }
+
+      node_t* next;
+    };
+
+  public:
+
+    typedef size_t size_type; ///< The type used for determining the size of forward_list.
+
+    //*************************************************************************
+    /// Gets the size of the forward_list.
+    //*************************************************************************
+    size_type size() const
+    {
+      return p_node_pool->size();
+    }
+
+    //*************************************************************************
+    /// Gets the maximum possible size of the forward_list.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return MAX_SIZE;
+    }
+
+    //*************************************************************************
+    /// Checks to see if the forward_list is empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return p_node_pool->empty();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the forward_list is full.
+    //*************************************************************************
+    bool full() const
+    {
+      return p_node_pool->full();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return p_node_pool->available();
+    }
+
+    //*************************************************************************
+    /// Reverses the forward_list.
+    //*************************************************************************
+    void reverse()
+    {
+      if (is_trivial_list())
+      {
+        return;
+      }
+
+      node_t* p_last = &start_node;
+      node_t* p_current = p_last->next;
+      node_t* p_next = p_current->next;
+
+      p_current->next = std::nullptr;
+
+      while (p_next != std::nullptr)
+      {
+        p_last = p_current;
+        p_current = p_next;
+        p_next = p_current->next;
+
+        p_current->next = p_last;
+      }
+
+      join(&start_node, p_current);
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// The constructor that is called from derived classes.
+    //*************************************************************************
+    forward_list_base(etl::ipool& node_pool_, size_type max_size_)
+      : p_node_pool(&node_pool_),
+        MAX_SIZE(max_size_)
+    {
+    }
+
+    //*************************************************************************
+    /// Get the head node.
+    //*************************************************************************
+    node_t& get_head()
+    {
+      return *start_node.next;
+    }
+
+    //*************************************************************************
+    /// Get the head node.
+    //*************************************************************************
+    const node_t& get_head() const
+    {
+      return *start_node.next;
+    }
+
+    //*************************************************************************
+    /// Insert a node.
+    //*************************************************************************
+    inline void insert_node_after(node_t& position, node_t& node)
+    {
+      // Connect to the forward_list.
+      join(&node, position.next);
+      join(&position, &node);
+    }
+
+    //*************************************************************************
+    /// Is the forward_list a trivial length?
+    //*************************************************************************
+    bool is_trivial_list() const
+    {
+      return (size() < 2);
+    }
+
+    //*************************************************************************
+    /// Join two nodes.
+    //*************************************************************************
+    void join(node_t* left, node_t* right)
+    {
+      left->next = right;
+    }
+
+    node_t           start_node;      ///< The node that acts as the forward_list start.
+    etl::ipool*      p_node_pool;     ///< The pool of data nodes used in the list.
+    const size_type  MAX_SIZE;        ///< The maximum size of the forward_list.
+    etl::debug_count construct_count; ///< Internal debugging.
+  };
+
+  //***************************************************************************
+  /// A templated base for all etl::forward_list types.
+  ///\ingroup forward_list
+  //***************************************************************************
+  template <typename T>
+  class iforward_list : public etl::forward_list_base
+  {
+  public:
+
+    typedef T        value_type;
+    typedef T*       pointer;
+    typedef const T* const_pointer;
+    typedef T&       reference;
+    typedef const T& const_reference;
+    typedef size_t   size_type;
+
+  protected:
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+
+    //*************************************************************************
+    /// The data node element in the forward_list.
+    //*************************************************************************
+    struct data_node_t : public node_t
+    {
+      explicit data_node_t(parameter_t value_)
+        : value(value_)
+      {}
+
+      T value;
+    };
+
+  public:
+
+    //*************************************************************************
+    /// iterator.
+    //*************************************************************************
+    class iterator : public std::iterator<std::forward_iterator_tag, T>
+    {
+    public:
+
+      friend class iforward_list;
+
+      iterator()
+        : p_node(std::nullptr)
+      {
+      }
+
+      iterator(node_t& node)
+        : p_node(&node)
+      {
+      }
+
+      iterator(const iterator& other)
+        : p_node(other.p_node)
+      {
+      }
+
+      iterator& operator ++()
+      {
+        p_node = p_node->next;
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        p_node = p_node->next;
+        return temp;
+      }
+
+      iterator operator =(const iterator& other)
+      {
+        p_node = other.p_node;
+        return *this;
+      }
+
+      reference operator *()
+      {
+        return iforward_list::data_cast(p_node)->value;
+      }
+
+      const_reference operator *() const
+      {
+        return iforward_list::data_cast(p_node)->value;
+      }
+
+      pointer operator &()
+      {
+        return &(iforward_list::data_cast(p_node)->value);
+      }
+
+      const_pointer operator &() const
+      {
+        return &(iforward_list::data_cast(p_node)->value);
+      }
+
+      pointer operator ->()
+      {
+        return &(iforward_list::data_cast(p_node)->value);
+      }
+
+      const_pointer operator ->() const
+      {
+        return &(iforward_list::data_cast(p_node)->value);
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.p_node == rhs.p_node;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      node_t* p_node;
+    };
+
+    //*************************************************************************
+    /// const_iterator
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::forward_iterator_tag, const T>
+    {
+    public:
+
+      friend class iforward_list;
+
+      const_iterator()
+        : p_node(std::nullptr)
+      {
+      }
+
+      const_iterator(node_t& node)
+        : p_node(&node)
+      {
+      }
+
+      const_iterator(const node_t& node)
+        : p_node(&node)
+      {
+      }
+
+      const_iterator(const typename iforward_list::iterator& other)
+        : p_node(other.p_node)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : p_node(other.p_node)
+      {
+      }
+
+      const_iterator& operator ++()
+      {
+        p_node = p_node->next;
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        p_node = p_node->next;
+        return temp;
+      }
+
+      const_iterator operator =(const const_iterator& other)
+      {
+        p_node = other.p_node;
+        return *this;
+      }
+
+      const_reference operator *() const
+      {
+        return iforward_list::data_cast(p_node)->value;
+      }
+
+      const_pointer operator &() const
+      {
+        return &(iforward_list::data_cast(p_node)->value);
+      }
+
+      const_pointer operator ->() const
+      {
+        return &(iforward_list::data_cast(p_node)->value);
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.p_node == rhs.p_node;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      const node_t* p_node;
+    };
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    //*************************************************************************
+    /// Gets the beginning of the forward_list.
+    //*************************************************************************
+    iterator begin()
+    {
+      return iterator(data_cast(get_head()));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the forward_list.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(data_cast(get_head()));
+    }
+
+    //*************************************************************************
+    /// Gets before the beginning of the forward_list.
+    //*************************************************************************
+    iterator before_begin()
+    {
+      return iterator(static_cast<data_node_t&>(start_node));
+    }
+
+    //*************************************************************************
+    /// Gets before the beginning of the forward_list.
+    //*************************************************************************
+    const_iterator before_begin() const
+    {
+      return const_iterator(static_cast<const data_node_t&>(start_node));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the forward_list.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(get_head());
+    }
+
+    //*************************************************************************
+    /// Gets the end of the forward_list.
+    //*************************************************************************
+    iterator end()
+    {
+      return iterator();
+    }
+
+    //*************************************************************************
+    /// Gets the end of the forward_list.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return const_iterator();
+    }
+
+    //*************************************************************************
+    /// Gets the end of the forward_list.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator();
+    }
+
+    //*************************************************************************
+    /// Clears the forward_list.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the first element.
+    //*************************************************************************
+    reference front()
+    {
+      return data_cast(get_head()).value;
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the first element.
+    //*************************************************************************
+    const_reference front() const
+    {
+      return data_cast(get_head()).value;
+    }
+
+    //*************************************************************************
+    /// Assigns a range of values to the forward_list.
+    /// If asserts or exceptions are enabled throws etl::forward_list_full if the forward_list does not have enough free space.
+    /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined throws forward_list_iterator if the iterators are reversed.
+    //*************************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(d >= 0, ETL_ERROR(forward_list_iterator));
+#endif
+
+      initialise();
+
+      node_t* p_last_node = &start_node;
+
+      // Add all of the elements.
+      while (first != last)
+      {
+        ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+
+        data_node_t& data_node = allocate_data_node(*first++);
+        join(p_last_node, &data_node);
+        data_node.next = std::nullptr;
+        p_last_node = &data_node;
+      }
+    }
+
+    //*************************************************************************
+    /// Assigns 'n' copies of a value to the forward_list.
+    //*************************************************************************
+    void assign(size_t n, parameter_t value)
+    {
+      ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(forward_list_full));
+
+      initialise();
+
+      node_t* p_last_node = &start_node;
+
+      // Add all of the elements.
+      while (size() < n)
+      {
+        data_node_t& data_node = allocate_data_node(value);
+        join(p_last_node, &data_node);
+        data_node.next = std::nullptr;
+        p_last_node = &data_node;
+      }
+    }
+
+    //*************************************************************************
+    /// Adds a node to the front of the forward_list so a new value can be assigned to front().
+    //*************************************************************************
+    void push_front()
+    {
+      push_front(T());
+    }
+
+    //*************************************************************************
+    /// Pushes a value to the front of the forward_list.
+    //*************************************************************************
+    void push_front(parameter_t value)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+#endif
+
+      data_node_t& data_node = allocate_data_node(value);
+      insert_node_after(start_node, data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the front of the list..
+    //*************************************************************************
+    template <typename T1>
+    void emplace_front(const T1& value1)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+#endif
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1);
+      ++construct_count;
+      insert_node_after(start_node, *p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the front of the list..
+    //*************************************************************************
+    template <typename T1, typename T2>
+    void emplace_front(const T1& value1, const T2& value2)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+#endif
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2);
+      ++construct_count;
+      insert_node_after(start_node, *p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the front of the list..
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3>
+    void emplace_front(const T1& value1, const T2& value2, const T3& value3)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+#endif
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2, value3);
+      ++construct_count;
+      insert_node_after(start_node, *p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the front of the list..
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    void emplace_front(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+#endif
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2, value3, value4);
+      ++construct_count;
+      insert_node_after(start_node, *p_data_node);
+    }
+
+    //*************************************************************************
+    /// Removes a value from the front of the forward_list.
+    //*************************************************************************
+    void pop_front()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(forward_list_empty));
+#endif
+      remove_node_after(start_node);
+    }
+
+    //*************************************************************************
+    /// Resizes the forward_list.
+    //*************************************************************************
+    void resize(size_t n)
+    {
+      resize(n, T());
+    }
+
+    //*************************************************************************
+    /// Resizes the forward_list.
+    /// If asserts or exceptions are enabled, will throw an etl::forward_list_full
+    /// if <b>n</b> is larger than the maximum size.
+    //*************************************************************************
+    void resize(size_t n, T value)
+    {
+      ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(forward_list_full));
+
+      size_t i = 0;
+      iterator i_node = begin();
+      iterator i_last_node;
+
+      // Find where we're currently at.
+      while ((i < n) && (i_node != end()))
+      {
+        ++i;
+        i_last_node = i_node;
+        ++i_node;
+      }
+
+      if (i_node != end())
+      {
+        // Reduce.
+        erase_after(i_last_node, end());
+      }
+      else if (i_node == end())
+      {
+        // Increase.
+        while (i < n)
+        {
+          i_last_node = insert_after(i_last_node, value);
+          ++i;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Inserts a value to the forward_list after the specified position.
+    //*************************************************************************
+    iterator insert_after(iterator position, parameter_t value)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+
+      data_node_t& data_node = allocate_data_node(value);
+      insert_node_after(*position.p_node, data_node);
+
+      return iterator(data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the forward_list after the specified position.
+    //*************************************************************************
+    template <typename T1>
+    iterator emplace_after(iterator position, const T1& value1)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1);
+      ++construct_count;
+      insert_node_after(*position.p_node, *p_data_node);
+
+      return iterator(*p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the forward_list after the specified position.
+    //*************************************************************************
+    template <typename T1, typename T2>
+    iterator emplace_after(iterator position, const T1& value1, const T2& value2)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2);
+      ++construct_count;
+      insert_node_after(*position.p_node, *p_data_node);
+
+      return iterator(*p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the forward_list after the specified position.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3>
+    iterator emplace_after(iterator position, const T1& value1, const T2& value2, const T3& value3)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2, value3);
+      ++construct_count;
+      insert_node_after(*position.p_node, *p_data_node);
+
+      return iterator(*p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the forward_list after the specified position.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    iterator emplace_after(iterator position, const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2, value3, value4);
+      ++construct_count;
+      insert_node_after(*position.p_node, *p_data_node);
+
+      return iterator(*p_data_node);
+    }
+
+    //*************************************************************************
+    /// Inserts 'n' copies of a value to the forward_list after the specified position.
+    //*************************************************************************
+    void insert_after(iterator position, size_t n, parameter_t value)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(forward_list_full));
+
+      for (size_t i = 0; !full() && (i < n); ++i)
+      {
+        // Set up the next free node.
+        data_node_t& data_node = allocate_data_node(value);
+        insert_node_after(*position.p_node, data_node);
+      }
+    }
+
+    //*************************************************************************
+    /// Inserts a range of values to the forward_list after the specified position.
+    //*************************************************************************
+    template <typename TIterator>
+    void insert_after(iterator position, TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT((d + size()) <= MAX_SIZE, ETL_ERROR(forward_list_full));
+#endif
+
+      while (first != last)
+      {
+        // Set up the next free node.
+        data_node_t& data_node = allocate_data_node(*first++);
+        insert_node_after(*position.p_node, data_node);
+        ++position;
+      }
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    iterator erase_after(iterator position)
+    {
+      iterator next(position);
+      if (next != end())
+      {
+        ++next;
+        if (next != end())
+        {
+          ++next;
+          remove_node_after(*position.p_node);
+        }
+      }
+
+      return next;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    //*************************************************************************
+    iterator erase_after(iterator first, iterator last)
+    {
+      if (first != end() && (first != last))
+      {
+        node_t* p_first = first.p_node;
+        node_t* p_last = last.p_node;
+        node_t* p_next = p_first->next;
+
+        // Join the ends.
+        join(p_first, p_last);
+
+        p_first = p_next;
+
+        // Erase the ones in between.
+        while (p_first != p_last)
+        {
+          p_next = p_first->next;                               // Remember the next node.
+          destroy_data_node(static_cast<data_node_t&>(*p_first)); // Destroy the pool object.
+          p_first = p_next;                                     // Move to the next node.
+        }
+
+        if (p_next == std::nullptr)
+        {
+          return end();
+        }
+        else
+        {
+          return iterator(*p_last);
+        }
+      }
+      else
+      {
+        return end();
+      }
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    void move_after(const_iterator from_before, const_iterator to_before)
+    {
+      if (from_before == to_before) // Can't move to after yourself!
+      {
+        return;
+      }
+
+      node_t* p_from_before = const_cast<node_t*>(from_before.p_node); // We're not changing the value, just it's position.
+      node_t* p_to_before = const_cast<node_t*>(to_before.p_node);   // We're not changing the value, just it's position.
+
+      node_t* p_from = p_from_before->next;
+
+      // Disconnect from the list.
+      join(p_from_before, p_from->next);
+
+      // Attach it to the new position.
+      join(p_from, p_to_before->next);
+      join(p_to_before, p_from);
+    }
+
+    //*************************************************************************
+    /// Moves a range from one position to another within the list.
+    /// Moves a range at position 'first_before'/'last' to the position before 'to_before'.
+    //*************************************************************************
+    void move_after(const_iterator first_before, const_iterator last, const_iterator to_before)
+    {
+      if ((first_before == to_before) || (last == to_before))
+      {
+        return; // Can't more to before yourself!
+      }
+
+#if defined(ETL_DEBUG)
+      // Check that we are not doing an illegal move!
+      for (const_iterator item = first_before; item != last; ++item)
+      {
+        ETL_ASSERT(item != to_before, ETL_ERROR(forward_list_iterator));
+      }
+#endif
+
+      node_t* p_first_before = const_cast<node_t*>(first_before.p_node); // We're not changing the value, just it's position.
+      node_t* p_last = const_cast<node_t*>(last.p_node);         // We're not changing the value, just it's position.
+      node_t* p_to_before = const_cast<node_t*>(to_before.p_node);    // We're not changing the value, just it's position.
+      node_t* p_first = p_first_before->next;
+      node_t* p_final = p_first_before;
+
+      // Find the last node that will be moved.
+      while (p_final->next != p_last)
+      {
+        p_final = p_final->next;
+      }
+
+      // Disconnect from the list.
+      join(p_first_before, p_final->next);
+
+      // Attach it to the new position.
+      join(p_final, p_to_before->next);
+      join(p_to_before, p_first);
+    }
+
+    //*************************************************************************
+    /// Removes all but the first element from every consecutive group of equal
+    /// elements in the container.
+    //*************************************************************************
+    void unique()
+    {
+      unique(std::equal_to<T>());
+    }
+
+    //*************************************************************************
+    /// Removes all but the one element from every consecutive group of equal
+    /// elements in the container.
+    //*************************************************************************
+    template <typename TIsEqual>
+    void unique(TIsEqual isEqual)
+    {
+      if (empty())
+      {
+        return;
+      }
+
+      node_t* last = &get_head();
+      node_t* current = last->next;
+
+      while (current != std::nullptr)
+      {
+        // Is this value the same as the last?
+        if (isEqual(data_cast(current)->value, data_cast(last)->value))
+        {
+          remove_node_after(*last);
+        }
+        else
+        {
+          // Move on one.
+          last = current;
+        }
+
+        current = last->next;
+      }
+    }
+
+    //*************************************************************************
+    /// Sort using in-place merge sort algorithm.
+    /// Uses 'less-than operator as the predicate.
+    //*************************************************************************
+    void sort()
+    {
+      sort(std::less<T>());
+    }
+
+    //*************************************************************************
+    /// Sort using in-place merge sort algorithm.
+    /// Uses a supplied predicate function or functor.
+    /// This is not my algorithm. I got it off the web somewhere.
+    //*************************************************************************
+    template <typename TCompare>
+    void sort(TCompare compare)
+    {
+      iterator p_left;
+      iterator p_right;
+      iterator p_node;
+      iterator p_head;
+      iterator p_tail;
+      int      list_size = 1;
+      int      number_of_merges;
+      int      left_size;
+      int      right_size;
+
+      if (is_trivial_list())
+      {
+        return;
+      }
+
+      while (true)
+      {
+        p_left = begin();
+        p_head = before_begin();
+        p_tail = before_begin();
+
+        number_of_merges = 0;  // Count the number of merges we do in this pass.
+
+        while (p_left != end())
+        {
+          ++number_of_merges;  // There exists a merge to be done.
+          p_right = p_left;
+          left_size = 0;
+
+          // Step 'list_size' places along from left
+          for (int i = 0; i < list_size; ++i)
+          {
+            ++left_size;
+
+            ++p_right;
+
+            if (p_right == end())
+            {
+              break;
+            }
+          }
+
+          // If right hasn't fallen off end, we have two lists to merge.
+          right_size = list_size;
+
+          // Now we have two lists. Merge them.
+          while (left_size > 0 || (right_size > 0 && p_right != end()))
+          {
+            // Decide whether the next node of merge comes from left or right.
+            if (left_size == 0)
+            {
+              // Left is empty. The node must come from right.
+              p_node = p_right;
+              ++p_right;
+              --right_size;
+            }
+            else if (right_size == 0 || p_right == end())
+            {
+              // Right is empty. The node must come from left.
+              p_node = p_left;
+              ++p_left;
+              --left_size;
+            }
+            else if (!compare(*p_right, *p_left))
+            {
+              // First node of left is lower or same. The node must come from left.
+              p_node = p_left;
+              ++p_left;
+              --left_size;
+            }
+            else
+            {
+              // First node of right is lower. The node must come from right.
+              p_node = p_right;
+              ++p_right;
+              --right_size;
+            }
+
+            // Add the next node to the merged head.
+            if (p_head == before_begin())
+            {
+              join(p_head.p_node, p_node.p_node);
+              p_head = p_node;
+              p_tail = p_node;
+            }
+            else
+            {
+              join(p_tail.p_node, p_node.p_node);
+              p_tail = p_node;
+            }
+
+            p_tail.p_node->next = std::nullptr;
+          }
+
+          // Now left has stepped `list_size' places along, and right has too.
+          p_left = p_right;
+        }
+
+        // If we have done only one merge, we're finished.
+        if (number_of_merges <= 1)   // Allow for number_of_merges == 0, the empty head case
+        {
+          return;
+        }
+
+        // Otherwise repeat, merging lists twice the size
+        list_size *= 2;
+      }
+    }
+
+    //*************************************************************************
+    // Removes the values specified.
+    //*************************************************************************
+    void remove(parameter_t value)
+    {
+      iterator i_item = begin();
+      iterator i_last_item = before_begin();
+
+      while (i_item != end())
+      {
+        if (*i_item == value)
+        {
+          i_item = erase_after(i_last_item);
+        }
+        else
+        {
+          ++i_item;
+          ++i_last_item;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Removes according to a predicate.
+    //*************************************************************************
+    template <typename TPredicate>
+    void remove_if(TPredicate predicate)
+    {
+      iterator i_item = begin();
+      iterator i_last_item = before_begin();
+
+      while (i_item != end())
+      {
+        if (predicate(*i_item))
+        {
+          i_item = erase_after(i_last_item);
+        }
+        else
+        {
+          ++i_item;
+          ++i_last_item;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    iforward_list& operator = (const iforward_list& rhs)
+    {
+      if (&rhs != this)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    iforward_list(etl::ipool& node_pool, size_t max_size_)
+      : forward_list_base(node_pool, max_size_)
+    {
+    }
+
+    //*************************************************************************
+    /// Initialise the forward_list.
+    //*************************************************************************
+    void initialise()
+    {
+      if (!empty())
+      {
+        node_t* p_first = start_node.next;
+        node_t* p_next;
+
+        // Erase the ones in between.
+        while (p_first != std::nullptr)
+        {
+          p_next = p_first->next;                                 // Remember the next node.
+          destroy_data_node(static_cast<data_node_t&>(*p_first)); // Destroy the pool object.
+          p_first = p_next;                                       // Move to the next node.
+        }
+      }
+
+      start_node.next = std::nullptr;
+    }
+
+  private:
+
+    //*************************************************************************
+    /// Downcast a node_t* to a data_node_t*
+    //*************************************************************************
+    static data_node_t* data_cast(node_t* p_node)
+    {
+      return static_cast<data_node_t*>(p_node);
+    }
+
+    //*************************************************************************
+    /// Downcast a node_t& to a data_node_t&
+    //*************************************************************************
+    static data_node_t& data_cast(node_t& node)
+    {
+      return static_cast<data_node_t&>(node);
+    }
+
+    //*************************************************************************
+    /// Downcast a const node_t* to a const data_node_t*
+    //*************************************************************************
+    static const data_node_t* data_cast(const node_t* p_node)
+    {
+      return static_cast<const data_node_t*>(p_node);
+    }
+
+    //*************************************************************************
+    /// Downcast a const node_t& to a const data_node_t&
+    //*************************************************************************
+    static const data_node_t& data_cast(const node_t& node)
+    {
+      return static_cast<const data_node_t&>(node);
+    }
+
+    //*************************************************************************
+    /// Remove a node.
+    //*************************************************************************
+    void remove_node_after(node_t& node)
+    {
+      // The node to erase.
+      node_t* p_node = node.next;
+
+      if (p_node != std::nullptr)
+      {
+        // Disconnect the node from the forward_list.
+        join(&node, p_node->next);
+
+        // Destroy the pool object.
+        destroy_data_node(static_cast<data_node_t&>(*p_node));
+      }
+    }
+
+    //*************************************************************************
+    /// Allocate a data_node_t.
+    //*************************************************************************
+    data_node_t& allocate_data_node(parameter_t value)
+    {
+      data_node_t* p_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_node->value)) T(value);
+      ++construct_count;
+
+      return *p_node;
+    }
+
+    //*************************************************************************
+    /// Destroy a data_node_t.
+    //*************************************************************************
+    void destroy_data_node(data_node_t& node)
+    {
+      node.value.~T();
+      p_node_pool->release(&node);
+      --construct_count;
+    }
+
+    // Disable copy construction.
+    iforward_list(const iforward_list&);
+  };
+
+  //*************************************************************************
+  /// A templated forward_list implementation that uses a fixed size pool.
+  ///\note 'merge' and 'splice_after' and are not supported.
+  //*************************************************************************
+  template <typename T, const size_t MAX_SIZE_>
+  class forward_list : public etl::iforward_list<T>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+  public:
+
+    typedef T        value_type;
+    typedef T*       pointer;
+    typedef const T* const_pointer;
+    typedef T&       reference;
+    typedef const T& const_reference;
+    typedef size_t   size_type;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    forward_list()
+      : etl::iforward_list<T>(node_pool, MAX_SIZE)
+    {
+      etl::iforward_list<T>::initialise();
+    }
+
+    //*************************************************************************
+    /// Construct from size and value.
+    //*************************************************************************
+    explicit forward_list(size_t initial_size, typename etl::iforward_list<T>::parameter_t value = T())
+      : etl::iforward_list<T>(node_pool, MAX_SIZE)
+    {
+      etl::iforward_list<T>::assign(initial_size, value);
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    forward_list(const forward_list& other)
+      : etl::iforward_list<T>(node_pool, MAX_SIZE)
+    {
+      etl::iforward_list<T>::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Construct from range.
+    //*************************************************************************
+    template <typename TIterator>
+    forward_list(TIterator first, TIterator last)
+      : etl::iforward_list<T>(node_pool, MAX_SIZE)
+    {
+      etl::iforward_list<T>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~forward_list()
+    {
+      etl::iforward_list<T>::initialise();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    forward_list& operator = (const forward_list& rhs)
+    {
+      if (&rhs != this)
+      {
+        etl::iforward_list<T>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    /// The pool of nodes used in the list.
+    etl::pool<typename etl::iforward_list<T>::data_node_t, MAX_SIZE> node_pool;
+  };
+}
+
+//*************************************************************************
+/// Equal operator.
+///\param lhs Reference to the first forward_list.
+///\param rhs Reference to the second forward_list.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator ==(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs)
+{
+  return (lhs.size() == rhs.size()) &&
+    std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//*************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the first forward_list.
+///\param rhs Reference to the second forward_list.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator !=(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs)
+{
+  return !(lhs == rhs);
+}
+
+//*************************************************************************
+/// Less than operator.
+///\param lhs Reference to the first forward_list.
+///\param rhs Reference to the second forward_list.
+///\return <b>true</b> if the first forward_list is lexicographically less than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator <(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs)
+{
+  return std::lexicographical_compare(lhs.begin(),
+    lhs.end(),
+    rhs.begin(),
+    rhs.end());
+}
+
+//*************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the first forward_list.
+///\param rhs Reference to the second forward_list.
+///\return <b>true</b> if the first forward_list is lexicographically greater than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator >(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs)
+{
+  return (rhs < lhs);
+}
+
+//*************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the first forward_list.
+///\param rhs Reference to the second forward_list.
+///\return <b>true</b> if the first forward_list is lexicographically less than or equal
+/// to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator <=(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs)
+{
+  return !(lhs > rhs);
+}
+
+//*************************************************************************
+/// Greater than or equal operator.
+///\param lhs Reference to the first forward_list.
+///\param rhs Reference to the second forward_list.
+///\return <b>true</b> if the first forward_list is lexicographically greater than or
+/// equal to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator >=(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs)
+{
+  return !(lhs < rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/frame_check_sequence.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,137 @@
+
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+Copyright(c) 2014 jwellbelove
+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 __ETL_FRAME_CHECK_SEQUENCE__
+#define __ETL_FRAME_CHECK_SEQUENCE__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "static_assert.h"
+#include "type_traits.h"
+#include "binary.h"
+
+STATIC_ASSERT(ETL_8BIT_SUPPORT, "This file does not currently support targets with no 8bit type");
+
+///\defgroup frame_check_sequence Frame check sequence calculation
+///\ingroup maths
+
+namespace etl
+{
+  //***************************************************************************
+  /// Calculates a frame check sequence according to the specified policy.
+  ///\tparam TPolicy The type used to enact the policy.
+  ///\ingroup frame_check_sequence
+  //***************************************************************************
+  template <typename TPolicy>
+  class frame_check_sequence
+  {
+  public:
+
+    typedef TPolicy policy_type;
+    typedef typename policy_type::value_type value_type;
+
+    STATIC_ASSERT(etl::is_unsigned<value_type>::value, "Signed frame check type not supported");
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    frame_check_sequence()
+    {
+      reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    frame_check_sequence(TIterator begin, const TIterator end)
+    {
+      STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+      reset();
+      add(begin, end);
+    }
+
+    //*************************************************************************
+    /// Resets the FCS to the initial state.
+    //*************************************************************************
+    void reset()
+    {
+      frame_check = policy.initial();
+    }
+
+    //*************************************************************************
+    /// Adds a range.
+    /// \param begin
+    /// \param end
+    //*************************************************************************
+    template<typename TIterator>
+    void add(TIterator begin, const TIterator end)
+    {
+      STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+      while (begin != end)
+      {
+        frame_check = policy.add(frame_check, *begin++);
+      }
+    }
+
+    //*************************************************************************
+    /// \param value The uint8_t to add to the FCS.
+    //*************************************************************************
+    void add(uint8_t value_)
+    {
+      frame_check = policy.add(frame_check, value_);
+    }
+
+    //*************************************************************************
+    /// Gets the FCS value.
+    //*************************************************************************
+    value_type value()
+    {
+      return policy.final(frame_check);
+    }
+
+    //*************************************************************************
+    /// Conversion operator to value_type.
+    //*************************************************************************
+    operator value_type ()
+    {
+      return policy.final(frame_check);
+    }
+
+  private:
+
+    value_type  frame_check;
+    policy_type policy;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fsm.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1216 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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.
+******************************************************************************/
+
+#if 0
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+#endif
+
+//***************************************************************************
+// This file has been auto generated. Do not edit this file.
+//***************************************************************************
+
+//***************************************************************************
+// To generate to header file, run this at the command line.
+// Note: You will need Python and COG installed.
+//
+// python -m cogapp -d -e -ofsm.h -DHandlers=<n> fsm_generator.h
+// Where <n> is the number of messages to support.
+//
+// e.g.
+// To generate handlers for up to 16 events...
+// python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h
+//
+// See generate.bat
+//***************************************************************************
+
+#ifndef __ETL_FSM__
+#define __ETL_FSM__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "array.h"
+#include "nullptr.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "user_type.h"
+#include "message_router.h"
+#include "integral_limits.h"
+#include "largest.h"
+
+#undef ETL_FILE
+#define ETL_FILE "34"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef max
+#endif
+
+namespace etl
+{
+  class fsm;
+
+  /// Allow alternative type for state id.
+#if !defined(ETL_FSM_STATE_ID_TYPE)
+    typedef uint_least8_t fsm_state_id_t;
+#else
+    typedef ETL_FSM_STATE_ID_TYPE fsm_state_id_t;
+#endif
+
+  // For internal FSM use.
+  typedef typename etl::larger_type<etl::message_id_t>::type fsm_internal_id_t;
+
+  //***************************************************************************
+  /// Base exception class for FSM.
+  //***************************************************************************
+  class fsm_exception : public etl::exception
+  {
+  public:
+
+    fsm_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Exception for null state pointer.
+  //***************************************************************************
+  class fsm_null_state_exception : public etl::fsm_exception
+  {
+  public:
+
+    fsm_null_state_exception(string_type file_name_, numeric_type line_number_)
+      : etl::fsm_exception(ETL_ERROR_TEXT("fsm:null state", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Exception for invalid state id.
+  //***************************************************************************
+  class fsm_state_id_exception : public etl::fsm_exception
+  {
+  public:
+
+    fsm_state_id_exception(string_type file_name_, numeric_type line_number_)
+      : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state id", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Exception for incompatible state list.
+  //***************************************************************************
+  class fsm_state_list_exception : public etl::fsm_exception
+  {
+  public:
+
+    fsm_state_list_exception(string_type file_name_, numeric_type line_number_)
+      : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state list", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Interface class for FSM states.
+  //***************************************************************************
+  class ifsm_state
+  {
+  public:
+
+    /// Allows ifsm_state functions to be private.
+    friend class etl::fsm;
+
+    //*******************************************
+    /// Gets the id for this state.
+    //*******************************************
+    etl::fsm_state_id_t get_state_id() const
+    {
+      return state_id;
+    }
+
+  protected:
+
+    //*******************************************
+    /// Constructor.
+    //*******************************************
+    ifsm_state(etl::fsm_state_id_t state_id_)
+      : state_id(state_id_),
+        p_context(std::nullptr)
+    {
+    }
+
+    //*******************************************
+    inline etl::fsm& get_fsm_context() const
+    {
+      return *p_context;
+    }
+
+  private:
+
+    virtual fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) = 0;
+
+    virtual fsm_state_id_t on_enter_state() { return state_id; } // By default, do nothing.
+    virtual void on_exit_state() {}  // By default, do nothing.
+
+    //*******************************************
+    void set_fsm_context(etl::fsm& context)
+    {
+      p_context = &context;
+    }
+
+    // The state id.
+    const etl::fsm_state_id_t state_id;
+
+    // A pointer to the FSM context.
+    etl::fsm* p_context;
+
+    // Disabled.
+    ifsm_state(const ifsm_state&);
+    ifsm_state& operator =(const ifsm_state&);
+  };
+
+  //***************************************************************************
+  /// The FSM class.
+  //***************************************************************************
+  class fsm : public etl::imessage_router
+  {
+  public:
+
+    //*******************************************
+    /// Constructor.
+    //*******************************************
+    fsm(etl::message_router_id_t id)
+      : imessage_router(id),
+        p_state(std::nullptr)
+    {
+    }
+
+    //*******************************************
+    /// Set the states for the FSM
+    //*******************************************
+    template <typename TSize>
+    void set_states(etl::ifsm_state** p_states, TSize size)
+    {
+      state_list       = p_states;
+      number_of_states = etl::fsm_state_id_t(size);
+
+      ETL_ASSERT((number_of_states > 0), ETL_ERROR(etl::fsm_state_list_exception));
+
+      for (etl::fsm_state_id_t i = 0; i < size; ++i)
+      {
+        ETL_ASSERT((state_list[i] != std::nullptr), ETL_ERROR(etl::fsm_null_state_exception));
+        state_list[i]->set_fsm_context(*this);
+      }
+    }
+
+    //*******************************************
+    /// Starts the FSM.
+    /// Can only be called once.
+    /// Subsequent calls will do nothing.
+    //*******************************************
+    void start()
+    {
+      // Can only be started once.
+      if (p_state == std::nullptr)
+      {
+        p_state = state_list[0];
+        ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception));
+
+        p_state->on_enter_state();
+      }
+    }
+
+    //*******************************************
+    /// Top level message handler for the FSM.
+    //*******************************************
+    void receive(const etl::imessage& message)
+    {
+      etl::null_message_router nmr;
+      receive(nmr, message);
+    }
+
+    //*******************************************
+    /// Top level message handler for the FSM.
+    //*******************************************
+    void receive(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t next_state_id = p_state->process_event(source, message);
+      ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception));
+
+      etl::ifsm_state* p_next_state = state_list[next_state_id];
+
+      // Have we changed state?
+      if (p_next_state != p_state)
+      {
+        do
+        {
+          p_state->on_exit_state();
+          p_state = p_next_state;
+
+          next_state_id = p_state->on_enter_state();
+          ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception));
+
+          p_next_state = state_list[next_state_id];
+
+        } while (p_next_state != p_state); // Have we changed state again?
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //*******************************************
+    /// Does this FSM accept the message id?
+    /// Yes, it accepts everything!
+    //*******************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      return true;
+    }
+
+    //*******************************************
+    /// Gets the current state id.
+    //*******************************************
+    etl::fsm_state_id_t get_state_id() const
+    {
+      ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception));
+      return p_state->get_state_id();
+    }
+
+    //*******************************************
+    /// Gets a reference to the current state interface.
+    //*******************************************
+    ifsm_state& get_state()
+    {
+      ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception));
+      return *p_state;
+    }
+
+    //*******************************************
+    /// Gets a const reference to the current state interface.
+    //*******************************************
+    const ifsm_state& get_state() const
+    {
+      ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception));
+      return *p_state;
+    }
+
+    //*******************************************
+    /// Checks if the FSM has been started.
+    //*******************************************
+    bool is_started() const
+    {
+      return p_state != std::nullptr;
+    }
+
+    //*******************************************
+    /// Reset the FSM to pre-started state.
+    //*******************************************
+    void reset()
+    {
+      p_state = std::nullptr;
+    }
+
+  private:
+
+    etl::ifsm_state*    p_state;          ///< A pointer to the current state.
+    etl::ifsm_state**   state_list;       ///< The list of added states.
+    etl::fsm_state_id_t number_of_states; ///< The number of states.
+  };
+
+  //***************************************************************************
+  // The definition for all 16 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void, 
+            typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, 
+            typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, 
+            typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
+  class fsm_state : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break;
+        case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break;
+        case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break;
+        case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break;
+        case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break;
+        case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break;
+        case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break;
+        case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break;
+        case T13::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T13&>(message)); break;
+        case T14::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T14&>(message)); break;
+        case T15::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T15&>(message)); break;
+        case T16::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T16&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 15 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11, typename T12, 
+            typename T13, typename T14, typename T15>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break;
+        case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break;
+        case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break;
+        case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break;
+        case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break;
+        case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break;
+        case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break;
+        case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break;
+        case T13::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T13&>(message)); break;
+        case T14::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T14&>(message)); break;
+        case T15::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T15&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 14 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11, typename T12, 
+            typename T13, typename T14>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break;
+        case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break;
+        case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break;
+        case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break;
+        case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break;
+        case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break;
+        case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break;
+        case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break;
+        case T13::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T13&>(message)); break;
+        case T14::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T14&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 13 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11, typename T12, 
+            typename T13>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break;
+        case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break;
+        case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break;
+        case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break;
+        case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break;
+        case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break;
+        case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break;
+        case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break;
+        case T13::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T13&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 12 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11, typename T12>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break;
+        case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break;
+        case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break;
+        case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break;
+        case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break;
+        case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break;
+        case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break;
+        case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 11 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, void, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break;
+        case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break;
+        case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break;
+        case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break;
+        case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break;
+        case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break;
+        case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 10 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, void, void, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break;
+        case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break;
+        case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break;
+        case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break;
+        case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break;
+        case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 9 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, void, void, void, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break;
+        case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break;
+        case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break;
+        case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break;
+        case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 8 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, void, void, void, void, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break;
+        case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break;
+        case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break;
+        case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 7 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, void, void, void, void, void, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break;
+        case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break;
+        case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 6 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break;
+        case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 5 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 4 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3, typename T4>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 3 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2, typename T3>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 2 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1, typename T2>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 1 message type.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, 
+            typename T1>
+  class fsm_state<TContext, TDerived, STATE_ID_, T1, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+  protected:
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t new_state_id;
+      etl::message_id_t event_id = message.message_id;
+
+      switch (event_id)
+      {
+        case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break;
+        default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break;
+      }
+
+      return new_state_id;
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 0 message types.
+  //***************************************************************************
+  template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_>
+  class fsm_state<TContext, TDerived, STATE_ID_, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
+  {
+  public:
+
+    enum
+    {
+      STATE_ID = STATE_ID_
+    };
+
+    fsm_state()
+      : ifsm_state(STATE_ID)
+    {
+    }
+
+    inline TContext& get_fsm_context() const
+    {
+      return static_cast<TContext&>(ifsm_state::get_fsm_context());
+    }
+  private:
+
+    etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)
+    {
+      return static_cast<TDerived*>(this)->on_event_unknown(source, message);
+    }
+  };
+}
+
+#undef ETL_FILE
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fsm_generator.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,539 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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.
+******************************************************************************/
+
+/*[[[cog
+import cog
+cog.outl("#if 0")
+]]]*/
+/*[[[end]]]*/
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+/*[[[cog
+import cog
+cog.outl("#endif")
+]]]*/
+/*[[[end]]]*/
+
+/*[[[cog
+import cog
+cog.outl("//***************************************************************************")
+cog.outl("// This file has been auto generated. Do not edit this file.")
+cog.outl("//***************************************************************************")
+]]]*/
+/*[[[end]]]*/
+
+//***************************************************************************
+// To generate to header file, run this at the command line.
+// Note: You will need Python and COG installed.
+//
+// python -m cogapp -d -e -ofsm.h -DHandlers=<n> fsm_generator.h
+// Where <n> is the number of messages to support.
+//
+// e.g.
+// To generate handlers for up to 16 events...
+// python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h
+//
+// See generate.bat
+//***************************************************************************
+
+#ifndef __ETL_FSM__
+#define __ETL_FSM__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "array.h"
+#include "nullptr.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "user_type.h"
+#include "message_router.h"
+#include "integral_limits.h"
+#include "largest.h"
+
+#undef ETL_FILE
+#define ETL_FILE "34"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef max
+#endif
+
+namespace etl
+{
+  class fsm;
+
+  /// Allow alternative type for state id.
+#if !defined(ETL_FSM_STATE_ID_TYPE)
+    typedef uint_least8_t fsm_state_id_t;
+#else
+    typedef ETL_FSM_STATE_ID_TYPE fsm_state_id_t;
+#endif
+
+  // For internal FSM use.
+  typedef typename etl::larger_type<etl::message_id_t>::type fsm_internal_id_t;
+
+  //***************************************************************************
+  /// Base exception class for FSM.
+  //***************************************************************************
+  class fsm_exception : public etl::exception
+  {
+  public:
+
+    fsm_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Exception for null state pointer.
+  //***************************************************************************
+  class fsm_null_state_exception : public etl::fsm_exception
+  {
+  public:
+
+    fsm_null_state_exception(string_type file_name_, numeric_type line_number_)
+      : etl::fsm_exception(ETL_ERROR_TEXT("fsm:null state", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Exception for invalid state id.
+  //***************************************************************************
+  class fsm_state_id_exception : public etl::fsm_exception
+  {
+  public:
+
+    fsm_state_id_exception(string_type file_name_, numeric_type line_number_)
+      : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state id", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Exception for incompatible state list.
+  //***************************************************************************
+  class fsm_state_list_exception : public etl::fsm_exception
+  {
+  public:
+
+    fsm_state_list_exception(string_type file_name_, numeric_type line_number_)
+      : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state list", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Interface class for FSM states.
+  //***************************************************************************
+  class ifsm_state
+  {
+  public:
+
+    /// Allows ifsm_state functions to be private.
+    friend class etl::fsm;
+
+    //*******************************************
+    /// Gets the id for this state.
+    //*******************************************
+    etl::fsm_state_id_t get_state_id() const
+    {
+      return state_id;
+    }
+
+  protected:
+
+    //*******************************************
+    /// Constructor.
+    //*******************************************
+    ifsm_state(etl::fsm_state_id_t state_id_)
+      : state_id(state_id_),
+        p_context(std::nullptr)
+    {
+    }
+
+    //*******************************************
+    inline etl::fsm& get_fsm_context() const
+    {
+      return *p_context;
+    }
+
+  private:
+
+    virtual fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) = 0;
+
+    virtual fsm_state_id_t on_enter_state() { return state_id; } // By default, do nothing.
+    virtual void on_exit_state() {}  // By default, do nothing.
+
+    //*******************************************
+    void set_fsm_context(etl::fsm& context)
+    {
+      p_context = &context;
+    }
+
+    // The state id.
+    const etl::fsm_state_id_t state_id;
+
+    // A pointer to the FSM context.
+    etl::fsm* p_context;
+
+    // Disabled.
+    ifsm_state(const ifsm_state&);
+    ifsm_state& operator =(const ifsm_state&);
+  };
+
+  //***************************************************************************
+  /// The FSM class.
+  //***************************************************************************
+  class fsm : public etl::imessage_router
+  {
+  public:
+
+    //*******************************************
+    /// Constructor.
+    //*******************************************
+    fsm(etl::message_router_id_t id)
+      : imessage_router(id),
+        p_state(std::nullptr)
+    {
+    }
+
+    //*******************************************
+    /// Set the states for the FSM
+    //*******************************************
+    template <typename TSize>
+    void set_states(etl::ifsm_state** p_states, TSize size)
+    {
+      state_list       = p_states;
+      number_of_states = etl::fsm_state_id_t(size);
+
+      ETL_ASSERT((number_of_states > 0), ETL_ERROR(etl::fsm_state_list_exception));
+
+      for (etl::fsm_state_id_t i = 0; i < size; ++i)
+      {
+        ETL_ASSERT((state_list[i] != std::nullptr), ETL_ERROR(etl::fsm_null_state_exception));
+        state_list[i]->set_fsm_context(*this);
+      }
+    }
+
+    //*******************************************
+    /// Starts the FSM.
+    /// Can only be called once.
+    /// Subsequent calls will do nothing.
+    //*******************************************
+    void start()
+    {
+      // Can only be started once.
+      if (p_state == std::nullptr)
+      {
+        p_state = state_list[0];
+        ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception));
+
+        p_state->on_enter_state();
+      }
+    }
+
+    //*******************************************
+    /// Top level message handler for the FSM.
+    //*******************************************
+    void receive(const etl::imessage& message)
+    {
+      etl::null_message_router nmr;
+      receive(nmr, message);
+    }
+
+    //*******************************************
+    /// Top level message handler for the FSM.
+    //*******************************************
+    void receive(etl::imessage_router& source, const etl::imessage& message)
+    {
+      etl::fsm_state_id_t next_state_id = p_state->process_event(source, message);
+      ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception));
+
+      etl::ifsm_state* p_next_state = state_list[next_state_id];
+
+      // Have we changed state?
+      if (p_next_state != p_state)
+      {
+        do
+        {
+          p_state->on_exit_state();
+          p_state = p_next_state;
+
+          next_state_id = p_state->on_enter_state();
+          ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception));
+
+          p_next_state = state_list[next_state_id];
+
+        } while (p_next_state != p_state); // Have we changed state again?
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //*******************************************
+    /// Does this FSM accept the message id?
+    /// Yes, it accepts everything!
+    //*******************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      return true;
+    }
+
+    //*******************************************
+    /// Gets the current state id.
+    //*******************************************
+    etl::fsm_state_id_t get_state_id() const
+    {
+      ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception));
+      return p_state->get_state_id();
+    }
+
+    //*******************************************
+    /// Gets a reference to the current state interface.
+    //*******************************************
+    ifsm_state& get_state()
+    {
+      ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception));
+      return *p_state;
+    }
+
+    //*******************************************
+    /// Gets a const reference to the current state interface.
+    //*******************************************
+    const ifsm_state& get_state() const
+    {
+      ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception));
+      return *p_state;
+    }
+
+    //*******************************************
+    /// Checks if the FSM has been started.
+    //*******************************************
+    bool is_started() const
+    {
+      return p_state != std::nullptr;
+    }
+
+    //*******************************************
+    /// Reset the FSM to pre-started state.
+    //*******************************************
+    void reset()
+    {
+      p_state = std::nullptr;
+    }
+
+  private:
+
+    etl::ifsm_state*    p_state;          ///< A pointer to the current state.
+    etl::ifsm_state**   state_list;       ///< The list of added states.
+    etl::fsm_state_id_t number_of_states; ///< The number of states.
+  };
+
+  /*[[[cog
+  import cog
+  ################################################
+  # The first definition for all of the events.
+  ################################################
+  cog.outl("//***************************************************************************")
+  cog.outl("// The definition for all %s message types." % Handlers)
+  cog.outl("//***************************************************************************")
+  cog.outl("template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, ")
+  cog.out("          ")
+  for n in range(1, int(Handlers)):
+      cog.out("typename T%s = void, " % n)
+      if n % 4 == 0:
+          cog.outl("")
+          cog.out("          ")
+  cog.outl("typename T%s = void>" % Handlers)
+  cog.outl("class fsm_state : public ifsm_state")
+  cog.outl("{")
+  cog.outl("public:")
+  cog.outl("")
+  cog.outl("  enum")
+  cog.outl("  {")
+  cog.outl("    STATE_ID = STATE_ID_")
+  cog.outl("  };")
+  cog.outl("")
+  cog.outl("  fsm_state()")
+  cog.outl("    : ifsm_state(STATE_ID)")
+  cog.outl("  {")
+  cog.outl("  }")
+  cog.outl("")
+  cog.outl("protected:")
+  cog.outl("")
+  cog.outl("  inline TContext& get_fsm_context() const")
+  cog.outl("  {")
+  cog.outl("    return static_cast<TContext&>(ifsm_state::get_fsm_context());")
+  cog.outl("  }")
+  cog.outl("")
+  cog.outl("private:")
+  cog.outl("")
+  cog.outl("  etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)")
+  cog.outl("  {")
+  cog.outl("    etl::fsm_state_id_t new_state_id;")
+  cog.outl("    etl::message_id_t event_id = message.message_id;")
+  cog.outl("")
+  cog.outl("    switch (event_id)")
+  cog.outl("    {")
+  for n in range(1, int(Handlers) + 1):
+      cog.out("      case T%d::ID:" % n)
+      cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T%d&>(message));" % n)
+      cog.outl(" break;")
+  cog.out("      default:")
+  cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message);")
+  cog.outl(" break;")
+  cog.outl("    }")
+  cog.outl("")
+  cog.outl("    return new_state_id;")
+  cog.outl("  }")
+  cog.outl("};")
+
+  ####################################
+  # All of the other specialisations.
+  ####################################
+  for n in range(int(Handlers) - 1, 0, -1):
+      cog.outl("")
+      cog.outl("//***************************************************************************")
+      if n == 1:
+          cog.outl("// Specialisation for %d message type." % n)
+      else:
+          cog.outl("// Specialisation for %d message types." % n)
+      cog.outl("//***************************************************************************")
+      cog.outl("template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, ")
+      cog.out("          ")
+      for t in range(1, n):
+          cog.out("typename T%d, " % t)
+          if t % 4 == 0:
+              cog.outl("")
+              cog.out("          ")
+      cog.outl("typename T%d>" % n)
+      cog.out("class fsm_state<TContext, TDerived, STATE_ID_, ")
+      for t in range(1, n + 1):
+          cog.out("T%d, " % t)
+      if t % 16 == 0:
+          cog.outl("")
+          cog.out("               ")
+      for t in range(n + 1, int(Handlers)):
+          cog.out("void, ")
+      if t % 16 == 0:
+          cog.outl("")
+          cog.out("               ")
+      cog.outl("void> : public ifsm_state")
+      cog.outl("{")
+      cog.outl("public:")
+      cog.outl("")
+      cog.outl("  enum")
+      cog.outl("  {")
+      cog.outl("    STATE_ID = STATE_ID_")
+      cog.outl("  };")
+      cog.outl("")
+      cog.outl("  fsm_state()")
+      cog.outl("    : ifsm_state(STATE_ID)")
+      cog.outl("  {")
+      cog.outl("  }")
+      cog.outl("")
+      cog.outl("protected:")
+      cog.outl("")
+      cog.outl("  inline TContext& get_fsm_context() const")
+      cog.outl("  {")
+      cog.outl("    return static_cast<TContext&>(ifsm_state::get_fsm_context());")
+      cog.outl("  }")
+      cog.outl("")
+      cog.outl("private:")
+      cog.outl("")
+      cog.outl("  etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)")
+      cog.outl("  {")
+      cog.outl("    etl::fsm_state_id_t new_state_id;")
+      cog.outl("    etl::message_id_t event_id = message.message_id;")
+      cog.outl("")
+      cog.outl("    switch (event_id)")
+      cog.outl("    {")
+      for n in range(1, n + 1):
+          cog.out("      case T%d::ID:" % n)
+          cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T%d&>(message));" % n)
+          cog.outl(" break;")
+      cog.out("      default:")
+      cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message);")
+      cog.outl(" break;")
+      cog.outl("    }")
+      cog.outl("")
+      cog.outl("    return new_state_id;")
+      cog.outl("  }")
+      cog.outl("};")
+  ####################################
+  # Specialisation for zero messages.
+  ####################################
+  cog.outl("")
+  cog.outl("//***************************************************************************")
+  cog.outl("// Specialisation for 0 message types.")
+  cog.outl("//***************************************************************************")
+  cog.outl("template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_>")
+  cog.out("class fsm_state<TContext, TDerived, STATE_ID_, ")
+  for t in range(1, int(Handlers)):
+      cog.out("void, ")
+  if t % 16 == 0:
+      cog.outl("")
+      cog.out("               ")
+  cog.outl("void> : public ifsm_state")
+  cog.outl("{")
+  cog.outl("public:")
+  cog.outl("")
+  cog.outl("  enum")
+  cog.outl("  {")
+  cog.outl("    STATE_ID = STATE_ID_")
+  cog.outl("  };")
+  cog.outl("")
+  cog.outl("  fsm_state()")
+  cog.outl("    : ifsm_state(STATE_ID)")
+  cog.outl("  {")
+  cog.outl("  }")
+  cog.outl("")
+  cog.outl("  inline TContext& get_fsm_context() const")
+  cog.outl("  {")
+  cog.outl("    return static_cast<TContext&>(ifsm_state::get_fsm_context());")
+  cog.outl("  }")
+  cog.outl("private:")
+  cog.outl("")
+  cog.outl("  etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)")
+  cog.outl("  {")
+  cog.outl("    return static_cast<TDerived*>(this)->on_event_unknown(source, message);")
+  cog.outl("  }")
+  cog.outl("};")
+  ]]]*/
+  /*[[[end]]]*/
+}
+
+#undef ETL_FILE
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/function.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,417 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_FUNCTION__
+#define __ETL_FUNCTION__
+
+#include "platform.h"
+
+//*****************************************************************************
+///\defgroup function function
+/// A set of wrapper templates to allow a member or static function to be called
+/// without the caller having to know the specific details of the callee.
+/// This template class may be used to link interrupt vectors to specific member
+/// functions of a handler class.
+///\ingroup utilities
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  ///\ingroup function
+  /// The base interface template for function template specialisations.
+  ///\tparam TParameter The parameter type expected by the function.
+  //***************************************************************************
+  template <typename TParameter>
+  class ifunction
+  {
+  public:
+
+    typedef TParameter parameter_type; ///< The type of parameter sent to the function.
+
+    //*************************************************************************
+    /// The function operator that will be overridden.
+    //*************************************************************************
+    virtual void operator ()(TParameter) = 0;
+  };
+
+  //***************************************************************************
+  ///\ingroup function
+  /// The base interface template for functions taking <b>void</b> parameters.
+  //***************************************************************************
+  template <>
+  class ifunction<void>
+  {
+  public:
+
+    typedef void parameter_type; ///< The type of parameter sent to the function.
+
+    //*************************************************************************
+    /// The function operator that will be overridden.
+    //*************************************************************************
+    virtual void operator ()() = 0;
+  };
+
+  //***************************************************************************
+  ///\ingroup function
+  /// A derived function template that takes an object type and parameter type.
+  ///\tparam TObject    The object type that contains the member function.
+  ///\tparam TParameter The parameter type accepted by the member function.
+  //***************************************************************************
+  template <typename TObject, typename TParameter>
+  class function : public ifunction<TParameter>
+  {
+  public:
+
+    typedef TObject    object_type;    ///< The type of object.
+    typedef TParameter parameter_type; ///< The type of parameter sent to the function.
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param object    Reference to the object
+    ///\param p_function Pointer to the member function
+    //*************************************************************************
+    function(TObject& object_, void(TObject::* p_function_)(TParameter))
+      : p_object(&object_),
+        p_function(p_function_)
+    {
+    }
+
+    //*************************************************************************
+    /// The function operator that calls the destination function.
+    ///\param data The data to pass to the function.
+    //*************************************************************************
+    virtual void operator ()(TParameter data)
+    {
+      // Call the object's member function with the data.
+      (p_object->*p_function)(data);
+    }
+
+  private:
+
+    TObject* p_object;                        ///< Pointer to the object that contains the function.
+    void (TObject::* p_function)(TParameter); ///< Pointer to the member function.
+  };
+
+  //***************************************************************************
+  ///\ingroup function
+  /// A derived function template that takes a parameter type.
+  ///\tparam TObject The object type that contains the member function.
+  //***************************************************************************
+  template <typename TObject>
+  class function<TObject, void> : public ifunction<void>
+  {
+  public:
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param object   Reference to the object
+    ///\param p_function Pointer to the member function
+    //*************************************************************************
+    function(TObject& object_, void(TObject::* p_function_)(void))
+      : p_object(&object_),
+        p_function(p_function_)
+    {
+    }
+
+    //*************************************************************************
+    /// The function operator that calls the destination function.
+    //*************************************************************************
+    virtual void operator ()()
+    {
+      // Call the object's member function.
+      (p_object->*p_function)();
+    }
+
+  private:
+
+    TObject* p_object;              ///< Pointer to the object that contains the function.
+    void (TObject::* p_function)(); ///< Pointer to the member function.
+  };
+
+  //***************************************************************************
+  ///\ingroup function
+  /// Specialisation for static or global functions that takes a parameter.
+  //***************************************************************************
+  template <typename TParameter>
+  class function<void, TParameter> : public ifunction<TParameter>
+  {
+  public:
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param p_function Pointer to the function
+    //*************************************************************************
+    function(void(*p_function_)(TParameter))
+      : p_function(p_function_)
+    {
+    }
+
+    //*************************************************************************
+    /// The function operator that calls the destination function.
+    ///\param data The data to pass to the function.
+    //*************************************************************************
+    virtual void operator ()(TParameter data)
+    {
+      // Call the function with the data.
+      (*p_function)(data);
+    }
+
+  private:
+
+    void (*p_function)(TParameter); ///< Pointer to the function.
+  };
+
+  //***************************************************************************
+  ///\ingroup function
+  /// Specialisation static functions taking void parameter.
+  //***************************************************************************
+  template <>
+  class function<void, void> : public ifunction<void>
+  {
+  public:
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param p_function Pointer to the function.
+    //*************************************************************************
+    function(void(*p_function_)(void))
+      : p_function(p_function_)
+    {
+    }
+
+    //*************************************************************************
+    /// The function operator that calls the destination function.
+    //*************************************************************************
+    virtual void operator ()()
+    {
+      // Call the function.
+      (*p_function)();
+    }
+
+  private:
+
+    void (*p_function)(); ///< Pointer to the function.
+  };
+
+  //***************************************************************************
+  ///\ingroup function
+  /// A derived function template that takes an object type and parameter type.
+  ///\tparam TObject    The object type that contains the member function.
+  ///\tparam TParameter The parameter type accepted by the member function.
+  //***************************************************************************
+  template <typename TObject, typename TParameter, void (TObject::*Function)(TParameter)>
+  class function_mp : public ifunction<TParameter>
+  {
+  public:
+
+    typedef TObject    object_type;    ///< The type of object.
+    typedef TParameter parameter_type; ///< The type of parameter sent to the function.
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param object    Reference to the object
+    //*************************************************************************
+    function_mp(TObject& object_)
+      : p_object(&object_)
+    {
+    }
+
+    //*************************************************************************
+    /// The function operator that calls the destination function.
+    ///\param data The data to pass to the function.
+    //*************************************************************************
+    virtual void operator ()(TParameter data)
+    {
+      // Call the object's member function with the data.
+      (p_object->*Function)(data);
+    }
+
+  private:
+
+    TObject* p_object; ///< Pointer to the object that contains the function.
+  };
+
+  //***************************************************************************
+  ///\ingroup function
+  /// A derived function template that takes an object type and parameter type.
+  ///\tparam TObject    The object type that contains the member function.
+  ///\tparam TParameter The parameter type accepted by the member function.
+  //***************************************************************************
+  template <typename TObject, void (TObject::*Function)(void)>
+  class function_mv : public ifunction<void>
+  {
+  public:
+
+    typedef TObject object_type;    ///< The type of object.
+    typedef void    parameter_type; ///< The type of parameter sent to the function.
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param object    Reference to the object
+    //*************************************************************************
+    function_mv(TObject& object_)
+      : p_object(&object_)
+    {
+    }
+
+    //*************************************************************************
+    /// The function operator that calls the destination function.
+    ///\param data The data to pass to the function.
+    //*************************************************************************
+    virtual void operator ()()
+    {
+      // Call the object's member function.
+      (p_object->*Function)();
+    }
+
+  private:
+
+    TObject* p_object; ///< Pointer to the object that contains the function.
+  };
+
+  //***************************************************************************
+  ///\ingroup function
+  /// A derived function template that takes an object type and parameter type.
+  ///\tparam TObject    The object type that contains the member function.
+  ///\tparam TParameter The parameter type accepted by the member function.
+  //***************************************************************************
+  template <typename TObject, typename TParameter, TObject& Instance, void (TObject::*Function)(TParameter)>
+  class function_imp : public ifunction<TParameter>
+  {
+  public:
+
+    typedef TObject    object_type;    ///< The type of object.
+    typedef TParameter parameter_type; ///< The type of parameter sent to the function.
+
+    //*************************************************************************
+    /// The function operator that calls the destination function.
+    ///\param data The data to pass to the function.
+    //*************************************************************************
+    virtual void operator ()(TParameter data)
+    {
+      // Call the object's member function with the data.
+      (Instance.*Function)(data);
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup function
+  /// A derived function template that takes an object type and parameter type.
+  ///\tparam TObject    The object type that contains the member function.
+  ///\tparam TParameter The parameter type accepted by the member function.
+  //***************************************************************************
+  template <typename TObject, TObject& Instance, void (TObject::*Function)(void)>
+  class function_imv : public ifunction<void>
+  {
+  public:
+
+    typedef TObject object_type;    ///< The type of object.
+    typedef void    parameter_type; ///< The type of parameter sent to the function.
+
+    //*************************************************************************
+    /// The function operator that calls the destination function.
+    ///\param data The data to pass to the function.
+    //*************************************************************************
+    virtual void operator ()()
+    {
+      // Call the object's member function.
+      (Instance.*Function)();
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup function
+  /// A derived function template that takes a parameter type.
+  ///\tparam TParameter The parameter type accepted by the member function.
+  //***************************************************************************
+  template <typename TParameter, void (*Function)(TParameter)>
+  class function_fp : public ifunction<TParameter>
+  {
+  public:
+
+    typedef TParameter parameter_type; ///< The type of parameter sent to the function.
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param object    Reference to the object
+    ///\param p_function Pointer to the member function
+    //*************************************************************************
+    function_fp()
+    {
+    }
+
+    //*************************************************************************
+    /// The function operator that calls the destination function.
+    ///\param data The data to pass to the function.
+    //*************************************************************************
+    virtual void operator ()(TParameter data)
+    {
+      // Call the object's member function with the data.
+      (*Function)(data);
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup function
+  /// A derived function template that takes a parameter type.
+  ///\tparam TParameter The parameter type accepted by the member function.
+  //***************************************************************************
+  template <void(*Function)(void)>
+  class function_fv : public ifunction<void>
+  {
+  public:
+
+    typedef void parameter_type; ///< The type of parameter sent to the function.
+
+    //*************************************************************************
+    /// Constructor.
+    ///\param object    Reference to the object
+    ///\param p_function Pointer to the member function
+    //*************************************************************************
+    function_fv()
+    {
+    }
+
+    //*************************************************************************
+    /// The function operator that calls the destination function.
+    ///\param data The data to pass to the function.
+    //*************************************************************************
+    virtual void operator ()()
+    {
+      // Call the function.
+      (*Function)();
+    }
+  };
+
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/functional.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,112 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_FUNCTIONAL__
+#define __ETL_FUNCTIONAL__
+
+#include "platform.h"
+
+///\defgroup functional functional
+///\ingroup utilities
+
+///\defgroup reference_wrapper reference_wrapper
+///\ingroup functional
+
+namespace etl
+{
+  //***************************************************************************
+  /// A definition of reference_wrapper for those that don't have C++ 0x11 support.
+  ///\ingroup reference
+  //***************************************************************************
+  template <typename T>
+  class reference_wrapper
+  {
+  public:
+
+    typedef T type;
+
+    explicit reference_wrapper(T& t_)
+      : t(&t_)
+    {
+    }
+
+    operator T& () const
+    {
+      return *t;
+    }
+
+    reference_wrapper<T>& operator = (T value)
+    {
+      *t = value;
+      return *this;
+    }
+    
+    T& get() const
+    {
+      return *t;
+    }
+
+  private:
+
+    T* t;
+  };
+
+  //***************************************************************************
+  template <typename T>
+  reference_wrapper<T> ref(T& t)
+  {
+    return reference_wrapper<T>(t);
+  }
+
+  //***************************************************************************
+  template <typename T>
+  reference_wrapper<T> ref(reference_wrapper<T> t)
+  {
+    return reference_wrapper<T>(t.get());
+  }
+
+  //***************************************************************************
+  template <typename T>
+  reference_wrapper<const T> cref(const T& t)
+  {
+    return reference_wrapper<const T>(t);
+  }
+
+  //***************************************************************************
+  template <typename T>
+  reference_wrapper<const T> cref(reference_wrapper<T> t)
+  {
+    return reference_wrapper<const T>(t.get());
+  }
+}
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hash.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,438 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_HASH__
+#define __ETL_HASH__
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "platform.h"
+
+// The default hash calculation.
+#include "fnv_1.h"
+#include "type_traits.h"
+#include "static_assert.h"
+
+///\defgroup hash Standard hash calculations
+///\ingroup maths
+
+namespace etl
+{
+  namespace __private_hash__
+  {
+    //*************************************************************************
+    /// Hash to use when size_t is 16 bits.
+    /// T is always expected to be size_t.
+    //*************************************************************************
+    template <typename T>
+    typename enable_if<sizeof(T) == sizeof(uint16_t), size_t>::type
+    generic_hash(const uint8_t* begin, const uint8_t* end)
+    {
+      uint32_t h = fnv_1a_32(begin, end);
+
+      return static_cast<size_t>(h ^ (h >> 16));
+    }
+
+    //*************************************************************************
+    /// Hash to use when size_t is 32 bits.
+    /// T is always expected to be size_t.
+    //*************************************************************************
+    template <typename T>
+    typename enable_if<sizeof(T) == sizeof(uint32_t), size_t>::type
+    generic_hash(const uint8_t* begin, const uint8_t* end)
+    {
+      return fnv_1a_32(begin, end);
+    }
+
+    //*************************************************************************
+    /// Hash to use when size_t is 64 bits.
+    /// T is always expected to be size_t.
+    //*************************************************************************
+    template <typename T>
+    typename enable_if<sizeof(T) == sizeof(uint64_t), size_t>::type
+    generic_hash(const uint8_t* begin, const uint8_t* end)
+    {
+      return fnv_1a_64(begin, end);
+    }
+  }
+
+  //***************************************************************************
+  /// Generic declaration for etl::hash
+  ///\ingroup hash
+  //***************************************************************************
+  template <typename T> struct hash;
+
+  //***************************************************************************
+  /// Specialisation for bool.
+  ///\ingroup hash
+  //***************************************************************************
+  template <>
+  struct hash <bool>
+  {
+    STATIC_ASSERT(sizeof(size_t) >= sizeof(bool), "size_t smaller than type");
+
+    size_t operator ()(bool v) const
+    {
+      return static_cast<size_t>(v);
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for char.
+  ///\ingroup hash
+  //***************************************************************************
+  template <>
+  struct hash<char>
+  {
+    STATIC_ASSERT(sizeof(size_t) >= sizeof(char), "size_t smaller than type");
+
+    size_t operator ()(char v) const
+    {
+      return static_cast<size_t>(v);
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for signed char.
+  ///\ingroup hash
+  //***************************************************************************
+  template<> struct
+  hash<signed char>
+  {
+    STATIC_ASSERT(sizeof(size_t) >= sizeof(signed char), "size_t smaller than type");
+
+    size_t operator ()(signed char v) const
+    {
+      return static_cast<size_t>(v);
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for unsigned char.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<unsigned char>
+  {
+    STATIC_ASSERT(sizeof(size_t) >= sizeof(unsigned char), "size_t smaller than type");
+
+    size_t operator ()(unsigned char v) const
+    {
+      return static_cast<size_t>(v);
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for wchar_t.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<wchar_t>
+  {
+    STATIC_ASSERT(sizeof(size_t) >= sizeof(wchar_t), "size_t smaller than type");
+
+    size_t operator ()(wchar_t v) const
+    {
+      return static_cast<size_t>(v);
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for short.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<short>
+  {
+    STATIC_ASSERT(sizeof(size_t) >= sizeof(short), "size_t smaller than type");
+
+    size_t operator ()(short v) const
+    {
+      return static_cast<size_t>(v);
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for unsigned short.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<unsigned short>
+  {
+    STATIC_ASSERT(sizeof(size_t) >= sizeof(unsigned short), "size_t smaller than type");
+
+    size_t operator ()(unsigned short v) const
+    {
+      return static_cast<size_t>(v);
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for int.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<int>
+  {
+    STATIC_ASSERT(sizeof(size_t) >= sizeof(int), "size_t smaller than type");
+
+    size_t operator ()(int v) const
+    {
+      return static_cast<size_t>(v);
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for unsigned int.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<unsigned int>
+  {
+    STATIC_ASSERT(sizeof(size_t) >= sizeof(unsigned int), "size_t smaller than type");
+
+    size_t operator ()(unsigned int v) const
+    {
+      return static_cast<size_t>(v);
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for long.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<long>
+  {
+    size_t operator ()(long v) const
+    {
+      // If it's the same size as a size_t.
+      if (sizeof(size_t) >= sizeof(v))
+      {
+        return static_cast<size_t>(v);
+      }
+      else
+      {
+        uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+        return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+      }
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for long long.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<long long>
+  {
+    size_t operator ()(long long v) const
+    {
+      // If it's the same size as a size_t.
+      if (sizeof(size_t) >= sizeof(v))
+      {
+        return static_cast<size_t>(v);
+      }
+      else
+      {
+        uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+        return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+      }
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for unsigned long.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<unsigned long>
+  {
+    size_t  operator ()(unsigned long v) const
+    {
+      // If it's the same size as a size_t.
+      if (sizeof(size_t) >= sizeof(v))
+      {
+        return static_cast<size_t>(v);
+      }
+      else
+      {
+        uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+        return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+      }
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for unsigned long long.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<unsigned long long>
+  {
+    size_t  operator ()(unsigned long long v) const
+    {
+      // If it's the same size as a size_t.
+      if (sizeof(size_t) >= sizeof(v))
+      {
+        return static_cast<size_t>(v);
+      }
+      else
+      {
+        uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+        return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+      }
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for float.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<float>
+  {
+    size_t operator ()(float v) const
+    {
+      // If it's the same size as a size_t.
+      if (sizeof(size_t) == sizeof(v))
+      {
+        union
+        {
+          size_t s;
+          float  v;
+        } u;
+
+        u.v = v;
+
+        return u.s;
+      }
+      else
+      {
+        uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+        return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+      }
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for double.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<double>
+  {
+    size_t  operator ()(double v) const
+    {
+      // If it's the same size as a size_t.
+      if (sizeof(size_t) == sizeof(v))
+      {
+        union
+        {
+          size_t s;
+          double v;
+        } u;
+
+        u.v = v;
+        
+        return u.s;
+      }
+      else
+      {
+        uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+        return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+      }
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for long double.
+  ///\ingroup hash
+  //***************************************************************************
+  template<>
+  struct hash<long double>
+  {
+    size_t operator ()(long double v) const
+    {
+      // If it's the same size as a size_t.
+      if (sizeof(size_t) == sizeof(v))
+      {
+        union
+        {
+          size_t s;
+          long double v;
+        } u;
+
+        u.v = v;
+
+        return u.s;
+      }
+      else
+      {
+        uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+        return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+      }
+    }
+  };
+
+  //***************************************************************************
+  /// Specialisation for pointers.
+  ///\ingroup hash
+  //***************************************************************************
+  template <typename T>
+  struct hash<T*>
+  {
+    size_t operator ()(const T* v) const
+    {
+      // If it's the same size as a size_t.
+      if (sizeof(size_t) == sizeof(T*))
+      {
+        union
+        {
+          size_t s;
+          const T* v;
+        } u;
+
+        u.v = v;
+
+        return u.s;
+      }
+      else
+      {
+        uint8_t* p = reinterpret_cast<uint8_t*>(&v);
+        return __private_hash__::generic_hash<size_t>(p, p + sizeof(v));
+      }
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/icache.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,117 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove, rlindeman
+
+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.
+******************************************************************************/
+
+//*****************************************************************************
+#error  This header is in development. Do not use.
+//*****************************************************************************
+
+#ifndef __ETL_ICACHE__
+#define __ETL_ICACHE__
+
+#include "platform.h"
+#include "function.h"
+#include "nullptr.h"
+
+#include <utility>
+
+namespace etl
+{
+  ///**************************************************************************
+  /// The base class for all caches.
+  ///**************************************************************************
+  template <typename TKey, typename TValue>
+  class icache
+  {
+  public:
+
+    ///************************************************************************
+    /// Constructor.
+    /// By default, 'write_through' is set to true.
+    ///************************************************************************
+    icache()
+      : write_through(true),
+        p_read_store(std::nullptr),
+        p_write_store(std::nullptr)
+    {
+    }
+
+    ///************************************************************************
+    /// Destructor.
+    /// Flushes the cache if necessary.
+    ///************************************************************************
+    virtual ~icache()
+    {
+      if (!write_through)
+      {
+        flush();
+      }
+    }
+
+    ///************************************************************************
+    /// Sets the function that reads from the store.
+    ///************************************************************************
+    void set_read_function(etl::ifunction<key_value_t&>* p_read)
+    {
+      p_read_store = p_read;
+    }
+
+    ///************************************************************************
+    /// Sets the function that writes to the store.
+    ///************************************************************************
+    void set_write_function(etl::ifunction<const key_value_t&>* p_write)
+    {
+      p_write_store = p_write;
+    }
+
+    ///************************************************************************
+    /// Sets the 'write through'' flag.
+    ///************************************************************************
+    void set_write_through(bool write_through_)
+    {
+      write_through = write_through_;
+    }
+
+    virtual const T& read(const TKey& key) const = 0;             ///< Reads from the cache. May read from the store using p_read_store.
+    virtual void write(const TKey& key, const TValue& value) = 0; ///< Writes to the cache. May write to the store using p_write_store.
+    virtual void flush() = 0;                                     ///< The overridden function should write all changed values to the store.
+
+  protected:
+
+    typedef std::pair<TKey, TValue> key_value_t;
+
+    bool write_through; ///< If true, the cache should write changed items back to the store immediately. If false then a flush() or destruct will be required.
+
+    etl::ifunction<key_value_t&>*       p_read_store;  ///< A pointer to the function that will read a value from the store into the cache.
+    etl::ifunction<const key_value_t&>* p_write_store; ///< A pointer to the function that will write a value from the cache into the store.
+  }
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ihash.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,82 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+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 __ETL_IHASH__
+#define __ETL_IHASH__
+
+#include <stdint.h>
+#include <utility>
+
+#include "platform.h"
+#include "exception.h"
+#include "error_handler.h"
+
+///\defgroup ihash Common data for all hash type classes.
+///\ingroup hash
+
+#undef ETL_FILE
+#define ETL_FILE "19"
+
+namespace etl
+{
+  //***************************************************************************
+  ///\ingroup hash
+  /// Exception base for hashes.
+  //***************************************************************************
+  class hash_exception : public exception
+  {
+  public:
+
+    hash_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  ///\ingroup vector
+  /// Hash finalised exception.
+  //***************************************************************************
+  class hash_finalised : public hash_exception
+  {
+  public:
+
+    hash_finalised(string_type file_name_, numeric_type line_number_)
+      : hash_exception(ETL_ERROR_TEXT("ihash:finalised", ETL_FILE"A"), file_name_, line_number_)
+    {}
+  };
+
+  /// For the Americans
+  typedef hash_finalised hash_finalized;
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/instance_count.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,86 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_INSTANCE_COUNT__
+#define __ETL_INSTANCE_COUNT__
+
+#include "platform.h"
+
+///\defgroup instance_count instance count
+///\ingroup utilities
+
+namespace etl
+{
+  //***************************************************************************
+  /// Inherit from this to count instances of a type.
+  ///\ingroup reference
+  //***************************************************************************
+  template <typename T>
+  class instance_count
+  {
+  public:
+
+    //*************************************************************************
+    /// Construct and add 1.
+    //*************************************************************************
+    instance_count()
+    {
+      ++how_many;
+    }
+
+    //*************************************************************************
+    /// Destruct and subtract 1.
+    //*************************************************************************
+    virtual ~instance_count()
+    {
+      --how_many;
+    }
+
+    //*************************************************************************
+    /// Get how many instances we have.
+    //*************************************************************************
+    inline static size_t get_instance_count()
+    {
+      return how_many;
+    }
+
+  private:
+
+    /// The count for this type.
+    static size_t how_many;
+  };
+
+  /// Initialisation.
+  template <typename T> size_t instance_count<T>::how_many = 0;
+}
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/integral_limits.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,222 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_INTEGRAL_LIMITS__
+#define __ETL_INTEGRAL_LIMITS__
+
+#include <limits.h>
+#include <stddef.h>
+
+#include "platform.h"
+#include "type_traits.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#undef max
+#endif
+
+//*****************************************************************************
+///\defgroup integral_limits integral_limits
+/// A set of templated compile time constants that mirror some of std::numeric_limits funtionality.
+///\ingroup utilities
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <typename T>
+  struct integral_limits;
+
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <>
+  struct integral_limits<void>
+  {
+    static const int min        = 0;
+    static const int max        = 0;
+    static const int bits       = 0;
+    static const bool is_signed = false;
+  };
+
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <>
+  struct integral_limits<signed char>
+  {
+    static const signed char min = SCHAR_MIN;
+    static const signed char max = SCHAR_MAX;
+    static const int bits        = CHAR_BIT;
+    static const bool is_signed  = etl::is_signed<signed char>::value;
+  };
+
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <>
+  struct integral_limits<unsigned char>
+  {
+    static const unsigned char min = 0;
+    static const unsigned char max = UCHAR_MAX;
+    static const int bits          = CHAR_BIT;
+    static const bool is_signed    = etl::is_signed<unsigned char>::value;
+  };
+
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <>
+  struct integral_limits<char>
+  {
+    static const char min       = (etl::is_signed<char>::value) ? SCHAR_MIN : 0;
+    static const char max       = (etl::is_signed<char>::value) ? SCHAR_MAX : char(UCHAR_MAX);
+    static const int bits       = CHAR_BIT;
+    static const bool is_signed = etl::is_signed<char>::value;
+  };
+
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <>
+  struct integral_limits<short>
+  {
+    static const short min      = SHRT_MIN;
+    static const short max      = SHRT_MAX;
+    static const int bits       = CHAR_BIT * (sizeof(short) / sizeof(char));
+    static const bool is_signed = etl::is_signed<short>::value;
+  };
+
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <>
+  struct integral_limits<unsigned short>
+  {
+    static const unsigned short min = 0;
+    static const unsigned short max = USHRT_MAX;
+    static const int bits           = CHAR_BIT * (sizeof(unsigned short) / sizeof(char));
+    static const bool is_signed     = etl::is_signed<unsigned short>::value;
+  };
+
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <>
+  struct integral_limits<int>
+  {
+    static const int min        = INT_MIN;
+    static const int max        = INT_MAX;
+    static const int bits       = CHAR_BIT * (sizeof(int) / sizeof(char));
+    static const bool is_signed = etl::is_signed<int>::value;
+  };
+
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <>
+  struct integral_limits<unsigned int>
+  {
+    static const unsigned int min = 0;
+    static const unsigned int max = UINT_MAX;
+    static const int bits         = CHAR_BIT * (sizeof(unsigned int) / sizeof(char));
+    static const bool is_signed   = etl::is_signed<unsigned int>::value;
+  };
+
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <>
+  struct integral_limits<long>
+  {
+    static const long min       = LONG_MIN;
+    static const long max       = LONG_MAX;
+    static const int bits       = CHAR_BIT * (sizeof(long) / sizeof(char));
+    static const bool is_signed = etl::is_signed<long>::value;
+  };
+
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <>
+  struct integral_limits<unsigned long>
+  {
+    static const unsigned long min = 0;
+    static const unsigned long max = ULONG_MAX;
+    static const int bits          = CHAR_BIT * (sizeof(unsigned long) / sizeof(char));
+    static const bool is_signed    = etl::is_signed<unsigned long>::value;
+  };
+
+#ifndef LLONG_MAX
+#define LLONG_MAX	9223372036854775807LL
+#endif
+
+#ifndef LLONG_MIN
+#define LLONG_MIN	(-LLONG_MAX - 1LL)
+#endif
+
+#ifndef ULLONG_MAX
+#define ULLONG_MAX 18446744073709551615ULL
+#endif
+
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <>
+  struct integral_limits<long long>
+  {
+    static const long long min  = LLONG_MIN;
+    static const long long max  = LLONG_MAX;
+    static const int bits       = CHAR_BIT * (sizeof(long long) / sizeof(char));
+    static const bool is_signed = etl::is_signed<long long>::value;
+  };
+
+  //***************************************************************************
+  ///\ingroup integral_limits
+  //***************************************************************************
+  template <>
+  struct integral_limits<unsigned long long>
+  {
+    static const unsigned long long min = 0;
+    static const unsigned long long max = ULLONG_MAX;
+    static const int bits               = CHAR_BIT * (sizeof(unsigned long long) / sizeof(char));
+    static const bool is_signed         = etl::is_signed<unsigned long long>::value;
+  };
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/intrusive_forward_list.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1049 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_INTRUSIVE_FORWARD_LIST__
+#define __ETL_INTRUSIVE_FORWARD_LIST__
+
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "platform.h"
+#include "nullptr.h"
+#include "type_traits.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "intrusive_links.h"
+#include "algorithm.h"
+
+#undef ETL_FILE
+#define ETL_FILE "20"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the intrusive_forward_list.
+  ///\ingroup intrusive_forward_list
+  //***************************************************************************
+  class intrusive_forward_list_exception : public exception
+  {
+  public:
+
+    intrusive_forward_list_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Empty exception for the intrusive_forward_list.
+  ///\ingroup intrusive_forward_list
+  //***************************************************************************
+  class intrusive_forward_list_empty : public intrusive_forward_list_exception
+  {
+  public:
+
+    intrusive_forward_list_empty(string_type file_name_, numeric_type line_number_)
+      : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:empty", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the intrusive_forward_list.
+  ///\ingroup intrusive_forward_list
+  //***************************************************************************
+  class intrusive_forward_list_iterator_exception : public intrusive_forward_list_exception
+  {
+  public:
+
+    intrusive_forward_list_iterator_exception(string_type file_name_, numeric_type line_number_)
+      : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:iterator", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Index exception for the intrusive_forward_list.
+  ///\ingroup intrusive_forward_list
+  //***************************************************************************
+  class intrusive_forward_list_index_exception : public intrusive_forward_list_exception
+  {
+  public:
+
+    intrusive_forward_list_index_exception(string_type file_name_, numeric_type line_number_)
+      : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:bounds", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Unsorted exception for the intrusive_forward_list.
+  ///\ingroup intrusive_list
+  //***************************************************************************
+  class intrusive_forward_list_unsorted : public intrusive_forward_list_exception
+  {
+  public:
+
+    intrusive_forward_list_unsorted(string_type file_name_, numeric_type line_number_)
+      : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:unsorted", ETL_FILE"D"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Base for intrusive forward list.
+  ///\ingroup intrusive_forward_list
+  //***************************************************************************
+  template <typename TLink>
+  class intrusive_forward_list_base
+  {
+  public:
+
+    // Node typedef.
+    typedef TLink link_type;
+
+    //*************************************************************************
+    /// Clears the intrusive_forward_list.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*************************************************************************
+    /// Assigns a range of values to the intrusive_forward_list.
+    /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined throws forward_list_iterator if the iterators are reversed.
+    //*************************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      intmax_t d = std::distance(first, last);
+      ETL_ASSERT(d >= 0, ETL_ERROR(intrusive_forward_list_iterator_exception));
+#endif
+
+      initialise();
+
+      link_type* p_last_link = &start_link;
+
+      // Add all of the elements.
+      while (first != last)
+      {
+        link_type& link = *first++;
+        etl::link_splice<link_type>(p_last_link, link);
+        p_last_link = &link;
+        ++current_size;
+      }
+    }
+
+    //*************************************************************************
+    /// Pushes a value to the front of the intrusive_forward_list.
+    //*************************************************************************
+    void push_front(link_type& value)
+    {
+      insert_link_after(start_link, value);
+    }
+
+    //*************************************************************************
+    /// Removes a value from the front of the intrusive_forward_list.
+    //*************************************************************************
+    void pop_front()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(intrusive_forward_list_empty));
+#endif
+      remove_link_after(start_link);
+    }
+
+    //*************************************************************************
+    /// Reverses the intrusive_forward_list.
+    //*************************************************************************
+    void reverse()
+    {
+      if (is_trivial_list())
+      {
+        return;
+      }
+
+      link_type* first = std::nullptr;             // To keep first link
+      link_type* second = start_link.etl_next; // To keep second link
+      link_type* track = start_link.etl_next; // Track the list
+
+      while (track != NULL)
+      {
+        track = track->etl_next;  // Track point to next link;
+        second->etl_next = first; // Second link point to first
+        first = second;          // Move first link to next
+        second = track;           // Move second link to next
+      }
+
+      etl::link<link_type>(start_link, first);
+    }
+
+    //*************************************************************************
+    /// Returns true if the list has no elements.
+    //*************************************************************************
+    bool empty() const
+    {
+      return start_link.etl_next == std::nullptr;
+    }
+
+    //*************************************************************************
+    /// Returns the number of elements.
+    //*************************************************************************
+    size_t size() const
+    {
+      return current_size;
+    }
+
+  protected:
+
+    link_type start_link; ///< The link that acts as the intrusive_forward_list start.
+
+    size_t current_size; ///< Counts the number of elements in the list.
+
+    //*************************************************************************
+    /// Is the intrusive_forward_list a trivial length?
+    //*************************************************************************
+    bool is_trivial_list() const
+    {
+      return (start_link.link_type::etl_next == std::nullptr) || (start_link.link_type::etl_next->etl_next == std::nullptr);;
+    }
+
+    //*************************************************************************
+    /// Insert a link.
+    //*************************************************************************
+    void insert_link_after(link_type& position, link_type& link)
+    {
+      // Connect to the intrusive_forward_list.
+      etl::link_splice<link_type>(position, link);
+      ++current_size;
+    }
+
+    //*************************************************************************
+    /// Remove a link.
+    //*************************************************************************
+    void remove_link_after(link_type& link)
+    {
+      link_type* p_next = link.etl_next;
+
+      if (p_next != std::nullptr)
+      {
+        etl::unlink_after<link_type>(link);
+        --current_size;
+      }
+    }
+
+    //*************************************************************************
+    /// Get the head link.
+    //*************************************************************************
+    link_type& get_head()
+    {
+      return *start_link.etl_next;
+    }
+
+    //*************************************************************************
+    /// Get the head link.
+    //*************************************************************************
+    const link_type& get_head() const
+    {
+      return *start_link.etl_next;
+    }
+
+    //*************************************************************************
+    /// Initialise the intrusive_forward_list.
+    //*************************************************************************
+    void initialise()
+    {
+      start_link.etl_next = std::nullptr;
+      current_size = 0;
+    }
+  };
+
+  //***************************************************************************
+  /// An intrusive forward list.
+  ///\ingroup intrusive_forward_list
+  ///\note TLink must be a base of TValue.
+  //***************************************************************************
+  template <typename TValue, typename TLink = etl::forward_link<0> >
+  class intrusive_forward_list : public etl::intrusive_forward_list_base<TLink>
+  {
+  public:
+
+    // Node typedef.
+    typedef typename etl::intrusive_forward_list_base<TLink>::link_type link_type;
+
+    // STL style typedefs.
+    typedef TValue            value_type;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef size_t            size_type;
+
+    typedef intrusive_forward_list<TValue, TLink> list_type;
+
+    //*************************************************************************
+    /// iterator.
+    //*************************************************************************
+    class iterator : public std::iterator<std::forward_iterator_tag, value_type>
+    {
+    public:
+
+      friend class intrusive_forward_list;
+
+      iterator()
+        : p_value(std::nullptr)
+      {
+      }
+
+      iterator(value_type& value)
+        : p_value(&value)
+      {
+      }
+
+      iterator(const iterator& other)
+        : p_value(other.p_value)
+      {
+      }
+
+      iterator& operator ++()
+      {
+        // Read the appropriate 'etl_next'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        // Read the appropriate 'etl_next'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+        return temp;
+      }
+
+      iterator operator =(const iterator& other)
+      {
+        p_value = other.p_value;
+        return *this;
+      }
+
+      reference operator *()
+      {
+        return *p_value;
+      }
+
+      const_reference operator *() const
+      {
+        return *p_value;
+      }
+
+      pointer operator &()
+      {
+        return p_value;
+      }
+
+      const_pointer operator &() const
+      {
+        return p_value;
+      }
+
+      pointer operator ->()
+      {
+        return p_value;
+      }
+
+      const_pointer operator ->() const
+      {
+        return p_value;
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.p_value == rhs.p_value;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      value_type* p_value;
+    };
+
+    //*************************************************************************
+    /// const_iterator
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::forward_iterator_tag, const value_type>
+    {
+    public:
+
+      friend class intrusive_forward_list;
+
+      const_iterator()
+        : p_value(std::nullptr)
+      {
+      }
+
+      const_iterator(const value_type& value)
+        : p_value(&value)
+      {
+      }
+
+      const_iterator(const typename intrusive_forward_list::iterator& other)
+        : p_value(other.p_value)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : p_value(other.p_value)
+      {
+      }
+
+      const_iterator& operator ++()
+      {
+        // Read the appropriate 'etl_next'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        // Read the appropriate 'etl_next'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+        return temp;
+      }
+
+      const_iterator operator =(const const_iterator& other)
+      {
+        p_value = other.p_value;
+        return *this;
+      }
+
+      const_reference operator *() const
+      {
+        return *p_value;
+      }
+
+      const_pointer operator &() const
+      {
+        return p_value;
+      }
+
+      const_pointer operator ->() const
+      {
+        return p_value;
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.p_value == rhs.p_value;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      const value_type* p_value;
+    };
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    intrusive_forward_list()
+    {
+      this->initialise();
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~intrusive_forward_list()
+    {
+      this->clear();
+    }
+
+    //*************************************************************************
+    /// Constructor from range
+    //*************************************************************************
+    template <typename TIterator>
+    intrusive_forward_list(TIterator first, TIterator last)
+    {
+      this->assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the intrusive_forward_list.
+    //*************************************************************************
+    iterator begin()
+    {
+      return iterator(static_cast<value_type&>(this->get_head()));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the intrusive_forward_list.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(static_cast<const value_type&>(this->get_head()));
+    }
+
+    //*************************************************************************
+    /// Gets before the beginning of the intrusive_forward_list.
+    //*************************************************************************
+    iterator before_begin()
+    {
+      return iterator(static_cast<value_type&>(this->start_link));
+    }
+
+    //*************************************************************************
+    /// Gets before the beginning of the intrusive_forward_list.
+    //*************************************************************************
+    const_iterator before_begin() const
+    {
+      return const_iterator(static_cast<const value_type&>(this->start_link));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the intrusive_forward_list.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(static_cast<const value_type&>(this->get_head()));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the intrusive_forward_list.
+    //*************************************************************************
+    iterator end()
+    {
+      return iterator();
+    }
+
+    //*************************************************************************
+    /// Gets the end of the intrusive_forward_list.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return const_iterator();
+    }
+
+    //*************************************************************************
+    /// Gets the end of the intrusive_forward_list.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator();
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the first element.
+    //*************************************************************************
+    reference front()
+    {
+      return static_cast<value_type&>(this->get_head());
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the first element.
+    //*************************************************************************
+    const_reference front() const
+    {
+      return static_cast<const value_type&>(this->get_head());;
+    }
+
+    //*************************************************************************
+    /// Inserts a value to the intrusive_forward_list after the specified position.
+    //*************************************************************************
+    iterator insert_after(iterator position, value_type& value)
+    {
+      this->insert_link_after(*position.p_value, value);
+      return iterator(value);
+    }
+
+    //*************************************************************************
+    /// Inserts a range of values to the intrusive_forward_list after the specified position.
+    //*************************************************************************
+    template <typename TIterator>
+    void insert_after(iterator position, TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        // Set up the next free link.
+        this->insert_link_after(*position.p_value, *first++);
+        ++position;
+      }
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    iterator erase_after(iterator position)
+    {
+      iterator next(position);
+      if (next != end())
+      {
+        ++next;
+        if (next != end())
+        {
+          ++next;
+          this->remove_link_after(*position.p_value);
+        }
+      }
+
+      return next;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    //*************************************************************************
+    iterator erase_after(iterator first, iterator last)
+    {
+      if (first != end() && (first != last))
+      {
+        this->current_size -= std::distance(first, last) - 1;
+
+        link_type* p_first = first.p_value;
+        link_type* p_last = last.p_value;
+        link_type* p_next = p_first->etl_next;
+
+        // Join the ends.
+        etl::link<link_type>(p_first, p_last);
+
+        if (p_next == std::nullptr)
+        {
+          return end();
+        }
+        else
+        {
+          return last;
+        }
+      }
+      else
+      {
+        return last;
+      }
+    }
+
+    //*************************************************************************
+    /// Removes all but the one element from every consecutive group of equal
+    /// elements in the container.
+    //*************************************************************************
+    template <typename TIsEqual>
+    void unique(TIsEqual isEqual)
+    {
+      if (this->empty())
+      {
+        return;
+      }
+
+      link_type* last    = &this->get_head();
+      link_type* current = last->etl_next;
+
+      while (current != std::nullptr)
+      {
+        // Is this value the same as the last?
+        if (isEqual(*static_cast<value_type*>(current), *static_cast<value_type*>(last)))
+        {
+          this->remove_link_after(*last);
+        }
+        else
+        {
+          // Move on one.
+          last = current;
+        }
+
+        current = last->etl_next;
+      }
+    }
+
+    //*************************************************************************
+    /// Sort using in-place merge sort algorithm.
+    //*************************************************************************
+    void sort()
+    {
+      sort(std::less<value_type>());
+    }
+
+    //*************************************************************************
+    /// Sort using in-place merge sort algorithm.
+    /// Uses a supplied predicate function or functor.
+    /// This is not my algorithm. I got it off the web somewhere.
+    //*************************************************************************
+    template <typename TCompare>
+    void sort(TCompare compare)
+    {
+      iterator i_left;
+      iterator i_right;
+      iterator i_link;
+      iterator i_head;
+      iterator i_tail;
+      int      list_size = 1;
+      int      number_of_merges;
+      int      left_size;
+      int      right_size;
+
+      if (this->is_trivial_list())
+      {
+        return;
+      }
+
+      while (true)
+      {
+        i_left = begin();
+        i_head = before_begin();
+        i_tail = before_begin();
+
+        number_of_merges = 0;  // Count the number of merges we do in this pass.
+
+        while (i_left != end())
+        {
+          ++number_of_merges;  // There exists a merge to be done.
+          i_right = i_left;
+          left_size = 0;
+
+          // Step 'list_size' places along from left
+          for (int i = 0; i < list_size; ++i)
+          {
+            ++left_size;
+
+            ++i_right;
+
+            if (i_right == end())
+            {
+              break;
+            }
+          }
+
+          // If right hasn't fallen off end, we have two lists to merge.
+          right_size = list_size;
+
+          // Now we have two lists. Merge them.
+          while (left_size > 0 || (right_size > 0 && i_right != end()))
+          {
+            // Decide whether the next link of merge comes from left or right.
+            if (left_size == 0)
+            {
+              // Left is empty. The link must come from right.
+              i_link = i_right;
+              ++i_right;
+              --right_size;
+            }
+            else if (right_size == 0 || i_right == end())
+            {
+              // Right is empty. The link must come from left.
+              i_link = i_left;
+              ++i_left;
+              --left_size;
+            }
+            else if (!compare(*i_right, *i_left))
+            {
+              // First link of left is lower or same. The link must come from left.
+              i_link = i_left;
+              ++i_left;
+              --left_size;
+            }
+            else
+            {
+              // First link of right is lower. The link must come from right.
+              i_link  = i_right;
+              ++i_right;
+              --right_size;
+            }
+
+            // Add the next link to the merged head.
+            if (i_head == before_begin())
+            {
+              etl::link<link_type>(i_head.p_value, i_link.p_value);
+              i_head = i_link;
+              i_tail = i_link;
+            }
+            else
+            {
+              etl::link<link_type>(i_tail.p_value, i_link.p_value);
+              i_tail = i_link;
+            }
+
+            i_tail.p_value->link_type::etl_next = std::nullptr;
+          }
+
+          // Now left has stepped `list_size' places along, and right has too.
+          i_left = i_right;
+        }
+
+        // If we have done only one merge, we're finished.
+        if (number_of_merges <= 1)   // Allow for number_of_merges == 0, the empty head case
+        {
+            return;
+        }
+
+        // Otherwise repeat, merging lists twice the size
+        list_size *= 2;
+      }
+    }
+
+    //*************************************************************************
+    // Removes the values specified.
+    //*************************************************************************
+    void remove(const_reference value)
+    {
+      iterator i_item = begin();
+      iterator i_last_item = before_begin();
+
+      while (i_item != end())
+      {
+        if (*i_item == value)
+        {
+          i_item = erase_after(i_last_item);
+        }
+        else
+        {
+          ++i_item;
+          ++i_last_item;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Removes according to a predicate.
+    //*************************************************************************
+    template <typename TPredicate>
+    void remove_if(TPredicate predicate)
+    {
+      iterator i_item = begin();
+      iterator i_last_item = before_begin();
+
+      while (i_item != end())
+      {
+        if (predicate(*i_item))
+        {
+          i_item = erase_after(i_last_item);
+        }
+        else
+        {
+          ++i_item;
+          ++i_last_item;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Splice another list into this one.
+    //*************************************************************************
+    void splice_after(iterator position, etl::intrusive_forward_list<TValue, TLink>& other)
+    {
+      // No point splicing to ourself!
+      if (&other != this)
+      {
+        if (!other.empty())
+        {
+          link_type& first = other.get_head();
+
+          if (&other != this)
+          {
+            this->current_size += other.size();
+          }
+
+          link_type& before = *position.p_value;
+          link_type& after  = *position.p_value->link_type::etl_next;
+
+          etl::link<link_type>(before, first);
+
+          link_type* last = &before;
+          while (last->link_type::etl_next != std::nullptr)
+          {
+            last = last->link_type::etl_next;
+          }
+
+          etl::link<link_type>(last, after);
+
+          other.initialise();
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Splice an element from another list into this one.
+    //*************************************************************************
+    void splice(iterator position, etl::intrusive_forward_list<TValue, TLink>& other, iterator isource)
+    {
+      link_type& before = *position.p_value;
+
+      etl::unlink<link_type>(*isource.p_value);
+      etl::link_splice<link_type>(before, *isource.p_value);
+
+      if (&other != this)
+      {
+        ++this->current_size;
+        --other.current_size;
+      }
+    }
+
+    //*************************************************************************
+    /// Splice a range of elements from another list into this one.
+    //*************************************************************************
+    void splice_after(iterator position, etl::intrusive_forward_list<TValue, TLink>& other, iterator begin_, iterator end_)
+    {
+      if (!other.empty())
+      {
+        if (&other != this)
+        {
+          size_t n = std::distance(begin_, end_) - 1;
+          this->current_size += n;
+          other.current_size -= n;
+        }
+
+        link_type* first = begin_.p_value;
+        link_type* last  = first;
+
+        while (last->link_type::etl_next != end_.p_value)
+        {
+          last = last->link_type::etl_next;
+        }
+
+        // Unlink from the source list.
+        link_type* first_next = first->link_type::etl_next;
+        etl::unlink_after(*first, *last);
+
+        // Fix our links.
+        link_type* before = position.p_value;
+
+        etl::link_splice<link_type>(*before, *first_next, *last);
+      }
+    }
+
+    //*************************************************************************
+    /// Merge another list into this one. Both lists should be sorted.
+    //*************************************************************************
+    void merge(list_type& other)
+    {
+      merge(other, std::less<value_type>());
+    }
+
+    //*************************************************************************
+    /// Merge another list into this one. Both lists should be sorted.
+    //*************************************************************************
+    template <typename TCompare>
+    void merge(list_type& other, TCompare compare)
+    {
+      if (!other.empty())
+      {
+#if defined(ETL_DEBUG)
+        ETL_ASSERT(etl::is_sorted(other.begin(), other.end(), compare), ETL_ERROR(intrusive_forward_list_unsorted));
+        ETL_ASSERT(etl::is_sorted(begin(), end(), compare), ETL_ERROR(intrusive_forward_list_unsorted));
+#endif
+
+        value_type* other_begin    = static_cast<value_type*>(&other.get_head());
+        value_type* other_terminal = std::nullptr;
+
+        value_type* before      = static_cast<value_type*>(&this->start_link);
+        value_type* before_next = get_next(before);
+        value_type* terminal    = std::nullptr;
+
+        while ((before->link_type::etl_next != terminal) && (other_begin != other_terminal))
+        {
+          // Find the place to insert.
+          while ((before_next != terminal) && !(compare(*other_begin, *before_next)))
+          {
+            before      = before_next;
+            before_next = get_next(before_next);
+          }
+
+          // Insert.
+          if (before_next != terminal)
+          {
+            while ((other_begin != other_terminal) && (compare(*other_begin, *before_next)))
+            {
+              value_type* value = other_begin;
+              other_begin = get_next(other_begin);
+              etl::link_splice<link_type>(*before, *value);
+              before = get_next(before);
+            }
+          }
+        }
+
+        // Any left over?
+        if (before_next == terminal)
+        {
+          while (other_begin != other_terminal)
+          {
+            value_type* value = other_begin;
+            other_begin = get_next(other_begin);
+            etl::link_splice<link_type>(*before, *value);
+            before = get_next(before);
+          }
+        }
+
+        this->current_size += other.size();
+
+        other.initialise();
+      }
+    }
+
+  private:
+
+    //*************************************************************************
+    /// Get the next value.
+    //*************************************************************************
+    value_type* get_next(link_type* link) const
+    {
+      return static_cast<value_type*>(link->etl_next);
+    }
+
+    // Disabled.
+    intrusive_forward_list(const intrusive_forward_list& other);
+    intrusive_forward_list& operator = (const intrusive_forward_list& rhs);
+  };
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/intrusive_links.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,795 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_INTRUSIVE_LINKS__
+#define __ETL_INTRUSIVE_LINKS__
+
+#include <assert.h>
+#include <utility>
+
+#include "platform.h"
+#include "nullptr.h"
+#include "type_traits.h"
+#include "exception.h"
+#include "error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "22"
+
+//*****************************************************************************
+// Note:
+// The link functions work slightly differently to the STL 'insert' convention
+// in that the second link parameter will be inserted after the first.
+// i.e.
+// If the list contains '1', '2', '3', '4' and "link_splice '2','5'" is invoked the
+// resulting list will contain '1', '2', '5', '3', '4'
+// This is to maintain consistency between forward and bidirectional links
+// and also is intuitive.
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Link exception.
+  //***************************************************************************
+  class link_exception : public etl::exception
+  {
+  public:
+
+    link_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// not unlinked exception.
+  //***************************************************************************
+  class not_unlinked_exception : public etl::link_exception
+  {
+  public:
+
+    not_unlinked_exception(string_type file_name_, numeric_type line_number_)
+      : link_exception(ETL_ERROR_TEXT("link:still linked", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// A forward link.
+  //***************************************************************************
+  template <const size_t ID_>
+  struct forward_link
+  {
+      enum
+      {
+        ID = ID_,
+      };
+
+      void clear()
+      {
+        etl_next = std::nullptr;
+      }
+
+      bool is_linked() const
+      {
+        return etl_next != std::nullptr;
+      }
+
+      forward_link* etl_next;
+  };
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link(TLink& lhs, TLink& rhs)
+  {
+    lhs.etl_next = &rhs;
+  }
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link_splice(TLink& lhs, TLink& rhs)
+  {
+    rhs.etl_next = lhs.etl_next;
+    lhs.etl_next = &rhs;
+  }
+
+  // Pointer, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link(TLink* lhs, TLink* rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      lhs->etl_next = rhs;
+    }
+  }
+
+  // Pointer, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link_splice(TLink* lhs, TLink* rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      if (rhs != std::nullptr)
+      {
+          rhs->etl_next = lhs->etl_next;
+      }
+
+      lhs->etl_next = rhs;
+    }
+  }
+
+  // Reference, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link(TLink& lhs, TLink* rhs)
+  {
+    lhs.etl_next = rhs;
+  }
+
+  // Reference, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link_splice(TLink& lhs, TLink* rhs)
+  {
+    if (rhs != std::nullptr)
+    {
+      rhs->etl_next = lhs.etl_next;
+    }
+
+    lhs.etl_next = rhs;
+  }
+
+  // Pointer, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link(TLink* lhs, TLink& rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      lhs->etl_next = &rhs;
+    }
+  }
+
+  // Pointer, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link_splice(TLink* lhs, TLink& rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      rhs.etl_next  = lhs->etl_next;
+      lhs->etl_next = &rhs;
+    }
+  }
+
+  // Reference, Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link_splice(TLink& lhs, TLink& first, TLink& last)
+  {
+    last.etl_next = lhs.etl_next;
+    lhs.etl_next  = &first;
+  }
+
+  // Pointer, Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  link_splice(TLink* lhs, TLink& first, TLink& last)
+  {
+    if (lhs != std::nullptr)
+    {
+      last.etl_next = lhs->etl_next;
+      lhs->etl_next  = &first;
+    }
+    else
+    {
+      last.etl_next = std::nullptr;
+    }
+  }
+
+  // Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  unlink_after(TLink& node)
+  {
+    if (node.etl_next != std::nullptr)
+    {
+      TLink* unlinked_node = node.etl_next;
+      node.etl_next = unlinked_node->etl_next;
+    }
+  }
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type
+  unlink_after(TLink& before, TLink& last)
+  {
+    before.etl_next = last.etl_next;
+  }
+
+  //***************************************************************************
+  /// A bidirectional link.
+  //***************************************************************************
+  template <const size_t ID_>
+  struct bidirectional_link
+  {
+      enum
+      {
+        ID = ID_,
+      };
+
+      void clear()
+      {
+        etl_previous = std::nullptr;
+        etl_next     = std::nullptr;
+      }
+
+      bool is_linked() const
+      {
+        return (etl_previous != std::nullptr) || (etl_next != std::nullptr);
+      }
+
+      void reverse()
+      {
+        std::swap(etl_previous, etl_next);
+      }
+
+      bidirectional_link* etl_previous;
+      bidirectional_link* etl_next;
+
+    void unlink()
+    {
+        // Connect the previous link with the next.
+        if (etl_previous != std::nullptr)
+        {
+          etl_previous->etl_next = etl_next;
+        }
+
+        // Connect the next link with the previous.
+        if (etl_next != std::nullptr)
+        {
+          etl_next->etl_previous = etl_previous;
+        }
+    }
+  };
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link(TLink& lhs, TLink& rhs)
+  {
+    lhs.etl_next     = &rhs;
+    rhs.etl_previous = &lhs;
+  }
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link_splice(TLink& lhs, TLink& rhs)
+  {
+    rhs.etl_next     = lhs.etl_next;
+    rhs.etl_previous = &lhs;
+
+    if (lhs.etl_next != std::nullptr)
+    {
+      lhs.etl_next->etl_previous = &rhs;
+    }
+
+    lhs.etl_next = &rhs;
+  }
+
+  // Pointer, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link(TLink* lhs, TLink* rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      lhs->etl_next = rhs;
+    }
+
+    if (rhs != std::nullptr)
+    {
+      rhs->etl_previous = lhs;
+    }
+  }
+
+  // Pointer, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link_splice(TLink* lhs, TLink* rhs)
+  {
+    if (rhs != std::nullptr)
+    {
+      if (lhs != std::nullptr)
+      {
+        rhs->etl_next = lhs->etl_next;
+      }
+
+      rhs->etl_previous = lhs;
+    }
+
+    if (lhs != std::nullptr)
+    {
+      if (lhs->etl_next != std::nullptr)
+      {
+        lhs->etl_next->etl_previous = rhs;
+      }
+
+      lhs->etl_next = rhs;
+    }
+  }
+
+  // Reference, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link(TLink& lhs, TLink* rhs)
+  {
+    lhs.etl_next = rhs;
+
+    if (rhs != std::nullptr)
+    {
+      rhs->etl_previous = &lhs;
+    }
+  }
+
+  // Reference, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link_splice(TLink& lhs, TLink* rhs)
+  {
+    if (rhs != std::nullptr)
+    {
+      rhs->etl_next     = lhs.etl_next;
+      rhs->etl_previous = &lhs;
+    }
+
+    if (lhs.etl_next != std::nullptr)
+    {
+      lhs.etl_next->etl_previous = rhs;
+    }
+
+    lhs.etl_next = rhs;
+  }
+
+  // Pointer, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link(TLink* lhs, TLink& rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      lhs->etl_next = &rhs;
+    }
+
+    rhs.etl_previous = lhs;
+  }
+
+  // Pointer, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link_splice(TLink* lhs, TLink& rhs)
+  {
+    if (lhs != std::nullptr)
+    {
+      rhs.etl_next = lhs->etl_next;
+    }
+
+    rhs.etl_previous = lhs;
+
+    if (lhs != std::nullptr)
+    {
+      if (lhs->etl_next != std::nullptr)
+      {
+        lhs->etl_next->etl_previous = &rhs;
+      }
+
+      lhs->etl_next = &rhs;
+    }
+  }
+
+  // Reference, Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link_splice(TLink& lhs, TLink& first, TLink& last)
+  {
+    last.etl_next = lhs.etl_next;
+    first.etl_previous = &lhs;
+
+    if (last.etl_next != std::nullptr)
+    {
+      last.etl_next->etl_previous = &last;
+    }
+
+    lhs.etl_next = &first;
+  }
+
+  // Pointer, Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  link_splice(TLink* lhs, TLink& first, TLink& last)
+  {
+    if (lhs != std::nullptr)
+    {
+      last.etl_next = lhs->etl_next;
+    }
+    else
+    {
+      last.etl_next = std::nullptr;
+    }
+
+    first.etl_previous = lhs;
+
+    if (last.etl_next != std::nullptr)
+    {
+      last.etl_next->etl_previous = &last;
+    }
+
+    if (lhs != std::nullptr)
+    {
+      lhs->etl_next = &first;
+    }
+  }
+
+  // Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  unlink(TLink& node)
+  {
+    node.unlink();
+  }
+
+  // Reference Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type
+  unlink(TLink& first, TLink& last)
+  {
+    if (&first == &last)
+    {
+      first.unlink();
+    }
+    else
+    {
+      if (last.etl_next != std::nullptr)
+      {
+        last.etl_next->etl_previous = first.etl_previous;
+      }
+
+      if (first.etl_previous != std::nullptr)
+      {
+        first.etl_previous->etl_next = last.etl_next;
+      }
+    }
+  }
+
+  //***************************************************************************
+  /// A binary tree link.
+  //***************************************************************************
+  template <const size_t ID_>
+  struct tree_link
+  {
+      enum
+      {
+        ID = ID_,
+      };
+
+      void clear()
+      {
+        etl_parent = std::nullptr;
+        etl_left   = std::nullptr;
+        etl_right  = std::nullptr;
+      }
+
+      bool is_linked() const
+      {
+        return (etl_parent != std::nullptr) || (etl_left != std::nullptr) || (etl_right != std::nullptr);
+      }
+
+      tree_link* etl_parent;
+      tree_link* etl_left;
+      tree_link* etl_right;
+  };
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_left(TLink& parent, TLink& leaf)
+  {
+    parent.etl_left = &leaf;
+    leaf.etl_parent = &parent;
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_right(TLink& parent, TLink& leaf)
+  {
+    parent.etl_right = &leaf;
+    leaf.etl_parent  = &parent;
+  }
+
+  // Pointer, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_left(TLink* parent, TLink* leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      parent->etl_left = leaf;
+    }
+
+    if (leaf != std::nullptr)
+    {
+      leaf->etl_parent = parent;
+    }
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_right(TLink* parent, TLink* leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      parent->etl_right = leaf;
+    }
+
+    if (leaf != std::nullptr)
+    {
+      leaf->etl_parent = parent;
+    }
+  }
+
+  // Reference, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_left(TLink& parent, TLink* leaf)
+  {
+    parent.etl_left = leaf;
+
+    if (leaf != std::nullptr)
+    {
+      leaf->etl_parent = &parent;
+    }
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_right(TLink& parent, TLink* leaf)
+  {
+    parent.etl_right = leaf;
+
+    if (leaf != std::nullptr)
+    {
+      leaf->etl_parent = &parent;
+    }
+  }
+
+  // Pointer, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_left(TLink* parent, TLink& leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      parent->etl_left = &leaf;
+    }
+
+    leaf.etl_parent = parent;
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_right(TLink* parent, TLink& leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      parent->etl_right = &leaf;
+    }
+
+    leaf.etl_parent = parent;
+  }
+
+  // Reference, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_left(TLink& parent, TLink& leaf)
+  {
+     parent.etl_right = leaf.etl_left;
+
+     if (parent.etl_right != std::nullptr)
+     {
+       parent.etl_right->etl_parent = &parent;
+     }
+
+     leaf.etl_parent   = parent.etl_parent;
+     parent.etl_parent = &leaf;
+     leaf.etl_left     = &parent;
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_right(TLink& parent, TLink& leaf)
+  {
+     parent.etl_left = leaf.etl_right;
+
+     if (parent.etl_left != std::nullptr)
+     {
+       parent.etl_left->etl_parent = &parent;
+     }
+
+     leaf.etl_parent   = parent.etl_parent;
+     parent.etl_parent = &leaf;
+     leaf.etl_right    = &parent;
+  }
+
+  // Pointer, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_left(TLink* parent, TLink* leaf)
+  {
+    if ((parent != std::nullptr) && (leaf != std::nullptr))
+    {
+      link_rotate_left(*parent, *leaf);
+    }
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_right(TLink* parent, TLink* leaf)
+  {
+    if ((parent != std::nullptr) && (leaf != std::nullptr))
+    {
+      link_rotate_right(*parent, *leaf);
+    }
+  }
+
+  // Reference, Pointer
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_left(TLink& parent, TLink* leaf)
+  {
+    if (leaf != std::nullptr)
+    {
+      link_rotate_left(parent, *leaf);
+    }
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_right(TLink& parent, TLink* leaf)
+  {
+    if (leaf != std::nullptr)
+    {
+      link_rotate_right(parent, *leaf);
+    }
+  }
+
+  // Pointer, Reference
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_left(TLink* parent, TLink& leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      link_rotate_left(*parent, leaf);
+    }
+  }
+
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate_right(TLink* parent, TLink& leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      link_rotate_right(*parent, leaf);
+    }
+  }
+
+  // Reference, Reference
+  /// Automatically detects whether a left or right rotate is expected.
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate(TLink& parent, TLink& leaf)
+  {
+    if (parent.etl_left == &leaf)
+    {
+      etl::link_rotate_right(parent, leaf);
+    }
+    else
+    {
+      etl::link_rotate_left(parent, leaf);
+    }
+  }
+
+  // Pointer, Pointer
+  /// Automatically detects whether a left or right rotate is expected.
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate(TLink* parent, TLink* leaf)
+  {
+    if ((parent != std::nullptr) && (leaf != std::nullptr))
+    {
+      if (parent->etl_left == leaf)
+      {
+        etl::link_rotate_right(*parent, *leaf);
+      }
+      else
+      {
+        etl::link_rotate_left(*parent, *leaf);
+      }
+    }
+  }
+
+  // Reference, Pointer
+  /// Automatically detects whether a left or right rotate is expected.
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate(TLink& parent, TLink* leaf)
+  {
+    if (leaf != std::nullptr)
+    {
+      if (parent.etl_left == leaf)
+      {
+        etl::link_rotate_right(parent, *leaf);
+      }
+      else
+      {
+        etl::link_rotate_left(parent, *leaf);
+      }
+    }
+  }
+
+  // Pointer, Reference
+  /// Automatically detects whether a left or right rotate is expected.
+  template <typename TLink>
+  typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type
+  link_rotate(TLink* parent, TLink& leaf)
+  {
+    if (parent != std::nullptr)
+    {
+      if (parent->etl_left == &leaf)
+      {
+        etl::link_rotate_right(*parent, leaf);
+      }
+      else
+      {
+        etl::link_rotate_left(*parent, leaf);
+      }
+    }
+  }
+}
+
+#undef ETL_FILE
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/intrusive_list.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1081 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_INTRUSIVE_LIST__
+#define __ETL_INTRUSIVE_LIST__
+
+#include "platform.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "platform.h"
+#include "nullptr.h"
+#include "type_traits.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "intrusive_links.h"
+#include "static_assert.h"
+#include "algorithm.h"
+
+#undef ETL_FILE
+#define ETL_FILE "21"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the intrusive_list.
+  ///\ingroup intrusive_list
+  //***************************************************************************
+  class intrusive_list_exception : public exception
+  {
+  public:
+
+    intrusive_list_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Empty exception for the intrusive_list.
+  ///\ingroup intrusive_list
+  //***************************************************************************
+  class intrusive_list_empty : public intrusive_list_exception
+  {
+  public:
+
+    intrusive_list_empty(string_type file_name_, numeric_type line_number_)
+      : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:empty", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the intrusive_list.
+  ///\ingroup intrusive_list
+  //***************************************************************************
+  class intrusive_list_iterator_exception : public intrusive_list_exception
+  {
+  public:
+
+    intrusive_list_iterator_exception(string_type file_name_, numeric_type line_number_)
+      : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:iterator", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Unsorted exception for the intrusive_list.
+  ///\ingroup intrusive_list
+  //***************************************************************************
+  class intrusive_list_unsorted : public intrusive_list_exception
+  {
+  public:
+
+    intrusive_list_unsorted(string_type file_name_, numeric_type line_number_)
+      : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:unsorted", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Base for intrusive list.
+  ///\ingroup intrusive_list
+  //***************************************************************************
+  template <typename TLink>
+  class intrusive_list_base
+  {
+  public:
+
+    // Node typedef.
+    typedef TLink link_type;
+
+    //*************************************************************************
+    /// Assigns a range of values to the intrusive_list.
+    /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined emits a
+    /// intrusive_list_iterator_exception if the iterators are reversed.
+    //*************************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      intmax_t d = std::distance(first, last);
+      ETL_ASSERT(d >= 0, ETL_ERROR(intrusive_list_iterator_exception));
+#endif
+
+      initialise();
+
+      link_type* p_last_link = &terminal_link;
+
+      // Add all of the elements.
+      while (first != last)
+      {
+        link_type& link = *first++;
+        etl::link_splice<link_type>(p_last_link, link);
+        p_last_link = &link;
+        ++current_size;
+      }
+    }
+
+    //*************************************************************************
+    /// Pushes a value to the front of the intrusive_list.
+    //*************************************************************************
+    void push_front(link_type& value)
+    {
+      insert_link(terminal_link, value);
+    }
+
+    //*************************************************************************
+    /// Removes a value from the front of the intrusive_list.
+    //*************************************************************************
+    void pop_front()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(intrusive_list_empty));
+#endif
+      remove_link(get_head());
+    }
+
+    //*************************************************************************
+    /// Pushes a value to the back of the intrusive_list.
+    //*************************************************************************
+    void push_back(link_type& value)
+    {
+      insert_link(terminal_link.link_type::etl_previous, value);
+    }
+
+    //*************************************************************************
+    /// Removes a value from the back of the intrusive_list.
+    //*************************************************************************
+    void pop_back()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(intrusive_list_empty));
+#endif
+      remove_link(get_tail());
+    }
+
+    //*************************************************************************
+    /// Clears the intrusive_list.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*************************************************************************
+    /// Reverses the list.
+    //*************************************************************************
+    void reverse()
+    {
+      if (is_trivial_list())
+      {
+        return;
+      }
+
+      link_type* pnode = terminal_link.etl_next;
+
+      while (pnode != &terminal_link)
+      {
+        pnode->reverse();
+        pnode = pnode->etl_previous; // Now we've reversed it, we must go to the previous node.
+      }
+
+      // Terminal node.
+      pnode->reverse();
+    }
+
+    //*************************************************************************
+    /// Returns true if the list has no elements.
+    //*************************************************************************
+    bool empty() const
+    {
+      return (terminal_link.link_type::etl_next == &terminal_link);
+    }
+
+    //*************************************************************************
+    /// Returns the number of elements.
+    //*************************************************************************
+    size_t size() const
+    {
+      return current_size;
+    }
+
+  protected:
+
+    /// The link that acts as the intrusive_list start & end.
+    link_type terminal_link;
+
+    size_t current_size; ///< Counts the number of elements in the list.
+
+    //*************************************************************************
+    /// Is the intrusive_list a trivial length?
+    //*************************************************************************
+    bool is_trivial_list() const
+    {
+      return (terminal_link.link_type::etl_next == &terminal_link) || (terminal_link.link_type::etl_next->etl_next == &terminal_link);
+    }
+
+    //*************************************************************************
+    /// Insert a link.
+    //*************************************************************************
+    void insert_link(link_type& previous, link_type& new_link)
+    {
+      // Connect to the intrusive_list.
+      etl::link_splice<link_type>(previous, new_link);
+      ++current_size;
+    }
+
+    //*************************************************************************
+    /// Insert a link.
+    //*************************************************************************
+    void insert_link(link_type* previous, link_type& new_link)
+    {
+      // Connect to the intrusive_list.
+      etl::link_splice<link_type>(previous, new_link);
+      ++current_size;
+    }
+
+    //*************************************************************************
+    /// Insert a link.
+    //*************************************************************************
+    void insert_link(link_type& previous, link_type* new_link)
+    {
+      // Connect to the intrusive_list.
+      etl::link_splice<link_type>(previous, new_link);
+      ++current_size;
+    }
+
+    //*************************************************************************
+    /// Insert a link.
+    //*************************************************************************
+    void insert_link(link_type* previous, link_type* new_link)
+    {
+      // Connect to the intrusive_list.
+      etl::link_splice<link_type>(previous, new_link);
+      ++current_size;
+    }
+
+    //*************************************************************************
+    /// Remove a link.
+    //*************************************************************************
+    void remove_link(link_type& link)
+    {
+      etl::unlink<link_type>(link);
+      --current_size;
+    }
+
+    //*************************************************************************
+    /// Remove a link.
+    //*************************************************************************
+    void remove_link(link_type* link)
+    {
+      etl::unlink<link_type>(*link);
+      --current_size;
+    }
+
+    //*************************************************************************
+    /// Get the head link.
+    //*************************************************************************
+    link_type* get_head()
+    {
+      return terminal_link.etl_next;
+    }
+
+    //*************************************************************************
+    /// Get the head link.
+    //*************************************************************************
+    const link_type* get_head() const
+    {
+      return terminal_link.etl_next;
+    }
+
+    //*************************************************************************
+    /// Get the tail link.
+    //*************************************************************************
+    link_type* get_tail()
+    {
+      return terminal_link.etl_previous;
+    }
+
+    //*************************************************************************
+    /// Get the tail link.
+    //*************************************************************************
+    const link_type* get_tail() const
+    {
+      return terminal_link.etl_previous;
+    }
+
+    //*************************************************************************
+    /// Initialise the intrusive_list.
+    //*************************************************************************
+    void initialise()
+    {
+      etl::link(terminal_link, terminal_link);
+      current_size = 0;
+    }
+  };
+
+  //***************************************************************************
+  /// An intrusive list.
+  ///\ingroup intrusive_list
+  ///\note TLink must be a base of TValue.
+  //***************************************************************************
+  template <typename TValue, typename TLink = etl::bidirectional_link<0> >
+  class intrusive_list : public etl::intrusive_list_base<TLink>
+  {
+  public:
+
+    // Node typedef.
+    typedef typename etl::intrusive_list_base<TLink>::link_type link_type;
+
+    typedef intrusive_list<TValue, TLink> list_type;
+
+    // STL style typedefs.
+    typedef TValue            value_type;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef size_t            size_type;
+
+    //*************************************************************************
+    /// iterator.
+    //*************************************************************************
+    class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+    {
+    public:
+
+      friend class intrusive_list;
+
+      iterator()
+        : p_value(std::nullptr)
+      {
+      }
+
+      iterator(value_type& value)
+        : p_value(&value)
+      {
+      }
+
+      iterator(const iterator& other)
+        : p_value(other.p_value)
+      {
+      }
+
+      iterator& operator ++()
+      {
+        // Read the appropriate 'etl_next'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        // Read the appropriate 'etl_next'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+        return temp;
+      }
+
+      iterator& operator --()
+      {
+        // Read the appropriate 'etl_previous'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_previous);
+        return *this;
+      }
+
+      iterator operator --(int)
+      {
+        iterator temp(*this);
+        // Read the appropriate 'etl_previous'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_previous);
+        return temp;
+      }
+
+      iterator operator =(const iterator& other)
+      {
+        p_value = other.p_value;
+        return *this;
+      }
+
+      reference operator *()
+      {
+        return *p_value;
+      }
+
+      const_reference operator *() const
+      {
+        return *p_value;
+      }
+
+      pointer operator &()
+      {
+        return p_value;
+      }
+
+      const_pointer operator &() const
+      {
+        return p_value;
+      }
+
+      pointer operator ->()
+      {
+        return p_value;
+      }
+
+      const_pointer operator ->() const
+      {
+        return p_value;
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.p_value == rhs.p_value;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      value_type* p_value;
+    };
+
+    //*************************************************************************
+    /// const_iterator
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+    {
+    public:
+
+      friend class intrusive_list;
+
+      const_iterator()
+        : p_value(std::nullptr)
+      {
+      }
+
+      const_iterator(const value_type& value)
+        : p_value(&value)
+      {
+      }
+
+      const_iterator(const typename intrusive_list::iterator& other)
+        : p_value(other.p_value)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : p_value(other.p_value)
+      {
+      }
+
+      const_iterator& operator ++()
+      {
+        // Read the appropriate 'etl_next'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        // Read the appropriate 'etl_next'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_next);
+        return temp;
+      }
+
+      const_iterator& operator --()
+      {
+        // Read the appropriate 'etl_previous'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_previous);
+        return *this;
+      }
+
+      const_iterator operator --(int)
+      {
+        const_iterator temp(*this);
+        // Read the appropriate 'etl_previous'.
+        p_value = static_cast<value_type*>(p_value->link_type::etl_previous);
+        return temp;
+      }
+
+      const_iterator operator =(const const_iterator& other)
+      {
+        p_value = other.p_value;
+        return *this;
+      }
+
+      const_reference operator *() const
+      {
+        return *p_value;
+      }
+
+      const_pointer operator &() const
+      {
+        return p_value;
+      }
+
+      const_pointer operator ->() const
+      {
+        return p_value;
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.p_value == rhs.p_value;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      const value_type* p_value;
+    };
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    intrusive_list()
+    {
+      this->initialise();
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~intrusive_list()
+    {
+      this->clear();
+    }
+
+    //*************************************************************************
+    /// Constructor from range
+    //*************************************************************************
+    template <typename TIterator>
+    intrusive_list(TIterator first, TIterator last)
+    {
+      this->assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the intrusive_list.
+    //*************************************************************************
+    iterator begin()
+    {
+      return iterator(static_cast<value_type&>(*this->get_head()));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the intrusive_list.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(static_cast<const value_type&>(*this->get_head()));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the intrusive_list.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(static_cast<const value_type&>(*this->get_head()));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the intrusive_list.
+    //*************************************************************************
+    iterator end()
+    {
+      return iterator(static_cast<value_type&>(this->terminal_link));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the intrusive_list.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(static_cast<const value_type&>(this->terminal_link));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the intrusive_list.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(static_cast<const value_type&>(this->terminal_link));
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the first element.
+    //*************************************************************************
+    reference front()
+    {
+      return *static_cast<value_type*>(this->get_head());
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the first element.
+    //*************************************************************************
+    const_reference front() const
+    {
+      return *static_cast<const value_type*>(this->get_head());;
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the last element.
+    //*************************************************************************
+    reference back()
+    {
+      return *static_cast<value_type*>(this->get_tail());
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the last element.
+    //*************************************************************************
+    const_reference back() const
+    {
+      return *static_cast<const value_type*>(this->get_tail());;
+    }
+
+    //*************************************************************************
+    /// Inserts a value to the intrusive_list before the specified position.
+    //*************************************************************************
+    iterator insert(iterator position, value_type& value)
+    {
+      this->insert_link(position.p_value->link_type::etl_previous, value);
+      return iterator(value);
+    }
+
+    //*************************************************************************
+    /// Inserts a range of values to the intrusive_list after the specified position.
+    //*************************************************************************
+    template <typename TIterator>
+    void insert(iterator position, TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        // Set up the next free link.
+        this->insert_link(*position.p_value->link_type::etl_previous, *first++);
+      }
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    iterator erase(iterator position)
+    {
+      iterator next(position);
+      ++next;
+
+      this->remove_link(*position.p_value);
+
+      return next;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    /// Clears the links after erasing if AUTO or CHECKED.
+    //*************************************************************************
+    iterator erase(iterator first, iterator last)
+    {
+      link_type* p_first = first.p_value;
+      link_type* p_last  = last.p_value;
+
+      // Join the ends.
+      etl::link<link_type>(p_first->etl_previous, p_last);
+
+      this->current_size -= std::distance(first, last);
+
+      if (p_last == &this->terminal_link)
+      {
+        return end();
+      }
+      else
+      {
+        return iterator(*static_cast<value_type*>(p_last));
+      }
+    }
+
+    //*************************************************************************
+    /// Removes all but the one element from every consecutive group of equal
+    /// elements in the container.
+    //*************************************************************************
+    template <typename TIsEqual>
+    void unique(TIsEqual isEqual)
+    {
+      if (this->empty())
+      {
+        return;
+      }
+
+      iterator i_item = begin();
+      ++i_item;
+      iterator i_previous = begin();
+
+      while (i_item != end())
+      {
+        if (isEqual(*i_previous, *i_item))
+        {
+          i_item = erase(i_item);
+        }
+        else
+        {
+          i_previous = i_item;
+          ++i_item;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Sort using in-place merge sort algorithm.
+    //*************************************************************************
+    void sort()
+    {
+      sort(std::less<value_type>());
+    }
+
+    //*************************************************************************
+    /// Sort using in-place merge sort algorithm.
+    /// Uses a supplied predicate function or functor.
+    /// This is not my algorithm. I got it off the web somewhere.
+    //*************************************************************************
+    template <typename TCompare>
+    void sort(TCompare compare)
+    {
+      iterator i_left;
+      iterator i_right;
+      iterator i_node;
+      iterator i_head;
+      iterator i_tail;
+      int      list_size = 1;
+      int      number_of_merges;
+      int      left_size;
+      int      right_size;
+
+      if (this->is_trivial_list())
+      {
+        return;
+      }
+
+      while (true)
+      {
+        i_left = begin();
+        i_head = end();
+        i_tail = end();
+
+        number_of_merges = 0;  // Count the number of merges we do in this pass.
+
+        while (i_left != end())
+        {
+          ++number_of_merges;  // There exists a merge to be done.
+          i_right = i_left;
+          left_size = 0;
+
+          // Step 'list_size' places along from left
+          for (int i = 0; i < list_size; ++i)
+          {
+            ++left_size;
+            ++i_right;
+
+            if (i_right == end())
+            {
+              break;
+            }
+          }
+
+          // If right hasn't fallen off end, we have two lists to merge.
+          right_size = list_size;
+
+          // Now we have two lists. Merge them.
+          while (left_size > 0 || (right_size > 0 && i_right != end()))
+          {
+            // Decide whether the next node of merge comes from left or right.
+            if (left_size == 0)
+            {
+              // Left is empty. The node must come from right.
+              i_node = i_right++;
+              --right_size;
+            }
+            else if (right_size == 0 || i_right == end())
+            {
+              // Right is empty. The node must come from left.
+              i_node = i_left++;
+              --left_size;
+            }
+            else if (!compare(*i_right, *i_left))
+            {
+              // First node of left is lower or same. The node must come from left.
+              i_node = i_left++;
+              --left_size;
+            }
+            else
+            {
+              // First node of right is lower. The node must come from right.
+              i_node = i_right;
+              ++i_right;
+              --right_size;
+            }
+
+            // Add the next node to the merged head.
+            if (i_head == end())
+            {
+              etl::link<link_type>(i_head.p_value, i_node.p_value);
+              i_head = i_node;
+              i_tail = i_node;
+            }
+            else
+            {
+              etl::link<link_type>(i_tail.p_value, i_node.p_value);
+              i_tail = i_node;
+            }
+
+            etl::link<link_type>(i_tail.p_value, this->terminal_link);
+          }
+
+          // Now left has stepped `list_size' places along, and right has too.
+          i_left = i_right;
+        }
+
+        // If we have done only one merge, we're finished.
+        if (number_of_merges <= 1)   // Allow for number_of_merges == 0, the empty head case
+        {
+          return;
+        }
+
+        // Otherwise repeat, merging lists twice the size
+        list_size *= 2;
+      }
+    }
+
+    //*************************************************************************
+    // Removes the values specified.
+    //*************************************************************************
+    void remove(const_reference value)
+    {
+      iterator i_item = begin();
+
+      while (i_item != end())
+      {
+        if (*i_item == value)
+        {
+          i_item = erase(i_item);
+        }
+        else
+        {
+          ++i_item;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Removes according to a predicate.
+    //*************************************************************************
+    template <typename TPredicate>
+    void remove_if(TPredicate predicate)
+    {
+      iterator i_item = begin();
+
+      while (i_item != end())
+      {
+        if (predicate(*i_item))
+        {
+          i_item = erase(i_item);
+        }
+        else
+        {
+          ++i_item;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Splice another list into this one.
+    //*************************************************************************
+    void splice(iterator position, list_type& other)
+    {
+      // No point splicing to ourself!
+      if (&other != this)
+      {
+        if (!other.empty())
+        {
+          link_type& first = *other.get_head();
+          link_type& last = *other.get_tail();
+
+          if (&other != this)
+          {
+            this->current_size += other.size();
+          }
+
+          link_type& after = *position.p_value;
+          link_type& before = *after.etl_previous;
+
+          etl::link<link_type>(before, first);
+          etl::link<link_type>(last, after);
+
+          other.initialise();
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Splice an element from another list into this one.
+    //*************************************************************************
+    void splice(iterator position, list_type& other, iterator isource)
+    {
+      link_type& before = *position.p_value->link_type::etl_previous;
+
+      etl::unlink<link_type>(*isource.p_value);
+      etl::link_splice<link_type>(before, *isource.p_value);
+
+      if (&other != this)
+      {
+        ++this->current_size;
+        --other.current_size;
+      }
+    }
+
+    //*************************************************************************
+    /// Splice a range of elements from another list into this one.
+    //*************************************************************************
+    void splice(iterator position, list_type& other, iterator begin_, iterator end_)
+    {
+      if (!other.empty())
+      {
+        if (&other != this)
+        {
+          size_t n = std::distance(begin_, end_);
+          this->current_size += n;
+          other.current_size -= n;
+        }
+
+        link_type& first = *begin_.p_value;
+        link_type& last  = *end_.p_value->link_type::etl_previous;
+
+        // Unlink from the source list.
+        etl::unlink(first, last);
+
+        // Fix our links.
+        link_type& before = *position.p_value->link_type::etl_previous;
+
+        etl::link_splice<link_type>(before, first, last);
+      }
+    }
+
+    //*************************************************************************
+    /// Merge another list into this one. Both lists should be sorted.
+    //*************************************************************************
+    void merge(list_type& other)
+    {
+      merge(other, std::less<value_type>());
+    }
+
+    //*************************************************************************
+    /// Merge another list into this one. Both lists should be sorted.
+    //*************************************************************************
+    template <typename TCompare>
+    void merge(list_type& other, TCompare compare)
+    {
+      if (!other.empty())
+      {
+#if defined(ETL_DEBUG)
+        ETL_ASSERT(etl::is_sorted(other.begin(), other.end(), compare), ETL_ERROR(intrusive_list_unsorted));
+        ETL_ASSERT(etl::is_sorted(begin(), end(), compare), ETL_ERROR(intrusive_list_unsorted));
+#endif
+
+        value_type* other_begin = static_cast<value_type*>(other.get_head());
+        value_type* other_end   = static_cast<value_type*>(&other.terminal_link);
+
+        value_type* this_begin = static_cast<value_type*>(this->get_head());
+        value_type* this_end   = static_cast<value_type*>(&this->terminal_link);
+
+        while ((this_begin != this_end) && (other_begin != other_end))
+        {
+          // Find the place to insert.
+          while ((this_begin != this_end) && !(compare(*other_begin, *this_begin)))
+          {
+            this_begin = static_cast<value_type*>(this_begin->link_type::etl_next);
+          }
+
+          // Insert.
+          if (this_begin != this_end)
+          {
+            while ((other_begin != other_end) && (compare(*other_begin, *this_begin)))
+            {
+              value_type* value = other_begin;
+              other_begin = static_cast<value_type*>(other_begin->link_type::etl_next);
+              etl::link_splice<link_type>(*this_begin->link_type::etl_previous, *value);
+            }
+          }
+        }
+
+        // Any left over?
+        if ((this_begin == this_end) && (other_begin != other_end))
+        {
+          etl::link_splice<link_type>(*this->get_tail(), *other_begin, *other_end->link_type::etl_previous);
+        }
+
+        this->current_size += other.size();
+
+        other.initialise();
+      }
+    }
+
+  private:
+
+    // Disabled.
+    intrusive_list(const intrusive_list& other);
+    intrusive_list& operator = (const intrusive_list& rhs);
+  };
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/intrusive_queue.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,272 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_INTRUSIVE_QUEUE__
+#define __ETL_INTRUSIVE_QUEUE__
+
+#include <stddef.h>
+
+#include "platform.h"
+#include "type_traits.h"
+#include "error_handler.h"
+#include "intrusive_links.h"
+
+#define ETL_FILE "29"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception base for intrusive queue
+  ///\ingroup intrusive_queue
+  //***************************************************************************
+  class intrusive_queue_exception : public etl::exception
+  {
+  public:
+
+    intrusive_queue_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// intrusive_queue empty exception.
+  ///\ingroup intrusive_queue
+  //***************************************************************************
+  class intrusive_queue_empty : public intrusive_queue_exception
+  {
+  public:
+
+    intrusive_queue_empty(string_type file_name_, numeric_type line_number_)
+      : intrusive_queue_exception(ETL_ERROR_TEXT("intrusive_queue:empty", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup queue
+  /// Base for intrusive queue. Stores elements derived any type that supports an 'etl_next' pointer member.
+  /// \tparam TLink  The link type that the value is derived from.
+  //***************************************************************************
+  template <typename TLink>
+  class intrusive_queue_base
+  {
+  public:
+
+    // Node typedef.
+    typedef TLink link_type;
+
+    //*************************************************************************
+    /// Adds a value to the queue.
+    ///\param value The value to push to the queue.
+    //*************************************************************************
+    void push(link_type& value)
+    {
+      value.clear();
+
+      if (p_back != std::nullptr)
+      {
+        etl::link(p_back, value);
+      }
+      else
+      {
+        p_front = &value;
+      }
+
+      p_back = &value;
+
+      ++current_size;
+    }
+
+    //*************************************************************************
+    /// Removes the oldest item from the queue.
+    /// Undefined behaviour if the queue is already empty.
+    //*************************************************************************
+    void pop()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(intrusive_queue_empty));
+#endif
+      link_type* p_next = p_front->etl_next;
+
+      p_front = p_next;
+
+      // Now empty?
+      if (p_front == std::nullptr)
+      {
+        p_back = std::nullptr;
+      }
+
+      --current_size;
+    }
+
+    //*************************************************************************
+    /// Removes the oldest item from the queue and pushes it to the destination.
+    /// Undefined behaviour if the queue is already empty.
+    /// NOTE: The destination must be an intrusize container that supports a push(TLink) member function.
+    //*************************************************************************
+    template <typename TContainer>
+    void pop_into(TContainer& destination)
+    {
+      link_type* p_link = p_front;
+      pop();
+      destination.push(*p_link);
+    }
+
+    //*************************************************************************
+    /// Clears the queue to the empty state.
+    //*************************************************************************
+    void clear()
+    {
+      while (!empty())
+      {
+        pop();
+      }
+
+      current_size = 0;
+    }
+
+    //*************************************************************************
+    /// Checks if the queue is in the empty state.
+    //*************************************************************************
+    bool empty() const
+    {
+      return current_size == 0;
+    }
+
+    //*************************************************************************
+    /// Returns the number of elements.
+    //*************************************************************************
+    size_t size() const
+    {
+      return current_size;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor
+    //*************************************************************************
+    intrusive_queue_base()
+      : p_front(std::nullptr),
+        p_back(std::nullptr),
+        current_size(0)
+    {
+    }
+
+    link_type* p_front; ///< The current front of the queue.
+    link_type* p_back;  ///< The current back of the queue.
+
+    size_t current_size; ///< Counts the number of elements in the list.
+  };
+
+  //***************************************************************************
+  ///\ingroup queue
+  /// An intrusive queue. Stores elements derived from any type that supports an 'etl_next' pointer member.
+  /// \warning This queue cannot be used for concurrent access from multiple threads.
+  /// \tparam TValue The type of value that the queue holds.
+  /// \tparam TLink  The link type that the value is derived from.
+  //***************************************************************************
+  template <typename TValue, typename TLink>
+  class intrusive_queue : public etl::intrusive_queue_base<TLink>
+  {
+  public:
+
+    // Node typedef.
+    typedef typename etl::intrusive_queue_base<TLink> link_type;
+
+    // STL style typedefs.
+    typedef TValue            value_type;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef size_t            size_type;
+
+    //*************************************************************************
+    /// Constructor
+    //*************************************************************************
+    intrusive_queue()
+      : intrusive_queue_base<TLink>()
+    {
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the value at the front of the queue.
+    /// Undefined behaviour if the queue is empty.
+    /// \return A reference to the value at the front of the queue.
+    //*************************************************************************
+    reference front()
+    {
+      return *static_cast<TValue*>(this->p_front);
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the value at the back of the queue.
+    /// Undefined behaviour if the queue is empty.
+    /// \return A reference to the value at the back of the queue.
+    //*************************************************************************
+    reference back()
+    {
+      return *static_cast<TValue*>(this->p_back);
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the value at the front of the queue.
+    /// Undefined behaviour if the queue is empty.
+    /// \return A const reference to the value at the front of the queue.
+    //*************************************************************************
+    const_reference front() const
+    {
+      return *static_cast<const TValue*>(this->p_front);
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the value at the back of the queue.
+    /// Undefined behaviour if the queue is empty.
+    /// \return A reference to the value at the back of the queue.
+    //*************************************************************************
+    const_reference back() const
+    {
+      return *static_cast<const TValue*>(this->p_back);
+    }
+
+  private:
+
+    // Disable copy construction and assignment.
+    intrusive_queue(const intrusive_queue&);
+    intrusive_queue& operator = (const intrusive_queue& rhs);
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/intrusive_stack.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,257 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_INTRUSIVE_STACK__
+#define __ETL_INTRUSIVE_STACK__
+
+#include <stddef.h>
+
+#include "platform.h"
+#include "type_traits.h"
+#include "error_handler.h"
+#include "intrusive_links.h"
+
+#define ETL_FILE "28"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception base for intrusive stack
+  ///\ingroup intrusive_stack
+  //***************************************************************************
+  class intrusive_stack_exception : public etl::exception
+  {
+  public:
+
+    intrusive_stack_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// intrusive_stack empty exception.
+  ///\ingroup intrusive_stack
+  //***************************************************************************
+  class intrusive_stack_empty : public intrusive_stack_exception
+  {
+  public:
+
+    intrusive_stack_empty(string_type file_name_, numeric_type line_number_)
+      : intrusive_stack_exception(ETL_ERROR_TEXT("intrusive_stack:empty", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup stack
+  /// Base for intrusive stack. Stores elements derived any type that supports an 'etl_next' pointer member.
+  /// \tparam TLink  The link type that the value is derived from.
+  //***************************************************************************
+  template <typename TLink>
+  class intrusive_stack_base
+  {
+  public:
+
+    // Node typedef.
+    typedef TLink  link_type;
+
+    //*************************************************************************
+    /// Adds a value to the stack.
+    ///\param value The value to push to the stack.
+    //*************************************************************************
+    void push(link_type& value)
+    {
+      value.clear();
+
+      if (p_top != std::nullptr)
+      {
+        etl::link(value, p_top);
+      }
+
+      p_top = &value;
+
+      ++current_size;
+    }
+
+    //*************************************************************************
+    /// Removes the oldest item from the top of the stack.
+    /// Undefined behaviour if the stack is already empty.
+    //*************************************************************************
+    void pop()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(intrusive_stack_empty));
+#endif
+      link_type* p_next = p_top->etl_next;
+      p_top = p_next;
+      --current_size;
+    }
+
+    //*************************************************************************
+    /// Removes the oldest item from the queue and pushes it to the destination.
+    /// Undefined behaviour if the queue is already empty.
+    /// NOTE: The destination must be an intrusize container that supports a push(TLink) member function.
+    //*************************************************************************
+    template <typename TContainer>
+    void pop_into(TContainer& destination)
+    {
+      link_type* p_link = p_top;
+      pop();
+      destination.push(*p_link);
+    }
+
+    //*************************************************************************
+    /// Reverses the stack order.
+    //*************************************************************************
+    void reverse()
+    {
+      link_type* previous = std::nullptr;
+      link_type* current = p_top;
+      link_type* next;
+
+      while (current != std::nullptr)
+      {
+        next = current->etl_next;
+        current->etl_next = previous;
+        previous = current;
+        current = next;
+      }
+
+      p_top = previous;
+    }
+
+    //*************************************************************************
+    /// Clears the stack to the empty state.
+    //*************************************************************************
+    void clear()
+    {
+      while (!empty())
+      {
+        pop();
+      }
+
+      current_size = 0;
+    }
+
+    //*************************************************************************
+    /// Checks if the stack is in the empty state.
+    //*************************************************************************
+    bool empty() const
+    {
+      return current_size == 0;
+    }
+
+    //*************************************************************************
+    /// Returns the number of elements.
+    //*************************************************************************
+    size_t size() const
+    {
+      return current_size;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor
+    //*************************************************************************
+    intrusive_stack_base()
+      : p_top(std::nullptr),
+        current_size(0)
+    {
+    }
+
+    link_type* p_top; ///< The current top of the stack.
+
+    size_t current_size; ///< Counts the number of elements in the list.
+  };
+
+  //***************************************************************************
+  ///\ingroup stack
+  /// An intrusive stack. Stores elements derived from any type that supports an 'etl_next' pointer member.
+  /// \warning This stack cannot be used for concurrent access from multiple threads.
+  /// \tparam TValue The type of value that the stack holds.
+  /// \tparam TLink  The link type that the value is derived from.
+  //***************************************************************************
+  template <typename TValue, typename TLink>
+  class intrusive_stack : public etl::intrusive_stack_base<TLink>
+  {
+  public:
+
+    // Node typedef.
+    typedef typename etl::intrusive_stack_base<TLink>::link_type link_type;
+
+    // STL style typedefs.
+    typedef TValue            value_type;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef size_t            size_type;
+
+    //*************************************************************************
+    /// Constructor
+    //*************************************************************************
+    intrusive_stack()
+    : intrusive_stack_base<TLink>()
+    {
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the value at the top of the stack.
+    /// Undefined behaviour if the stack is empty.
+    /// \return A reference to the value at the top of the stack.
+    //*************************************************************************
+    reference top()
+    {
+      return *static_cast<TValue*>(this->p_top);
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the value at the top of the stack.<br>
+    /// \return A const reference to the value at the top of the stack.
+    //*************************************************************************
+    const_reference top() const
+    {
+      return *static_cast<const TValue*>(this->p_top);
+    }
+
+  private:
+
+    // Disable copy construction and assignment.
+    intrusive_stack(const intrusive_stack&);
+    intrusive_stack& operator = (const intrusive_stack& rhs);
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/io_port.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,808 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_IO_PORT__
+#define __ETL_IO_PORT__
+
+///\defgroup io_port io port
+/// IO port access
+///\ingroup utilities
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "nullptr.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Read write port.
+  //***************************************************************************
+  template <typename T, uintptr_t ADDRESS = 0>
+  class io_port_rw : public std::iterator<std::forward_iterator_tag, T>
+  {
+  public:
+
+    typedef volatile T*       pointer;
+    typedef volatile const T* const_pointer;
+    typedef volatile T&       reference;
+    typedef volatile const T& const_reference;
+  
+    /// Read.
+    operator T() const
+    {
+      return *reinterpret_cast<const_pointer>(ADDRESS);
+    }
+
+    /// Read.
+    T read() const
+    {
+      return *reinterpret_cast<const_pointer>(ADDRESS);
+    }
+
+    /// Write.
+    void write(T value_)
+    {
+      *reinterpret_cast<pointer>(ADDRESS) = value_;
+    }
+
+    /// Write.
+    io_port_rw& operator =(T value_)
+    {
+      *reinterpret_cast<pointer>(ADDRESS) = value_;
+      return *this;
+    }
+
+    /// Read / Write
+    reference operator *()
+    {
+      return *reinterpret_cast<pointer>(ADDRESS);
+    }
+
+    /// Read
+    const_reference operator *() const
+    {
+      return *reinterpret_cast<const_pointer>(ADDRESS);
+    }
+
+    /// Increment
+    io_port_rw& operator ++()
+    {
+      return *this;
+    }
+
+    /// Increment
+    io_port_rw operator ++(int)
+    {
+      return *this;
+    }
+    
+    /// Get the IO port address.
+    pointer get_address()
+    {
+      return reinterpret_cast<pointer>(ADDRESS);
+    }
+
+    /// Get the IO port address.
+    const_pointer get_address() const
+    {
+      return reinterpret_cast<const_pointer>(ADDRESS);
+    }
+
+  private:
+
+    /// Disabled.
+    io_port_rw& operator =(const io_port_rw&);
+  };
+
+  //***************************************************************************
+  /// Read only port.
+  //***************************************************************************
+  template <typename T, uintptr_t ADDRESS = 0>
+  class io_port_ro : public std::iterator<std::input_iterator_tag, T>
+  {
+  public:
+
+    typedef volatile T*       pointer;
+    typedef volatile const T* const_pointer;
+    typedef volatile T&       reference;
+    typedef volatile const T& const_reference;
+
+    /// Read.
+    operator T() const
+    {
+      return *reinterpret_cast<const_pointer>(ADDRESS);
+    }
+
+    /// Read.
+    T read() const
+    {
+      return *reinterpret_cast<const_pointer>(ADDRESS);
+    }
+
+    /// Read
+    const_reference operator *() const
+    {
+      return *reinterpret_cast<const_pointer>(ADDRESS);
+    }
+
+    /// Increment
+    io_port_ro& operator ++()
+    {
+      return *this;
+    }
+
+    /// Increment
+    io_port_ro operator ++(int)
+    {
+      return *this;
+    }
+
+    /// Get the IO port address.
+    pointer get_address()
+    {
+      return reinterpret_cast<pointer>(ADDRESS);
+    }
+
+    /// Get the IO port address.
+    const_pointer get_address() const
+    {
+      return reinterpret_cast<const_pointer>(ADDRESS);
+    }
+
+  private:
+
+    /// Write disabled.
+    void operator =(T value);
+
+    /// Disabled.
+    io_port_ro& operator =(const io_port_ro&);
+  };
+
+  //***************************************************************************
+  /// Write only port.
+  //***************************************************************************
+  template <typename T, uintptr_t ADDRESS = 0>
+  class io_port_wo : public std::iterator<std::output_iterator_tag, T>
+  {
+  public:
+
+    typedef volatile T*       pointer;
+    typedef volatile const T* const_pointer;
+    typedef volatile T&       reference;
+    typedef volatile const T& const_reference;
+
+    /// Write.
+    void operator =(T value)
+    {
+      *reinterpret_cast<pointer>(ADDRESS) = value;
+    }
+
+    /// Write.
+    void write(T value_)
+    {
+      *reinterpret_cast<pointer>(ADDRESS) = value_;
+    }
+
+    /// Write
+    io_port_wo& operator *()
+    {
+      return *this;
+    }
+
+    /// Increment
+    io_port_wo& operator ++()
+    {
+      return *this;
+    }
+
+    /// Increment
+    io_port_wo operator ++(int)
+    {
+      return *this;
+    }
+
+    /// Get the IO port address.
+    pointer get_address()
+    {
+      return reinterpret_cast<pointer>(ADDRESS);
+    }
+
+    /// Get the IO port address.
+    const_pointer get_address() const
+    {
+      return reinterpret_cast<const_pointer>(ADDRESS);
+    }
+
+  private:
+
+    /// Read disabled.
+    operator T() const;
+
+    /// Disabled.
+    io_port_wo& operator =(const io_port_wo&);
+  };
+
+  //***************************************************************************
+  /// Write only port with shadow register.
+  //***************************************************************************
+  template <typename T, uintptr_t ADDRESS = 0>
+  class io_port_wos : public std::iterator<std::forward_iterator_tag, T>
+  {
+  public:
+
+    typedef volatile T*       pointer;
+    typedef volatile const T* const_pointer;
+    typedef volatile T&       reference;
+    typedef volatile const T& const_reference;
+
+    /// Read.
+    operator T() const
+    {
+      return shadow_value;
+    }
+
+    /// Read.
+    T read() const
+    {
+      return shadow_value;
+    }
+
+    /// Write.
+    void write(T value_)
+    {
+      shadow_value = value_;
+      *reinterpret_cast<pointer>(ADDRESS) = shadow_value;
+    }
+
+    /// Write.
+    io_port_wos& operator =(T value_)
+    {
+      shadow_value = value_;
+      *reinterpret_cast<pointer>(ADDRESS) = shadow_value;
+      return *this;
+    }
+
+    /// Read / Write
+    io_port_wos& operator *()
+    {
+      return *this;
+    }
+
+    /// Read
+    const_reference operator *() const
+    {
+      return shadow_value;
+    }
+
+    /// Increment
+    io_port_wos& operator ++()
+    {
+      return *this;
+    }
+
+    /// Increment
+    io_port_wos operator ++(int)
+    {
+      return *this;
+    }
+
+    /// Get the IO port address.
+    pointer get_address()
+    {
+      return reinterpret_cast<pointer>(ADDRESS);
+    }
+
+  private:
+
+    /// Disabled.
+    io_port_wos& operator =(const io_port_wos&);
+
+    T shadow_value;
+  };
+
+  //***************************************************************************
+  /// Read write port.
+  /// Specialisation for dynamic addresses.
+  //***************************************************************************
+  template <typename T>
+  class io_port_rw<T, 0> : public std::iterator<std::forward_iterator_tag, T>
+  {
+  public:
+
+    typedef volatile T*       pointer;
+    typedef volatile const T* const_pointer;
+    typedef volatile T&       reference;
+    typedef volatile const T& const_reference;
+
+    /// Default constructor.
+    io_port_rw()
+      : address(std::nullptr)
+    {
+    }
+
+    /// Constructor.
+    io_port_rw(void* address_)
+      : address(reinterpret_cast<pointer>(address_))
+    {
+    }
+
+    /// Copy Constructor.
+    io_port_rw(const io_port_rw& other_)
+      : address(reinterpret_cast<pointer>(other_.address))
+    {
+    }
+
+    /// Assignment.
+    io_port_rw& operator =(const io_port_rw& other_)
+    {
+      address = other_.address;
+      return *this;
+    }
+
+    /// Set the IO port address.
+    void set_address(void* address_)
+    {
+      address = reinterpret_cast<pointer>(address_);
+    }
+
+    /// Get the IO port address.
+    pointer get_address()
+    {
+      return address;
+    }
+
+    /// Get the IO port address.
+    const_pointer get_address() const
+    {
+      return address;
+    }
+
+    /// Read.
+    operator T() const
+    {
+      return *address;
+    }
+
+    /// Read.
+    T read() const
+    {
+      return *address;
+    }
+
+    /// Write.
+    void write(T value_)
+    {
+      *address = value_;
+    }
+
+    /// Write.
+    io_port_rw& operator =(T value_)
+    {
+      *address = value_;
+      return *this;
+    }
+
+    /// Read / Write
+    reference operator *()
+    {
+      return *address;
+    }
+
+    /// Read
+    const_reference operator *() const
+    {
+      return *address;
+    }
+
+    /// Increment
+    io_port_rw& operator ++()
+    {
+      return *this;
+    }
+
+    /// Increment
+    io_port_rw operator ++(int)
+    {
+      return *this;
+    }
+
+  private:
+
+    pointer address;
+  };
+
+  //***************************************************************************
+  /// Read only port.
+  /// Specialisation for dynamic addresses.
+  //***************************************************************************
+  template <typename T>
+  class io_port_ro<T, 0> : public std::iterator<std::input_iterator_tag, T>
+  {
+  public:
+
+    typedef volatile T*       pointer;
+    typedef volatile const T* const_pointer;
+    typedef volatile T&       reference;
+    typedef volatile const T& const_reference;
+
+    /// Default constructor.
+    io_port_ro()
+      : address(std::nullptr)
+    {
+    }
+
+    /// Constructor.
+    io_port_ro(void* address_)
+      : address(reinterpret_cast<pointer>(address_))
+    {
+    }
+
+    /// Copy Constructor.
+    io_port_ro(const io_port_ro& other_)
+      : address(reinterpret_cast<pointer>(other_.address))
+    {
+    }
+
+    /// Assignment.
+    io_port_ro& operator =(const io_port_ro& other_)
+    {
+      address = other_.address;
+      return *this;
+    }
+
+    /// Set the IO port address.
+    void set_address(void* address_)
+    {
+      address = reinterpret_cast<pointer>(address_);
+    }
+
+    /// Get the IO port address.
+    const_pointer get_address() const
+    {
+      return address;
+    }
+
+    /// Read.
+    operator T() const
+    {
+      return *address;
+    }
+
+    /// Read.
+    T read() const
+    {
+      return *address;
+    }
+
+    /// Read
+    const_reference operator *() const
+    {
+      return *address;
+    }
+
+    /// Increment
+    io_port_ro& operator ++()
+    {
+      return *this;
+    }
+
+    /// Increment
+    io_port_ro operator ++(int)
+    {
+      return *this;
+    }
+
+  private:
+
+    /// Write disabled.
+    void operator =(T value);
+
+    pointer address;
+  };
+
+  //***************************************************************************
+  /// Write only port.
+  /// Specialisation for dynamic addresses.
+  //***************************************************************************
+  template <typename T>
+  class io_port_wo<T, 0> : public std::iterator<std::output_iterator_tag, T>
+  {
+  public:
+
+    typedef volatile T*       pointer;
+    typedef volatile const T* const_pointer;
+    typedef volatile T&       reference;
+    typedef volatile const T& const_reference;
+
+    /// Default constructor.
+    io_port_wo()
+      : address(std::nullptr)
+    {
+    }
+
+    /// Constructor.
+    io_port_wo(void* address_)
+      : address(reinterpret_cast<pointer>(address_))
+    {
+    }
+
+    /// Copy Constructor.
+    io_port_wo(const io_port_wo& other_)
+      : address(reinterpret_cast<pointer>(other_.address))
+    {
+    }
+
+    /// Assignment.
+    io_port_wo& operator =(const io_port_wo& other_)
+    {
+      address = other_.address;
+      return *this;
+    }
+
+    /// Set the IO port address.
+    void set_address(void* address_)
+    {
+      address = reinterpret_cast<pointer>(address_);
+    }
+
+    /// Get the IO port address.
+    pointer get_address()
+    {
+      return address;
+    }
+
+    /// Get the IO port address.
+    const_pointer get_address() const
+    {
+      return address;
+    }
+
+    /// Write.
+    void write(T value_)
+    {
+      *address = value_;
+    }
+
+    /// Write.
+    void operator =(T value)
+    {
+      *address = value;
+    }
+
+    /// Write
+    io_port_wo& operator *()
+    {
+      return *this;
+    }
+
+    /// Increment
+    io_port_wo& operator ++()
+    {
+      return *this;
+    }
+
+    /// Write
+    io_port_wo operator ++(int)
+    {
+      return *this;
+    }
+    
+  private:
+
+    /// Read disabled.
+    operator T() const;
+
+    pointer address;
+  };
+
+  //***************************************************************************
+  /// Write only port with shadow register.
+  /// Specialisation for dynamic addresses.
+  //***************************************************************************
+  template <typename T>
+  class io_port_wos<T, 0> : public std::iterator<std::forward_iterator_tag, T>
+  {
+  public:
+
+    typedef volatile T*       pointer;
+    typedef volatile const T* const_pointer;
+    typedef volatile T&       reference;
+    typedef volatile const T& const_reference;
+
+    class iterator : public std::iterator<std::bidirectional_iterator_tag, T>
+    {
+      typedef io_port_wos<T, 0> iop_t;
+
+    public:
+
+      iterator(iop_t& iop)
+        : p_iop(&iop)
+      {
+      }
+
+      iterator(const iterator& other)
+        : p_iop(other.p_iop)
+      {
+      }
+
+      iterator& operator =(const iterator& other)
+      {
+        p_iop = other.p_iop;
+        return *this;
+      }
+
+      iop_t& operator *()
+      {
+        return *p_iop;
+      }
+
+      const iop_t& operator *() const
+      {
+        return *p_iop;
+      }
+
+      iterator& operator ++()
+      {
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        return *this;
+      }
+
+      iterator& operator --()
+      {
+        return *this;
+      }
+
+      iterator operator --(int)
+      {
+        return *this;
+      }
+
+    private:
+
+      iop_t* p_iop;
+    };
+    
+    /// Default constructor.
+    io_port_wos()
+      : address(std::nullptr)
+    {
+    }
+
+    /// Constructor.
+    io_port_wos(void* address_)
+      : address(reinterpret_cast<pointer>(address_))
+    {
+    }
+
+    /// Copy Constructor.
+    io_port_wos(const io_port_wos& other_)
+      : shadow_value(other_.shadow_value),
+        address(reinterpret_cast<pointer>(other_.address))
+    {
+    }
+
+    /// Assignment.
+    io_port_wos& operator =(const io_port_wos& other_)
+    {
+      shadow_value = other_.shadow_value;
+      address      = other_.address;
+      return *this;
+    }
+
+    /// Set the IO port address.
+    void set_address(void* address_)
+    {
+      address = reinterpret_cast<pointer>(address_);
+    }
+
+    /// Get the IO port address.
+    pointer get_address()
+    {
+      return address;
+    }
+
+    /// Get the IO port address.
+    const_pointer get_address() const
+    {
+      return address;
+    }
+
+    /// Get the iterator.
+    iterator get_iterator()
+    {
+      return iterator(*this);
+    }
+
+    /// Read.
+    operator T() const
+    {
+      return shadow_value;
+    }
+
+    /// Read.
+    T read() const
+    {
+      return shadow_value;
+    }
+
+    /// Write.
+    void write(T value_)
+    {
+      shadow_value = value_;
+      *address = shadow_value;
+    }
+
+    /// Write.
+    io_port_wos& operator =(T value_)
+    {
+      shadow_value = value_;
+      *address     = shadow_value;
+      return *this;
+    }
+
+    /// Read / Write
+    io_port_wos&  operator *()
+    {
+      return *this;
+    }
+
+    /// Read
+    const_reference operator *() const
+    {
+      return shadow_value;
+    }
+
+    /// Increment
+    io_port_wos& operator ++()
+    {
+      return *this;
+    }
+
+    /// Increment
+    io_port_wos operator ++(int)
+    {
+      return *this;
+    }
+    
+  private:
+
+    T       shadow_value;
+    pointer address;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/iterator.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,117 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_ITERATOR__
+#define __ETL_ITERATOR__
+
+#include <iterator>
+
+#include "platform.h"
+#include "type_traits.h"
+
+///\defgroup iterator iterator
+///\ingroup utilities
+
+namespace etl
+{
+  template <typename T>
+  struct is_input_iterator
+  {
+    static const bool value = etl::is_same<typename std::iterator_traits<T>::iterator_category, std::input_iterator_tag>::value;
+  };
+
+  template <typename T>
+  struct is_output_iterator
+  {
+    static const bool value = etl::is_same<typename std::iterator_traits<T>::iterator_category, std::output_iterator_tag>::value;
+  };
+
+  template <typename T>
+  struct is_forward_iterator
+  {
+    static const bool value = etl::is_same<typename std::iterator_traits<T>::iterator_category, std::forward_iterator_tag>::value;
+  };
+
+  template <typename T>
+  struct is_bidirectional_iterator
+  {
+    static const bool value = etl::is_same<typename std::iterator_traits<T>::iterator_category, std::bidirectional_iterator_tag>::value;
+  };
+
+  template <typename T>
+  struct is_random_iterator
+  {
+    static const bool value = etl::is_same<typename std::iterator_traits<T>::iterator_category, std::random_access_iterator_tag>::value;
+  };
+
+  template <typename T>
+  struct is_input_iterator_concept
+  {
+    static const bool value = etl::is_input_iterator<T>::value || 
+                              etl::is_forward_iterator<T>::value ||
+                              etl::is_bidirectional_iterator<T>::value ||
+                              etl::is_random_iterator<T>::value;
+  };
+
+  template <typename T>
+  struct is_output_iterator_concept
+  {
+    static const bool value = etl::is_output_iterator<T>::value ||
+                              etl::is_forward_iterator<T>::value ||
+                              etl::is_bidirectional_iterator<T>::value ||
+                              etl::is_random_iterator<T>::value;
+  };
+
+  template <typename T>
+  struct is_forward_iterator_concept
+  {
+    static const bool value = etl::is_forward_iterator<T>::value ||
+                              etl::is_bidirectional_iterator<T>::value ||
+                              etl::is_random_iterator<T>::value;
+  };
+
+  template <typename T>
+  struct is_bidirectional_iterator_concept
+  {
+    static const bool value = etl::is_bidirectional_iterator<T>::value ||
+                              etl::is_random_iterator<T>::value;
+  };
+
+  template <typename T>
+  struct is_random_iterator_concept
+  {
+    static const bool value = etl::is_random_iterator<T>::value;
+  };
+
+}
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jenkins.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,122 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_JENKINS__
+#define __ETL_JENKINS__
+
+#include <stdint.h>
+#include <iterator>
+
+#include "platform.h"
+#include "static_assert.h"
+#include "type_traits.h"
+#include "error_handler.h"
+#include "ihash.h"
+#include "frame_check_sequence.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup jenkins Jenkins 32 hash calculation
+///\ingroup maths
+
+namespace etl
+{
+  //***************************************************************************
+  /// Jenkins policy.
+  /// Calculates 32 bit Jenkins hash.
+  //***************************************************************************
+  struct jenkins_policy
+  {
+    typedef uint32_t value_type;
+
+    inline uint32_t initial()
+    {
+      is_finalised = false;
+
+      return 0;
+    }
+
+    inline uint32_t add(value_type hash, uint8_t value) const
+    {
+      ETL_ASSERT(!is_finalised, ETL_ERROR(hash_finalised));
+
+      hash += value;
+      hash += (hash << 10);
+      hash ^= (hash >> 6);
+
+      return hash;
+    }
+
+    inline uint32_t final(value_type hash)
+    {
+      hash += (hash << 3);
+      hash ^= (hash >> 11);
+      hash += (hash << 15);
+      is_finalised = true;
+
+      return hash;
+    }
+
+    bool is_finalised;
+  };
+
+  //*************************************************************************
+  /// jenkins
+  //*************************************************************************
+  class jenkins : public etl::frame_check_sequence<etl::jenkins_policy>
+  {
+  public:
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    jenkins()
+    {
+      this->reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    jenkins(TIterator begin, const TIterator end)
+    {
+      this->reset();
+      this->add(begin, end);
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/largest.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,229 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+#if 0
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+#endif
+
+//***************************************************************************
+// This file has been auto generated. Do not edit this file.
+//***************************************************************************
+
+//***************************************************************************
+// To generate to header file, run this at the command line.
+// Note: You will need Python and COG installed.
+//
+// python -m cogapp -d -e -olargest.h -DNTypes=<n> largest_generator.h
+// Where <n> is the number of types to support.
+//
+// e.g.
+// To generate handlers for up to 16 types...
+// python -m cogapp -d -e -olargest.h -DNTypes=16 largest_generator.h
+//
+// See generate.bat
+//***************************************************************************
+
+#ifndef __ETL_LARGEST__
+#define __ETL_LARGEST__
+
+///\defgroup largest largest
+///\ingroup utilities
+
+#include "platform.h"
+#include "type_traits.h"
+#include "smallest.h"
+#include "static_assert.h"
+
+namespace etl 
+{
+  //***************************************************************************
+  /// Template to determine the largest type and size.
+  /// Supports up to 16 types.
+  /// Defines 'value_type' which is the type of the largest parameter.
+  /// Defines 'size' which is the size of the largest parameter.
+  ///\ingroup largest
+  //***************************************************************************
+  template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void, 
+            typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, 
+            typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, 
+            typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
+  struct largest_type
+  {
+    // Define 'largest_other' as 'largest_type' with all but the first parameter. 
+    typedef typename largest_type<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::type largest_other;
+
+    // Set 'type' to be the largest of the first parameter and any of the others.
+    // This is recursive.
+    typedef typename etl::conditional<(sizeof(T1) > sizeof(largest_other)), // Boolean
+                                       T1,                                  // TrueType
+                                       largest_other>                       // FalseType
+                                       ::type type;                         // The largest type of the two.
+
+    // The size of the largest type.
+    enum
+    {
+      size = sizeof(type)
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for one template parameter.
+  //***************************************************************************
+  template <typename T1>
+  struct largest_type<T1,   void, void, void, void, void, void, void, 
+                      void, void, void, void, void, void, void, void>
+  {
+    typedef T1 type;
+
+    enum
+    {
+      size = sizeof(type)
+    };
+  };
+
+  //***************************************************************************
+  /// Template to determine the largest alignment.
+  /// Supports up to 16 types.
+  /// Defines <b>value</b> which is the largest alignment of all the parameters.
+  ///\ingroup largest
+  //***************************************************************************
+  template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void, 
+            typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, 
+            typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, 
+            typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
+  struct largest_alignment
+  {
+    // Define 'largest_other' as 'largest_type' with all but the first parameter. 
+    typedef typename largest_alignment<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::type largest_other;
+
+    // Set 'type' to be the largest of the first parameter and any of the others.
+    // This is recursive.
+    typedef typename etl::conditional<(etl::alignment_of<T1>::value > etl::alignment_of<largest_other>::value), // Boolean
+                                       T1,                                                                      // TrueType
+                                       largest_other>                                                           // FalseType
+                                       ::type type;                                                             // The largest type of the two.
+
+    // The largest alignment.
+    enum
+    {
+      value = etl::alignment_of<type>::value
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for one template parameter.
+  //***************************************************************************
+  template <typename T1>
+  struct largest_alignment<T1,   void, void, void, void, void, void, void, 
+                           void, void, void, void, void, void, void, void>
+  {
+    typedef T1 type;
+
+    enum
+    {
+      value = etl::alignment_of<type>::value
+    };
+  };
+
+  //***************************************************************************
+  /// Defines a type that is as larger or larger than the specified type.
+  /// Will return the specified type is there is not a larger type.
+  ///\ingroup largest
+  //***************************************************************************
+  template <typename T>
+  struct larger_int_type
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type");
+
+    typedef typename etl::smallest_int_for_bits<etl::integral_limits<typename etl::make_signed<T>::type>::bits + 1>::type type;
+  };
+
+  //***************************************************************************
+  /// Defines a type that is as larger or larger than the specified type.
+  /// Will return the specified type is there is not a larger type.
+  ///\ingroup largest
+  //***************************************************************************
+  template <typename T>
+  struct larger_uint_type
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type");
+
+    typedef typename etl::smallest_uint_for_bits<etl::integral_limits<typename etl::make_unsigned<T>::type>::bits + 1>::type type;
+  };
+
+  //***************************************************************************
+  /// Defines a type that is as larger or larger than the specified type.
+  /// Will return the specified type is there is not a larger type.
+  /// The returned type will be of the same sign.
+  ///\ingroup largest
+  //***************************************************************************
+  template <typename T, bool IS_SIGNED = etl::is_signed<T>::value>
+  struct larger_type;
+
+  template <typename T>
+  struct larger_type<T, false>
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type");
+
+    typedef typename etl::smallest_uint_for_bits<etl::integral_limits<T>::bits + 1>::type type;
+  };
+
+  template <typename T>
+  struct larger_type<T, true>
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type");
+
+    typedef typename etl::smallest_int_for_bits<etl::integral_limits<T>::bits + 1>::type type;
+  };
+
+  //***************************************************************************
+  /// Template to determine the largest type, size and alignment.
+  /// Supports up to 16 types.
+  /// Defines <b>value</b> which is the largest type, size and alignment of all the parameters.
+  ///\ingroup largest
+  //***************************************************************************
+  template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void, 
+            typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, 
+            typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, 
+            typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
+  struct largest
+  {
+    typedef typename etl::largest_type<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::type type;
+
+    enum
+    {
+      size      = etl::largest_type<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::size,
+      alignment = etl::largest_alignment<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value
+    };
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/largest_generator.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,302 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+/*[[[cog
+import cog
+cog.outl("#if 0")
+]]]*/
+/*[[[end]]]*/
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+/*[[[cog
+import cog
+cog.outl("#endif")
+]]]*/
+/*[[[end]]]*/
+
+/*[[[cog
+import cog
+cog.outl("//***************************************************************************")
+cog.outl("// This file has been auto generated. Do not edit this file.")
+cog.outl("//***************************************************************************")
+]]]*/
+/*[[[end]]]*/
+
+//***************************************************************************
+// To generate to header file, run this at the command line.
+// Note: You will need Python and COG installed.
+//
+// python -m cogapp -d -e -olargest.h -DNTypes=<n> largest_generator.h
+// Where <n> is the number of types to support.
+//
+// e.g.
+// To generate handlers for up to 16 types...
+// python -m cogapp -d -e -olargest.h -DNTypes=16 largest_generator.h
+//
+// See generate.bat
+//***************************************************************************
+
+#ifndef __ETL_LARGEST__
+#define __ETL_LARGEST__
+
+///\defgroup largest largest
+///\ingroup utilities
+
+#include "platform.h"
+#include "type_traits.h"
+#include "smallest.h"
+#include "static_assert.h"
+
+namespace etl 
+{
+  /*[[[cog
+  import cog
+  cog.outl("//***************************************************************************")
+  cog.outl("/// Template to determine the largest type and size.")
+  cog.outl("/// Supports up to %s types." % NTypes)
+  cog.outl("/// Defines 'value_type' which is the type of the largest parameter.")
+  cog.outl("/// Defines 'size' which is the size of the largest parameter.")
+  cog.outl("///\ingroup largest")
+  cog.outl("//***************************************************************************")
+  cog.out("template <typename T1, ")
+  for n in range(2, int(NTypes)):
+      cog.out("typename T%s = void, " % n)
+      if n % 4 == 0:
+          cog.outl("")
+          cog.out("          ")
+  cog.outl("typename T%s = void>" % int(NTypes))
+  cog.outl("struct largest_type")
+  cog.outl("{")
+  cog.outl("  // Define 'largest_other' as 'largest_type' with all but the first parameter. ")
+  cog.out("  typedef typename largest_type<")
+  for n in range(2, int(NTypes)):
+      cog.out("T%s, " % n)
+      if n % 16 == 0:
+          cog.outl("")
+          cog.out("                                ")
+  cog.outl("T%s>::type largest_other;" % int(NTypes))
+  cog.outl("")
+  cog.outl("  // Set 'type' to be the largest of the first parameter and any of the others.")
+  cog.outl("  // This is recursive.")
+  cog.outl("  typedef typename etl::conditional<(sizeof(T1) > sizeof(largest_other)), // Boolean")
+  cog.outl("                                     T1,                                  // TrueType")
+  cog.outl("                                     largest_other>                       // FalseType")
+  cog.outl("                                     ::type type;                         // The largest type of the two.")
+  cog.outl("")
+  cog.outl("  // The size of the largest type.")
+  cog.outl("  enum")
+  cog.outl("  {")
+  cog.outl("    size = sizeof(type)")
+  cog.outl("  };")
+  cog.outl("};")
+  cog.outl("")
+  cog.outl("//***************************************************************************")
+  cog.outl("// Specialisation for one template parameter.")
+  cog.outl("//***************************************************************************")
+  cog.outl("template <typename T1>")
+  cog.out("struct largest_type<T1,   ")
+  for n in range(2, int(NTypes)):
+      cog.out("void, ")
+      if n % 8 == 0:
+          cog.outl("")
+          cog.out("                    ")
+  cog.outl("void>")
+  cog.outl("{")
+  cog.outl("  typedef T1 type;")
+  cog.outl("")
+  cog.outl("  enum")
+  cog.outl("  {")
+  cog.outl("    size = sizeof(type)")
+  cog.outl("  };")
+  cog.outl("};")
+  ]]]*/
+  /*[[[end]]]*/
+
+  /*[[[cog
+  import cog
+  cog.outl("//***************************************************************************")
+  cog.outl("/// Template to determine the largest alignment.")
+  cog.outl("/// Supports up to %s types." % int(NTypes))
+  cog.outl("/// Defines <b>value</b> which is the largest alignment of all the parameters.")
+  cog.outl("///\ingroup largest")
+  cog.outl("//***************************************************************************")
+  cog.out("template <typename T1, ")
+  for n in range(2, int(NTypes)):
+      cog.out("typename T%s = void, " % n)
+      if n % 4 == 0:
+          cog.outl("")
+          cog.out("          ")
+  cog.outl("typename T%s = void>" % int(NTypes))
+  cog.outl("struct largest_alignment")
+  cog.outl("{")
+  cog.outl("  // Define 'largest_other' as 'largest_type' with all but the first parameter. ")
+  cog.out("  typedef typename largest_alignment<")
+  for n in range(2, int(NTypes)):
+      cog.out("T%s, " % n)
+      if n % 16 == 0:
+          cog.outl("")
+          cog.out("                                ")
+  cog.outl("T%s>::type largest_other;" % int(NTypes))
+  cog.outl("")
+  cog.outl("  // Set 'type' to be the largest of the first parameter and any of the others.")
+  cog.outl("  // This is recursive.")
+  cog.outl("  typedef typename etl::conditional<(etl::alignment_of<T1>::value > etl::alignment_of<largest_other>::value), // Boolean")
+  cog.outl("                                     T1,                                                                      // TrueType")
+  cog.outl("                                     largest_other>                                                           // FalseType")
+  cog.outl("                                     ::type type;                                                             // The largest type of the two.")
+  cog.outl("")
+  cog.outl("  // The largest alignment.")
+  cog.outl("  enum")
+  cog.outl("  {")
+  cog.outl("    value = etl::alignment_of<type>::value")
+  cog.outl("  };")
+  cog.outl("};")
+  cog.outl("")
+  cog.outl("//***************************************************************************")
+  cog.outl("// Specialisation for one template parameter.")
+  cog.outl("//***************************************************************************")
+  cog.outl("template <typename T1>")
+  cog.out("struct largest_alignment<T1,   ")
+  for n in range(2, int(NTypes)):
+      cog.out("void, ")
+      if n % 8 == 0:
+          cog.outl("")
+          cog.out("                         ")
+  cog.outl("void>")
+  cog.outl("{")
+  cog.outl("  typedef T1 type;")
+  cog.outl("")
+  cog.outl("  enum")
+  cog.outl("  {")
+  cog.outl("    value = etl::alignment_of<type>::value")
+  cog.outl("  };")
+  cog.outl("};")
+  ]]]*/
+  /*[[[end]]]*/
+
+  //***************************************************************************
+  /// Defines a type that is as larger or larger than the specified type.
+  /// Will return the specified type is there is not a larger type.
+  ///\ingroup largest
+  //***************************************************************************
+  template <typename T>
+  struct larger_int_type
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type");
+
+    typedef typename etl::smallest_int_for_bits<etl::integral_limits<typename etl::make_signed<T>::type>::bits + 1>::type type;
+  };
+
+  //***************************************************************************
+  /// Defines a type that is as larger or larger than the specified type.
+  /// Will return the specified type is there is not a larger type.
+  ///\ingroup largest
+  //***************************************************************************
+  template <typename T>
+  struct larger_uint_type
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type");
+
+    typedef typename etl::smallest_uint_for_bits<etl::integral_limits<typename etl::make_unsigned<T>::type>::bits + 1>::type type;
+  };
+
+  //***************************************************************************
+  /// Defines a type that is as larger or larger than the specified type.
+  /// Will return the specified type is there is not a larger type.
+  /// The returned type will be of the same sign.
+  ///\ingroup largest
+  //***************************************************************************
+  template <typename T, bool IS_SIGNED = etl::is_signed<T>::value>
+  struct larger_type;
+
+  template <typename T>
+  struct larger_type<T, false>
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type");
+
+    typedef typename etl::smallest_uint_for_bits<etl::integral_limits<T>::bits + 1>::type type;
+  };
+
+  template <typename T>
+  struct larger_type<T, true>
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type");
+
+    typedef typename etl::smallest_int_for_bits<etl::integral_limits<T>::bits + 1>::type type;
+  };
+
+  /*[[[cog
+  import cog
+  cog.outl("//***************************************************************************")
+  cog.outl("/// Template to determine the largest type, size and alignment.")
+  cog.outl("/// Supports up to %s types." % NTypes)
+  cog.outl("/// Defines <b>value</b> which is the largest type, size and alignment of all the parameters.")
+  cog.outl("///\ingroup largest")
+  cog.outl("//***************************************************************************")
+  cog.out("template <typename T1, ")
+  for n in range(2, int(NTypes)):
+      cog.out("typename T%s = void, " % n)
+      if n % 4 == 0:
+          cog.outl("")
+          cog.out("          ")
+  cog.outl("typename T%s = void>" % NTypes)
+  cog.outl("struct largest")
+  cog.outl("{")
+  cog.out("  typedef typename etl::largest_type<")
+  for n in range(1, int(NTypes)):
+      cog.out("T%s, " % n)
+      if n % 16 == 0:
+          cog.outl("")
+          cog.out("                                     ")
+  cog.outl("T%s>::type type;" % NTypes)
+  cog.outl("")
+  cog.outl("  enum")
+  cog.outl("  {")
+  cog.out("    size      = etl::largest_type<")
+  for n in range(1, int(NTypes)):
+      cog.out("T%s, " % n)
+      if n % 16 == 0:
+          cog.outl("")
+          cog.out("                                  ")
+  cog.outl("T%s>::size," % NTypes)
+  cog.out("    alignment = etl::largest_alignment<")
+  for n in range(1, int(NTypes)):
+      cog.out("T%s, " % n)
+      if n % 16 == 0:
+          cog.outl("")
+          cog.out("                                       ")
+  cog.outl("T%s>::value" % NTypes)
+  cog.outl("  };")
+  cog.outl("};")
+  ]]]*/
+  /*[[[end]]]*/
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/list.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1736 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_LIST__
+#define __ETL_LIST__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "platform.h"
+#include "container.h"
+#include "pool.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "debug_count.h"
+#include "nullptr.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "algorithm.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#undef ETL_FILE
+#define ETL_FILE "7"
+
+//*****************************************************************************
+///\defgroup list list
+/// A linked list with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the list.
+  ///\ingroup list
+  //***************************************************************************
+  class list_exception : public exception
+  {
+  public:
+
+    list_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Full exception for the list.
+  ///\ingroup list
+  //***************************************************************************
+  class list_full : public list_exception
+  {
+  public:
+
+    list_full(string_type file_name_, numeric_type line_number_)
+      : list_exception(ETL_ERROR_TEXT("list:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Empty exception for the list.
+  ///\ingroup list
+  //***************************************************************************
+  class list_empty : public list_exception
+  {
+  public:
+
+    list_empty(string_type file_name_, numeric_type line_number_)
+      : list_exception(ETL_ERROR_TEXT("list:empty", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the list.
+  ///\ingroup list
+  //***************************************************************************
+  class list_iterator : public list_exception
+  {
+  public:
+
+    list_iterator(string_type file_name_, numeric_type line_number_)
+      : list_exception(ETL_ERROR_TEXT("list:iterator", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Unsorted exception for the list.
+  ///\ingroup list
+  //***************************************************************************
+  class list_unsorted : public list_exception
+  {
+  public:
+
+    list_unsorted(string_type file_name_, numeric_type line_number_)
+      : list_exception(ETL_ERROR_TEXT("list:unsorted", ETL_FILE"D"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for all lists.
+  ///\ingroup list
+  //***************************************************************************
+  class list_base
+  {
+  public:
+
+    typedef size_t size_type; ///< The type used for determining the size of list.
+
+    //*************************************************************************
+    /// The node element in the list.
+    //*************************************************************************
+    struct node_t
+    {
+      //***********************************************************************
+      /// Constructor
+      //***********************************************************************
+      node_t()
+        : previous(std::nullptr),
+          next(std::nullptr)
+      {
+      }
+
+      //***********************************************************************
+      /// Reverses the previous & next pointers.
+      //***********************************************************************
+      inline void reverse()
+      {
+        std::swap(previous, next);
+      }
+
+      node_t* previous;
+      node_t* next;
+    };
+
+    //*************************************************************************
+    /// Reverses the list.
+    //*************************************************************************
+    void reverse()
+    {
+      if (is_trivial_list())
+      {
+        return;
+      }
+
+      node_t* p_node = terminal_node.next;
+
+      while (p_node != &terminal_node)
+      {
+        node_t* p_temp = p_node->previous;
+        p_node->previous = p_node->next;
+        p_node->next = p_temp;
+        p_node = p_node->previous;
+      }
+
+      // Terminal node.
+      node_t* p_temp = p_node->previous;
+      p_node->previous = p_node->next;
+      p_node->next = p_temp;
+    }
+
+    //*************************************************************************
+    /// Gets the maximum possible size of the list.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return MAX_SIZE;
+    }
+
+    //*************************************************************************
+    /// Gets the size of the list.
+    //*************************************************************************
+    size_type size() const
+    {
+      return p_node_pool->size();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the list is empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return p_node_pool->empty();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the list is full.
+    //*************************************************************************
+    bool full() const
+    {
+      return p_node_pool->size() == MAX_SIZE;
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return max_size() - size();
+    }
+
+    //*************************************************************************
+    /// Is the list a trivial length?
+    //*************************************************************************
+    bool is_trivial_list() const
+    {
+      return (size() < 2);
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Get the head node.
+    //*************************************************************************
+    node_t& get_head()
+    {
+      return *terminal_node.next;
+    }
+
+    //*************************************************************************
+    /// Get the head node.
+    //*************************************************************************
+    const node_t& get_head() const
+    {
+      return *terminal_node.next;
+    }
+
+    //*************************************************************************
+    /// Get the tail node.
+    //*************************************************************************
+    node_t& get_tail()
+    {
+      return *terminal_node.previous;
+    }
+
+    //*************************************************************************
+    /// Get the tail node.
+    //*************************************************************************
+    const node_t& get_tail() const
+    {
+      return *terminal_node.previous;
+    }
+
+    //*************************************************************************
+    /// Insert a node before 'position'.
+    //*************************************************************************
+    void insert_node(node_t& position, node_t& node)
+    {
+      // Connect to the list.
+      join(*position.previous, node);
+      join(node, position);
+    }
+
+    //*************************************************************************
+    /// Join two nodes.
+    //*************************************************************************
+    void join(node_t& left, node_t& right)
+    {
+      left.next = &right;
+      right.previous = &left;
+    }
+
+    //*************************************************************************
+    /// The constructor that is called from derived classes.
+    //*************************************************************************
+    list_base(etl::ipool& node_pool_, size_type   max_size_)
+      : p_node_pool(&node_pool_),
+        MAX_SIZE(max_size_)
+
+    {
+    }
+
+    etl::ipool*      p_node_pool;     ///< The pool of data nodes used in the list.
+    node_t           terminal_node;   ///< The node that acts as the list start and end.
+    const size_type  MAX_SIZE;        ///< The maximum size of the list.
+    etl::debug_count construct_count; ///< Internal debugging.
+  };
+
+  //***************************************************************************
+  /// A templated base for all etl::list types.
+  ///\ingroup list
+  //***************************************************************************
+  template <typename T>
+  class ilist : public etl::list_base
+  {
+  public:
+
+    typedef T        value_type;
+    typedef T*       pointer;
+    typedef const T* const_pointer;
+    typedef T&       reference;
+    typedef const T& const_reference;
+    typedef size_t   size_type;
+
+  protected:
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+
+    //*************************************************************************
+    /// The data node element in the list.
+    //*************************************************************************
+    struct data_node_t : public node_t
+    {
+      explicit data_node_t(parameter_t value_)
+        : value(value_)
+      {
+      }
+
+      T value;
+    };
+
+  private:
+
+    //*************************************************************************
+    /// Downcast a node_t* to a data_node_t*
+    //*************************************************************************
+    static data_node_t* data_cast(node_t* p_node)
+    {
+      return reinterpret_cast<data_node_t*>(p_node);
+    }
+
+    //*************************************************************************
+    /// Downcast a node_t& to a data_node_t&
+    //*************************************************************************
+    static data_node_t& data_cast(node_t& node)
+    {
+      return reinterpret_cast<data_node_t&>(node);
+    }
+
+    //*************************************************************************
+    /// Downcast a const node_t* to a const data_node_t*
+    //*************************************************************************
+    static const data_node_t* data_cast(const node_t* p_node)
+    {
+      return reinterpret_cast<const data_node_t*>(p_node);
+    }
+
+    //*************************************************************************
+    /// Downcast a const node_t& to a const data_node_t&
+    //*************************************************************************
+    static const data_node_t& data_cast(const node_t& node)
+    {
+      return reinterpret_cast<const data_node_t&>(node);
+    }
+
+  public:
+
+    //*************************************************************************
+    /// iterator.
+    //*************************************************************************
+    class iterator : public std::iterator<std::bidirectional_iterator_tag, T>
+    {
+    public:
+
+      friend class ilist;
+
+      iterator()
+        : p_node(nullptr)
+      {
+      }
+
+      iterator(node_t& node)
+        : p_node(&node)
+      {
+      }
+
+      iterator(const iterator& other)
+        : p_node(other.p_node)
+      {
+      }
+
+      iterator& operator ++()
+      {
+        p_node = p_node->next;
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        p_node = p_node->next;
+        return temp;
+      }
+
+      iterator& operator --()
+      {
+        p_node = p_node->previous;
+        return *this;
+      }
+
+      iterator operator --(int)
+      {
+        iterator temp(*this);
+        p_node = p_node->previous;
+        return temp;
+      }
+
+      iterator operator =(const iterator& other)
+      {
+        p_node = other.p_node;
+        return *this;
+      }
+
+      reference operator *()
+      {
+        return ilist::data_cast(p_node)->value;
+      }
+
+      const_reference operator *() const
+      {
+        return ilist::data_cast(p_node)->value;
+      }
+
+      pointer operator &()
+      {
+        return &(ilist::data_cast(p_node)->value);
+      }
+
+      const_pointer operator &() const
+      {
+        return &(ilist::data_cast(p_node)->value);
+      }
+
+      pointer operator ->()
+      {
+        return &(ilist::data_cast(p_node)->value);
+      }
+
+      const_pointer operator ->() const
+      {
+        return &(ilist::data_cast(p_node)->value);
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.p_node == rhs.p_node;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      node_t* p_node;
+    };
+
+    //*************************************************************************
+    /// const_iterator
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const T>
+    {
+    public:
+
+      friend class ilist;
+
+      const_iterator()
+        : p_node(nullptr)
+      {
+      }
+
+      const_iterator(node_t& node)
+        : p_node(&node)
+      {
+      }
+
+      const_iterator(const node_t& node)
+        : p_node(&node)
+      {
+      }
+
+      const_iterator(const typename ilist::iterator& other)
+        : p_node(other.p_node)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : p_node(other.p_node)
+      {
+      }
+
+      const_iterator& operator ++()
+      {
+        p_node = p_node->next;
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        p_node = p_node->next;
+        return temp;
+      }
+
+      const_iterator& operator --()
+      {
+        p_node = p_node->previous;
+        return *this;
+      }
+
+      const_iterator operator --(int)
+      {
+        const_iterator temp(*this);
+        p_node = p_node->previous;
+        return temp;
+      }
+
+      const_iterator operator =(const const_iterator& other)
+      {
+        p_node = other.p_node;
+        return *this;
+      }
+
+      const_reference operator *() const
+      {
+        return ilist::data_cast(p_node)->value;
+      }
+
+      const_pointer operator &() const
+      {
+        return &(ilist::data_cast(p_node)->value);
+      }
+
+      const_pointer operator ->() const
+      {
+        return &(ilist::data_cast(p_node)->value);
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.p_node == rhs.p_node;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      const node_t* p_node;
+    };
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+    //*************************************************************************
+    /// Gets the beginning of the list.
+    //*************************************************************************
+    iterator begin()
+    {
+      return iterator(get_head());
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the list.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(get_head());
+    }
+
+    //*************************************************************************
+    /// Gets the end of the list.
+    //*************************************************************************
+    iterator end()
+    {
+      return iterator(terminal_node);
+    }
+
+    //*************************************************************************
+    /// Gets the end of the list.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(static_cast<const data_node_t&>(terminal_node));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the list.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(get_head());
+    }
+
+    //*************************************************************************
+    /// Gets the end of the list.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(static_cast<const data_node_t&>(terminal_node));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(terminal_node);
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(static_cast<const data_node_t&>(terminal_node));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(get_head());
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(static_cast<const data_node_t&>(terminal_node));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(get_head());
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the first element.
+    //*************************************************************************
+    reference front()
+    {
+      return data_cast(get_head()).value;
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the first element.
+    //*************************************************************************
+    const_reference front() const
+    {
+      return data_cast(get_head()).value;
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the last element.
+    //*************************************************************************
+    reference back()
+    {
+      return data_cast(get_tail()).value;
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the last element.
+    //*************************************************************************
+    const_reference back() const
+    {
+      return data_cast(get_tail()).value;
+    }
+
+    //*************************************************************************
+    /// Assigns a range of values to the list.
+    /// If asserts or exceptions are enabled throws etl::list_full if the list does not have enough free space.
+    /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined throws list_iterator if the iterators are reversed.
+    //*************************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(d >= 0, ETL_ERROR(list_iterator));
+      ETL_ASSERT(size_t(d) <= MAX_SIZE, ETL_ERROR(list_full));
+#endif
+      initialise();
+
+      // Add all of the elements.
+      while (first != last)
+      {
+        data_node_t& node = allocate_data_node(*first);
+        join(get_tail(), node);
+        join(node, terminal_node);
+        ++first;
+      }
+    }
+
+    //*************************************************************************
+    /// Assigns 'n' copies of a value to the list.
+    //*************************************************************************
+    void assign(size_t n, parameter_t value)
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(list_full));
+#endif
+
+      initialise();
+
+      // Add all of the elements.
+      while (size() < n)
+      {
+        data_node_t& node = allocate_data_node(value);
+        join(*terminal_node.previous, node);
+        join(node, terminal_node);
+      }
+    }
+
+    //*************************************************************************
+    /// Adds a node to the front of the list so a new value can be assigned to front().
+    //*************************************************************************
+    void push_front()
+    {
+      push_front(T());
+    }
+
+    //*************************************************************************
+    /// Pushes a value to the front of the list.
+    //*************************************************************************
+    void push_front(parameter_t value)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+      insert_node(get_head(), allocate_data_node(value));
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the front of the list..
+    //*************************************************************************
+    template <typename T1>
+    void emplace_front(const T1& value1)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1);
+      ++construct_count;
+      insert_node(get_head(), *p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the front of the list..
+    //*************************************************************************
+    template <typename T1, typename T2>
+    void emplace_front(const T1& value1, const T2& value2)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2);
+      ++construct_count;
+      insert_node(get_head(), *p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the front of the list..
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3>
+    void emplace_front(const T1& value1, const T2& value2, const T3& value3)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2, value3);
+      ++construct_count;
+      insert_node(get_head(), *p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the front of the list..
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    void emplace_front(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2, value3, value4);
+      ++construct_count;
+      insert_node(get_head(), *p_data_node);
+    }
+
+    //*************************************************************************
+    /// Removes a value from the front of the list.
+    //*************************************************************************
+    void pop_front()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(list_empty));
+#endif
+      node_t& node = get_head();
+      remove_node(node);
+    }
+
+    //*************************************************************************
+    /// Adds a node to the back of the list so a new value can be assigned to back().
+    //*************************************************************************
+    void push_back()
+    {
+      push_back(T());
+    }
+
+    //*************************************************************************
+    /// Pushes a value to the back of the list..
+    //*************************************************************************
+    void push_back(parameter_t value)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+      insert_node(terminal_node, allocate_data_node(value));
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the back of the list..
+    //*************************************************************************
+    template <typename T1>
+    void emplace_back(const T1& value1)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1);
+      ++construct_count;
+      insert_node(terminal_node, *p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the back of the list..
+    //*************************************************************************
+    template <typename T1, typename T2>
+    void emplace_back(const T1& value1, const T2& value2)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2);
+      ++construct_count;
+      insert_node(terminal_node, *p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the back of the list..
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3>
+    void emplace_back(const T1& value1, const T2& value2, const T3& value3)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2, value3);
+      ++construct_count;
+      insert_node(terminal_node, *p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the back of the list..
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    void emplace_back(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+#endif
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2, value3, value4);
+      ++construct_count;
+      insert_node(terminal_node, *p_data_node);
+    }
+
+    //*************************************************************************
+    /// Removes a value from the back of the list.
+    //*************************************************************************
+    void pop_back()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(list_empty));
+#endif
+      node_t& node = get_tail();
+      remove_node(node);
+    }
+
+    //*************************************************************************
+    /// Inserts a value to the list at the specified position.
+    //*************************************************************************
+    iterator insert(iterator position, const value_type& value)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+
+      data_node_t& data_node = allocate_data_node(value);
+      insert_node(*position.p_node, data_node);
+
+      return iterator(data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the list at the specified position.
+    //*************************************************************************
+    template <typename T1>
+    iterator emplace(iterator position, const T1& value1)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1);
+      ++construct_count;
+      insert_node(*position.p_node, *p_data_node);
+
+      return iterator(*p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the list at the specified position.
+    //*************************************************************************
+    template <typename T1, typename T2>
+    iterator emplace(iterator position, const T1& value1, const T2& value2)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2);
+      ++construct_count;
+      insert_node(*position.p_node, *p_data_node);
+
+      return iterator(*p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the list at the specified position.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3>
+    iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2, value3);
+      ++construct_count;
+      insert_node(*position.p_node, *p_data_node);
+
+      return iterator(*p_data_node);
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the list at the specified position.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(list_full));
+
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value1, value2, value3, value4);
+      ++construct_count;
+      insert_node(*position.p_node, *p_data_node);
+
+      return iterator(*p_data_node);
+    }
+
+    //*************************************************************************
+    /// Inserts 'n' copies of a value to the list at the specified position.
+    //*************************************************************************
+    void insert(iterator position, size_t n, const value_type& value)
+    {
+      for (size_t i = 0; i < n; ++i)
+      {
+        ETL_ASSERT(!full(), ETL_ERROR(list_full));
+
+        // Set up the next free node and insert.
+        insert_node(*position.p_node, allocate_data_node(value));
+      }
+    }
+
+    //*************************************************************************
+    /// Inserts a range of values to the list at the specified position.
+    //*************************************************************************
+    template <typename TIterator>
+    void insert(iterator position, TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        ETL_ASSERT(!full(), ETL_ERROR(list_full));
+
+        // Set up the next free node and insert.
+        insert_node(*position.p_node, allocate_data_node(*first++));
+      }
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    iterator erase(iterator position)
+    {
+      ++position;
+      remove_node(*position.p_node->previous);
+      return position;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    //*************************************************************************
+    iterator erase(iterator first, iterator last)
+    {
+      node_t* p_first = first.p_node;
+      node_t* p_last = last.p_node;
+      node_t* p_next;
+
+      // Join the ends.
+      join(*(p_first->previous), *p_last);
+
+      // Erase the ones in between.
+      while (p_first != p_last)
+      {
+        p_next = p_first->next;                                // Remember the next node.
+        destroy_data_node(static_cast<data_node_t&>(*p_first)); // Destroy the current node.
+        p_first = p_next;                                       // Move to the next node.
+      }
+
+      return last;
+    }
+
+    //*************************************************************************
+    /// Resizes the list.
+    //*************************************************************************
+    void resize(size_t n)
+    {
+      resize(n, T());
+    }
+
+    //*************************************************************************
+    /// Resizes the list.
+    //*************************************************************************
+    void resize(size_t n, parameter_t value)
+    {
+      ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(list_full));
+
+      // Smaller?
+      if (n < size())
+      {
+        iterator i_start = end();
+        std::advance(i_start, -difference_type(size() - n));
+        erase(i_start, end());
+      }
+      // Larger?
+      else if (n > size())
+      {
+        insert(end(), n - size(), value);
+      }
+    }
+
+    //*************************************************************************
+    /// Clears the list.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*************************************************************************
+    // Removes the values specified.
+    //*************************************************************************
+    void remove(const value_type& value)
+    {
+      iterator iValue = begin();
+
+      while (iValue != end())
+      {
+        if (value == *iValue)
+        {
+          iValue = erase(iValue);
+        }
+        else
+        {
+          ++iValue;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Removes according to a predicate.
+    //*************************************************************************
+    template <typename TPredicate>
+    void remove_if(TPredicate predicate)
+    {
+      iterator iValue = begin();
+
+      while (iValue != end())
+      {
+        if (predicate(*iValue))
+        {
+          iValue = erase(iValue);
+        }
+        else
+        {
+          ++iValue;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Removes all but the first element from every consecutive group of equal
+    /// elements in the container.
+    //*************************************************************************
+    void unique()
+    {
+      unique(std::equal_to<T>());
+    }
+
+    //*************************************************************************
+    /// Removes all but the first element from every consecutive group of equal
+    /// elements in the container.
+    //*************************************************************************
+    template <typename TIsEqual>
+    void unique(TIsEqual isEqual)
+    {
+      if (empty())
+      {
+        return;
+      }
+
+      iterator i_item = begin();
+      ++i_item;
+      iterator i_previous = begin();
+
+      while (i_item != end())
+      {
+        if (isEqual(*i_previous, *i_item))
+        {
+          i_item = erase(i_item);
+        }
+        else
+        {
+          i_previous = i_item;
+          ++i_item;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Splices from another list to this.
+    //*************************************************************************
+    void splice(iterator to, ilist& other)
+    {
+      if (&other != this)
+      {
+        insert(to, other.begin(), other.end());
+        other.erase(other.begin(), other.end());
+      }
+    }
+
+    //*************************************************************************
+    /// Splices an element from another list to this.
+    //*************************************************************************
+    void splice(iterator to, ilist& other, iterator from)
+    {
+      if (&other == this)
+      {
+        // Internal move.
+        move(to, from);
+      }
+      else
+      {
+        // From another list.
+        insert(to, *from);
+        other.erase(from);
+      }
+    }
+
+    //*************************************************************************
+    /// Splices a range of elements from another list to this.
+    //*************************************************************************
+    void splice(iterator to, ilist& other, iterator first, iterator last)
+    {
+      if (&other == this)
+      {
+        // Internal move.
+        move(to, first, last);
+      }
+      else
+      {
+        // From another list.
+        insert(to, first, last);
+        other.erase(first, last);
+      }
+    }
+
+    //*************************************************************************
+    /// Merge another list into this one. Both lists should be sorted.
+    //*************************************************************************
+    void merge(ilist& other)
+    {
+      merge(other, std::less<value_type>());
+    }
+
+    //*************************************************************************
+    /// Merge another list into this one. Both lists should be sorted.
+    //*************************************************************************
+    template <typename TCompare>
+    void merge(ilist& other, TCompare compare)
+    {
+      if (!other.empty())
+      {
+#if defined(ETL_DEBUG)
+        ETL_ASSERT(etl::is_sorted(other.begin(), other.end(), compare), ETL_ERROR(list_unsorted));
+        ETL_ASSERT(etl::is_sorted(begin(), end(), compare), ETL_ERROR(list_unsorted));
+#endif
+
+        ilist::iterator other_begin = other.begin();
+        ilist::iterator other_end = other.end();
+
+        ilist::iterator this_begin = begin();
+        ilist::iterator this_end = end();
+
+        while ((this_begin != this_end) && (other_begin != other_end))
+        {
+          // Find the place to insert.
+          while ((this_begin != this_end) && !(compare(*other_begin, *this_begin)))
+          {
+            ++this_begin;
+          }
+
+          // Insert.
+          if (this_begin != this_end)
+          {
+            while ((other_begin != other_end) && (compare(*other_begin, *this_begin)))
+            {
+              insert(this_begin, *other_begin);
+              ++other_begin;
+            }
+          }
+        }
+
+        // Any left over?
+        if ((this_begin == this_end) && (other_begin != other_end))
+        {
+          insert(this_end, other_begin, other_end);
+        }
+
+        other.clear();
+      }
+    }
+
+    //*************************************************************************
+    /// Sort using in-place merge sort algorithm.
+    /// Uses 'less-than operator as the predicate.
+    //*************************************************************************
+    void sort()
+    {
+      sort(std::less<T>());
+    }
+
+    //*************************************************************************
+    /// Sort using in-place merge sort algorithm.
+    /// Uses a supplied predicate function or functor.
+    /// This is not my algorithm. I got it off the web somewhere.
+    //*************************************************************************
+    template <typename TCompare>
+    void sort(TCompare compare)
+    {
+      iterator i_left;
+      iterator i_right;
+      iterator i_node;
+      iterator i_head;
+      iterator i_tail;
+      int   list_size = 1;
+      int   number_of_merges;
+      int   left_size;
+      int   right_size;
+
+      if (is_trivial_list())
+      {
+        return;
+      }
+
+      while (true)
+      {
+        i_left = begin();
+        i_head = end();
+        i_tail = end();
+
+        number_of_merges = 0;  // Count the number of merges we do in this pass.
+
+        while (i_left != end())
+        {
+          ++number_of_merges;  // There exists a merge to be done.
+          i_right = i_left;
+          left_size = 0;
+
+          // Step 'list_size' places along from left
+          for (int i = 0; i < list_size; ++i)
+          {
+            ++left_size;
+            ++i_right;
+
+            if (i_right == end())
+            {
+              break;
+            }
+          }
+
+          // If right hasn't fallen off end, we have two lists to merge.
+          right_size = list_size;
+
+          // Now we have two lists. Merge them.
+          while (left_size > 0 || (right_size > 0 && i_right != end()))
+          {
+            // Decide whether the next node of merge comes from left or right.
+            if (left_size == 0)
+            {
+              // Left is empty. The node must come from right.
+              i_node = i_right++;
+              --right_size;
+            }
+            else if (right_size == 0 || i_right == end())
+            {
+              // Right is empty. The node must come from left.
+              i_node = i_left++;
+              --left_size;
+            }
+            else if (!compare(*i_right, *i_left))
+            {
+              // First node of left is lower or same. The node must come from left.
+              i_node = i_left++;
+              --left_size;
+            }
+            else
+            {
+              // First node of right is lower. The node must come from right.
+              i_node = i_right;
+              ++i_right;
+              --right_size;
+            }
+
+            // Add the next node to the merged head.
+            if (i_head == end())
+            {
+              join(*i_head.p_node, *i_node.p_node);
+              i_head = i_node;
+              i_tail = i_node;
+            }
+            else
+            {
+              join(*i_tail.p_node, *i_node.p_node);
+              i_tail = i_node;
+            }
+
+            join(*i_tail.p_node, terminal_node);
+          }
+
+          // Now left has stepped `list_size' places along, and right has too.
+          i_left = i_right;
+        }
+
+        // If we have done only one merge, we're finished.
+        if (number_of_merges <= 1)   // Allow for number_of_merges == 0, the empty head case
+        {
+          return;
+        }
+
+        // Otherwise repeat, merging lists twice the size
+        list_size *= 2;
+      }
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    ilist& operator = (const ilist& rhs)
+    {
+      if (&rhs != this)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    ilist(etl::ipool& node_pool, size_t max_size_)
+      : list_base(node_pool, max_size_)
+    {
+    }
+
+    //*************************************************************************
+    /// Initialise the list.
+    //*************************************************************************
+    void initialise()
+    {
+      if (!empty())
+      {
+        node_t* p_first = terminal_node.next;
+        node_t* p_last = &terminal_node;
+
+        while (p_first != p_last)
+        {
+          destroy_data_node(static_cast<data_node_t&>(*p_first)); // Destroy the current node.
+          p_first = p_first->next;                                // Move to the next node.
+        }
+      }
+
+      join(terminal_node, terminal_node);
+    }
+
+  private:
+
+    //*************************************************************************
+    /// Moves an element from one position to another within the list.
+    /// Moves the element at position 'from' to the position before 'to'.
+    //*************************************************************************
+    void move(iterator to, iterator from)
+    {
+      if (from == to)
+      {
+        return; // Can't more to before yourself!
+      }
+
+      node_t& from_node = *from.p_node;
+      node_t& to_node = *to.p_node;
+
+      // Disconnect the node from the list.
+      join(*from_node.previous, *from_node.next);
+
+      // Attach it to the new position.
+      join(*to_node.previous, from_node);
+      join(from_node, to_node);
+    }
+
+    //*************************************************************************
+    /// Moves a range from one position to another within the list.
+    /// Moves a range at position 'first'/'last' to the position before 'to'.
+    //*************************************************************************
+    void move(iterator to, iterator first, iterator last)
+    {
+      if ((first == to) || (last == to))
+      {
+        return; // Can't more to before yourself!
+      }
+
+#if defined(ETL_DEBUG)
+      // Check that we are not doing an illegal move!
+      for (const_iterator item = first; item != last; ++item)
+      {
+        ETL_ASSERT(item != to, ETL_ERROR(list_iterator));
+      }
+#endif
+
+      node_t& first_node = *first.p_node;
+      node_t& last_node = *last.p_node;
+      node_t& to_node = *to.p_node;
+      node_t& final_node = *last_node.previous;
+
+      // Disconnect the range from the list.
+      join(*first_node.previous, last_node);
+
+      // Attach it to the new position.
+      join(*to_node.previous, first_node);
+      join(final_node, to_node);
+    }
+
+    //*************************************************************************
+    /// Remove a node.
+    //*************************************************************************
+    void remove_node(node_t& node)
+    {
+      // Disconnect the node from the list.
+      join(*node.previous, *node.next);
+
+      // Destroy the pool object.
+      destroy_data_node(static_cast<data_node_t&>(node));
+    }
+
+    //*************************************************************************
+    /// Allocate a data_node_t.
+    //*************************************************************************
+    data_node_t& allocate_data_node(parameter_t value)
+    {
+      data_node_t* p_data_node = p_node_pool->allocate<data_node_t>();
+      ::new (&(p_data_node->value)) T(value);
+      ++construct_count;
+
+      return *p_data_node;
+    }
+
+    //*************************************************************************
+    /// Destroy a data_node_t.
+    //*************************************************************************
+    void destroy_data_node(data_node_t& node)
+    {
+      node.value.~T();
+      p_node_pool->release(&node);
+      --construct_count;
+    }
+
+    // Disable copy construction.
+    ilist(const ilist&);
+  };
+
+  //*************************************************************************
+  /// A templated list implementation that uses a fixed size buffer.
+  ///\note 'merge' and 'splice' and are not supported.
+  //*************************************************************************
+  template <typename T, const size_t MAX_SIZE_>
+  class list : public etl::ilist<T>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+  public:
+
+    typedef T        value_type;
+    typedef T*       pointer;
+    typedef const T* const_pointer;
+    typedef T&       reference;
+    typedef const T& const_reference;
+    typedef size_t   size_type;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    list()
+      : etl::ilist<T>(node_pool, MAX_SIZE)
+    {
+      etl::ilist<T>::initialise();
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~list()
+    {
+      etl::ilist<T>::initialise();
+    }
+
+    //*************************************************************************
+    /// Construct from size.
+    //*************************************************************************
+    explicit list(size_t initial_size)
+      : etl::ilist<T>(node_pool, MAX_SIZE)
+    {
+      etl::ilist<T>::assign(initial_size, T());
+    }
+
+    //*************************************************************************
+    /// Construct from size and value.
+    //*************************************************************************
+    list(size_t initial_size, typename ilist<T>::parameter_t value)
+      : etl::ilist<T>(node_pool, MAX_SIZE)
+    {
+      etl::ilist<T>::assign(initial_size, value);
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    list(const list& other)
+      : etl::ilist<T>(node_pool, MAX_SIZE)
+    {
+      if (this != &other)
+      {
+        etl::ilist<T>::assign(other.cbegin(), other.cend());
+      }
+    }
+
+    //*************************************************************************
+    /// Construct from range.
+    //*************************************************************************
+    template <typename TIterator>
+    list(TIterator first, TIterator last)
+      : ilist<T>(node_pool, MAX_SIZE)
+    {
+      etl::ilist<T>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    list& operator = (const list& rhs)
+    {
+      if (&rhs != this)
+      {
+        etl::ilist<T>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    /// The pool of nodes used in the list.
+    etl::pool<typename etl::ilist<T>::data_node_t, MAX_SIZE> node_pool;
+  };
+}
+
+//*************************************************************************
+/// Equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator ==(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs)
+{
+  return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//*************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator !=(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs)
+{
+  return !(lhs == rhs);
+}
+
+//*************************************************************************
+/// Less than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator <(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs)
+{
+  return std::lexicographical_compare(lhs.begin(),
+    lhs.end(),
+    rhs.begin(),
+    rhs.end());
+}
+
+//*************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator >(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs)
+{
+  return (rhs < lhs);
+}
+
+//*************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than or equal
+/// to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator <=(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs)
+{
+  return !(lhs > rhs);
+}
+
+//*************************************************************************
+/// Greater than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than or
+/// equal to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T>
+bool operator >=(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs)
+{
+  return !(lhs < rhs);
+}
+
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/log.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,116 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_LOG__
+#define __ETL_LOG__
+
+#include <stddef.h>
+
+#include "platform.h"
+
+///\defgroup log log
+/// log<N, BASE> : Calculates logs to any base, rounded down to the nearest integer.<br>
+/// log2<N>      : Calculates logs to base 2, rounded down to the nearest integer.<br>
+/// log10<N>     : Calculates logs to base 10, rounded down to the nearest integer.<br>
+///\ingroup maths
+
+namespace etl 
+{
+  //***************************************************************************
+  ///\ingroup log
+  /// The base generic log template.
+  /// Defines <b>value</b> as the log of the number at the specified base.
+  /// The result is rounded down to the next integer.
+  ///\tparam NV   The number to find the log of.
+  ///\tparam BASE The base of the log.
+  //***************************************************************************
+  template <const size_t NV, const size_t BASE>
+  struct log
+  {
+    enum value_type
+    {
+      // Recursive definition.
+      value = (NV >= BASE) ? 1 + log<NV / BASE, BASE>::value : 0
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for N = 1
+  //***************************************************************************
+  template <const size_t BASE>
+  struct log<1, BASE>
+  {
+    enum value_type
+    {
+      value = 0
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for N = 0
+  //***************************************************************************
+  template <const size_t BASE>
+  struct log<0, BASE>
+  {
+    enum value_type
+    {
+      value = 0
+    };
+  };
+
+  //***************************************************************************
+  ///\ingroup log
+  /// Calculates base 2 logs.
+  //***************************************************************************
+  template <const size_t NV>
+  struct log2
+  {
+    enum value_type
+    {
+      value = log<NV, 2>::value
+    };
+  };
+
+  //***************************************************************************
+  ///\ingroup log
+  /// Calculates base 10 logs.
+  //***************************************************************************
+  template <const size_t NV>
+  struct log10
+  {
+    enum value_type
+    {
+      value = log<NV, 10>::value
+    };
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/map.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,2160 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+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 __ETL_MAP__
+#define __ETL_MAP__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+#include <iterator>
+#include <algorithm>
+
+#include "platform.h"
+#include "container.h"
+#include "pool.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "debug_count.h"
+#include "nullptr.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#undef ETL_FILE
+#define ETL_FILE "8"
+
+//*****************************************************************************
+///\defgroup map map
+/// A map with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the map.
+  ///\ingroup map
+  //***************************************************************************
+  class map_exception : public etl::exception
+  {
+  public:
+
+    map_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Full exception for the map.
+  ///\ingroup map
+  //***************************************************************************
+  class map_full : public etl::map_exception
+  {
+  public:
+
+    map_full(string_type file_name_, numeric_type line_number_)
+      : etl::map_exception("map:full", file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Map out of bounds exception.
+  ///\ingroup map
+  //***************************************************************************
+  class map_out_of_bounds : public etl::map_exception
+  {
+  public:
+
+    map_out_of_bounds(string_type file_name_, numeric_type line_number_)
+      : etl::map_exception("map:bounds", file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the map.
+  ///\ingroup map
+  //***************************************************************************
+  class map_iterator : public etl::map_exception
+  {
+  public:
+
+    map_iterator(string_type file_name_, numeric_type line_number_)
+      : etl::map_exception("map:iterator", file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for all maps.
+  ///\ingroup map
+  //***************************************************************************
+  class map_base
+  {
+  public:
+
+    typedef size_t size_type; ///< The type used for determining the size of map.
+
+    //*************************************************************************
+    /// Gets the size of the map.
+    //*************************************************************************
+    size_type size() const
+    {
+      return current_size;
+    }
+
+    //*************************************************************************
+    /// Gets the maximum possible size of the map.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Checks to see if the map is empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return current_size == 0;
+    }
+
+    //*************************************************************************
+    /// Checks to see if the map is full.
+    //*************************************************************************
+    bool full() const
+    {
+      return current_size == CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the vector.
+    ///\return The capacity of the vector.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return max_size() - size();
+    }
+
+  protected:
+
+    enum
+    {
+      kLeft = 0,
+      kRight = 1,
+      kNeither = 2
+    };
+
+    //*************************************************************************
+    /// The node element in the map.
+    //*************************************************************************
+    struct Node
+    {
+      //***********************************************************************
+      /// Constructor
+      //***********************************************************************
+      Node() :
+        weight(uint_least8_t(kNeither)),
+        dir(uint_least8_t(kNeither))
+      {
+      }
+
+      ~Node()
+      {
+
+      }
+
+      //***********************************************************************
+      /// Marks the node as a leaf.
+      //***********************************************************************
+      void mark_as_leaf()
+      {
+        weight = uint_least8_t(kNeither);
+        dir = uint_least8_t(kNeither);
+        children[0] = std::nullptr;
+        children[1] = std::nullptr;
+      }
+
+      Node*   children[2];
+      uint_least8_t weight;
+      uint_least8_t dir;
+    };
+
+    //*************************************************************************
+    /// The constructor that is called from derived classes.
+    //*************************************************************************
+    map_base(size_type max_size_)
+      : current_size(0)
+      , CAPACITY(max_size_)
+      , root_node(std::nullptr)
+
+    {
+    }
+
+    //*************************************************************************
+    /// Balance the critical node at the position provided as needed
+    //*************************************************************************
+    void balance_node(Node*& critical_node)
+    {
+      // Step 1: Update weights for all children of the critical node up to the
+      // newly inserted node. This step is costly (in terms of traversing nodes
+      // multiple times during insertion) but doesn't require as much recursion
+      Node* weight_node = critical_node->children[critical_node->dir];
+      while (weight_node)
+      {
+        // Keep going until we reach a terminal node (dir == kNeither)
+        if (uint_least8_t(kNeither) != weight_node->dir)
+        {
+          // Does this insert balance the previous weight factor value?
+          if (weight_node->weight == 1 - weight_node->dir)
+          {
+            weight_node->weight = uint_least8_t(kNeither);
+          }
+          else
+          {
+            weight_node->weight = weight_node->dir;
+          }
+
+          // Update weight factor node to point to next node
+          weight_node = weight_node->children[weight_node->dir];
+        }
+        else
+        {
+          // Stop loop, terminal node found
+          break;
+        }
+      } // while(weight_node)
+
+        // Step 2: Update weight for critical_node or rotate tree to balance node
+      if (uint_least8_t(kNeither) == critical_node->weight)
+      {
+        critical_node->weight = critical_node->dir;
+      }
+      // If direction is different than weight, then it will now be balanced
+      else if (critical_node->dir != critical_node->weight)
+      {
+        critical_node->weight = uint_least8_t(kNeither);
+      }
+      // Rotate is required to balance the tree at the critical node
+      else
+      {
+        // If critical node matches child node direction then perform a two
+        // node rotate in the direction of the critical node
+        if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
+        {
+          rotate_2node(critical_node, critical_node->dir);
+        }
+        // Otherwise perform a three node rotation in the direction of the
+        // critical node
+        else
+        {
+          rotate_3node(critical_node, critical_node->dir,
+            critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Rotate two nodes at the position provided the to balance the tree
+    //*************************************************************************
+    void rotate_2node(Node*& position, uint_least8_t dir)
+    {
+      //     A            C             A          B
+      //   B   C   ->   A   E   OR    B   C  ->  D   A
+      //      D E      B D           D E            E C
+      // C (new position) becomes the root
+      // A (position) takes ownership of D as its children[kRight] child
+      // C (new position) takes ownership of A as its left child
+      //                 OR
+      // B (new position) becomes the root
+      // A (position) takes ownership of E as its left child
+      // B (new position) takes ownership of A as its right child
+
+      // Capture new root
+      Node* new_root = position->children[dir];
+      // Replace position's previous child with new root's other child
+      position->children[dir] = new_root->children[1 - dir];
+      // New root now becomes parent of current position
+      new_root->children[1 - dir] = position;
+      // Clear weight factor from current position
+      position->weight = uint_least8_t(kNeither);
+      // Newly detached right now becomes current position
+      position = new_root;
+      // Clear weight factor from new root
+      position->weight = uint_least8_t(kNeither);
+    }
+
+    //*************************************************************************
+    /// Rotate three nodes at the position provided the to balance the tree
+    //*************************************************************************
+    void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third)
+    {
+      //        __A__             __E__            __A__             __D__
+      //      _B_    C    ->     B     A    OR    B    _C_   ->     A     C
+      //     D   E              D F   G C             D   E        B F   G E
+      //        F G                                  F G
+      // E (new position) becomes the root
+      // B (position) takes ownership of F as its left child
+      // A takes ownership of G as its right child
+      //                  OR
+      // D (new position) becomes the root
+      // A (position) takes ownership of F as its right child
+      // C takes ownership of G as its left child
+
+      // Capture new root (either E or D depending on dir)
+      Node* new_root = position->children[dir]->children[1 - dir];
+      // Set weight factor for B or C based on F or G existing and being a different than dir
+      position->children[dir]->weight = third != uint_least8_t(kNeither) && third != dir ? dir : uint_least8_t(kNeither);
+
+      // Detach new root from its tree (replace with new roots child)
+      position->children[dir]->children[1 - dir] =
+        new_root->children[dir];
+      // Attach current left tree to new root
+      new_root->children[dir] = position->children[dir];
+      // Set weight factor for A based on F or G
+      position->weight = third != uint_least8_t(kNeither) && third == dir ? 1 - dir : uint_least8_t(kNeither);
+
+      // Move new root's right tree to current roots left tree
+      position->children[dir] = new_root->children[1 - dir];
+      // Attach current root to new roots right tree
+      new_root->children[1 - dir] = position;
+      // Replace current position with new root
+      position = new_root;
+      // Clear weight factor for new current position
+      position->weight = uint_least8_t(kNeither);
+    }
+
+    //*************************************************************************
+    /// Find the node whose key would go before all the other keys from the
+    /// position provided
+    //*************************************************************************
+    Node* find_limit_node(Node* position, const int8_t dir) const
+    {
+      // Something at this position and in the direction specified? keep going
+      Node* limit_node = position;
+      while (limit_node && limit_node->children[dir])
+      {
+        limit_node = limit_node->children[dir];
+      }
+
+      // Return the limit node position found
+      return limit_node;
+    }
+
+    //*************************************************************************
+    /// Find the node whose key would go before all the other keys from the
+    /// position provided
+    //*************************************************************************
+    const Node* find_limit_node(const Node* position, const int8_t dir) const
+    {
+      // Something at this position and in the direction specified? keep going
+      const Node* limit_node = position;
+      while (limit_node && limit_node->children[dir])
+      {
+        limit_node = limit_node->children[dir];
+      }
+
+      // Return the limit node position found
+      return limit_node;
+    }
+
+    //*************************************************************************
+    /// Attach the provided node to the position provided
+    //*************************************************************************
+    void attach_node(Node*& position, Node& node)
+    {
+      // Mark new node as leaf on attach to tree at position provided
+      node.mark_as_leaf();
+
+      // Add the node here
+      position = &node;
+
+      // One more.
+      ++current_size;
+    }
+
+    //*************************************************************************
+    /// Detach the node at the position provided
+    //*************************************************************************
+    void detach_node(Node*& position, Node*& replacement)
+    {
+      // Make temporary copy of actual nodes involved because we might lose
+      // their references in the process (e.g. position is the same as
+      // replacement or replacement is a child of position)
+      Node* detached = position;
+      Node* swap = replacement;
+
+      // Update current position to point to swap (replacement) node first
+      position = swap;
+
+      // Update replacement node to point to child in opposite direction
+      // otherwise we might lose the other child of the swap node
+      replacement = swap->children[1 - swap->dir];
+
+      // Point swap node to detached node's children and weight
+      swap->children[kLeft] = detached->children[kLeft];
+      swap->children[kRight] = detached->children[kRight];
+      swap->weight = detached->weight;
+    }
+
+    size_type current_size;   ///< The number of the used nodes.
+    const size_type CAPACITY; ///< The maximum size of the map.
+    Node* root_node;          ///< The node that acts as the map root.
+    etl::debug_count construct_count;
+  };
+
+  //***************************************************************************
+  /// A templated base for all etl::map types.
+  ///\ingroup map
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  class imap : public etl::map_base
+  {
+  public:
+
+    typedef TKey                           key_type;
+    typedef std::pair<const TKey, TMapped> value_type;
+    typedef TMapped                        mapped_type;
+    typedef TKeyCompare                    key_compare;
+    typedef value_type&                    reference;
+    typedef const value_type&              const_reference;
+    typedef value_type*                    pointer;
+    typedef const value_type*              const_pointer;
+    typedef size_t                         size_type;
+
+    //*************************************************************************
+    /// How to compare two key elements.
+    //*************************************************************************
+    struct key_comp
+    {
+      bool operator ()(const key_type& key1, const key_type& key2) const
+      {
+        return key_compare()(key1, key2);
+      }
+    };
+
+    //*************************************************************************
+    /// How to compare two value elements.
+    //*************************************************************************
+    struct value_comp
+    {
+      bool operator ()(const value_type& value1, const value_type& value2) const
+      {
+        return key_compare()(value1.first, value2.first);
+      }
+    };
+
+  protected:
+
+    //*************************************************************************
+    /// The data node element in the map.
+    //*************************************************************************
+    struct Data_Node : public Node
+    {
+      explicit Data_Node(value_type value_)
+        : value(value_)
+      {
+      }
+
+      ~Data_Node()
+      {
+
+      }
+
+      value_type value;
+    };
+
+    /// Defines the key value parameter type
+    typedef typename etl::parameter_type<TKey>::type key_parameter_t;
+
+    //*************************************************************************
+    /// How to compare node elements.
+    //*************************************************************************
+    bool node_comp(const Data_Node& node1, const Data_Node& node2) const
+    {
+      return key_compare()(node1.value.first, node2.value.first);
+    }
+    bool node_comp(const Data_Node& node, key_parameter_t key) const
+    {
+      return key_compare()(node.value.first, key);
+    }
+    bool node_comp(key_parameter_t key, const Data_Node& node) const
+    {
+      return key_compare()(key, node.value.first);
+    }
+
+  private:
+
+    /// The pool of data nodes used in the map.
+    ipool* p_node_pool;
+
+    //*************************************************************************
+    /// Downcast a Node* to a Data_Node*
+    //*************************************************************************
+    static Data_Node* data_cast(Node* p_node)
+    {
+      return static_cast<Data_Node*>(p_node);
+    }
+
+    //*************************************************************************
+    /// Downcast a Node& to a Data_Node&
+    //*************************************************************************
+    static Data_Node& data_cast(Node& node)
+    {
+      return static_cast<Data_Node&>(node);
+    }
+
+    //*************************************************************************
+    /// Downcast a const Node* to a const Data_Node*
+    //*************************************************************************
+    static const Data_Node* data_cast(const Node* p_node)
+    {
+      return static_cast<const Data_Node*>(p_node);
+    }
+
+    //*************************************************************************
+    /// Downcast a const Node& to a const Data_Node&
+    //*************************************************************************
+    static const Data_Node& data_cast(const Node& node)
+    {
+      return static_cast<const Data_Node&>(node);
+    }
+
+  public:
+
+    //*************************************************************************
+    /// iterator.
+    //*************************************************************************
+    class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+    {
+    public:
+
+      friend class imap;
+
+      iterator()
+        : p_map(std::nullptr)
+        , p_node(std::nullptr)
+      {
+      }
+
+      iterator(imap& map)
+        : p_map(&map)
+        , p_node(std::nullptr)
+      {
+      }
+
+      iterator(imap& map, Node* node)
+        : p_map(&map)
+        , p_node(node)
+      {
+      }
+
+      iterator(const iterator& other)
+        : p_map(other.p_map)
+        , p_node(other.p_node)
+      {
+      }
+
+      ~iterator()
+      {
+      }
+
+      iterator& operator ++()
+      {
+        p_map->next_node(p_node);
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        p_map->next_node(p_node);
+        return temp;
+      }
+
+      iterator& operator --()
+      {
+        p_map->prev_node(p_node);
+        return *this;
+      }
+
+      iterator operator --(int)
+      {
+        iterator temp(*this);
+        p_map->prev_node(p_node);
+        return temp;
+      }
+
+      iterator operator =(const iterator& other)
+      {
+        p_map = other.p_map;
+        p_node = other.p_node;
+        return *this;
+      }
+
+      reference operator *()
+      {
+        return imap::data_cast(p_node)->value;
+      }
+
+      const_reference operator *() const
+      {
+        return imap::data_cast(p_node)->value;
+      }
+
+      pointer operator &()
+      {
+        return &(imap::data_cast(p_node)->value);
+      }
+
+      const_pointer operator &() const
+      {
+        return &(imap::data_cast(p_node)->value);
+      }
+
+      pointer operator ->()
+      {
+        return &(imap::data_cast(p_node)->value);
+      }
+
+      const_pointer operator ->() const
+      {
+        return &(imap::data_cast(p_node)->value);
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.p_map == rhs.p_map && lhs.p_node == rhs.p_node;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      // Pointer to map associated with this iterator
+      imap* p_map;
+
+      // Pointer to the current node for this iterator
+      Node* p_node;
+    };
+
+    friend class iterator;
+
+    //*************************************************************************
+    /// const_iterator
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+    {
+    public:
+
+      friend class imap;
+
+      const_iterator()
+        : p_map(std::nullptr)
+        , p_node(std::nullptr)
+      {
+      }
+
+      const_iterator(const imap& map)
+        : p_map(&map)
+        , p_node(std::nullptr)
+      {
+      }
+
+      const_iterator(const imap& map, const Node* node)
+        : p_map(&map)
+        , p_node(node)
+      {
+      }
+
+      const_iterator(const typename imap::iterator& other)
+        : p_map(other.p_map)
+        , p_node(other.p_node)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : p_map(other.p_map)
+        , p_node(other.p_node)
+      {
+      }
+
+      ~const_iterator()
+      {
+      }
+
+      const_iterator& operator ++()
+      {
+        p_map->next_node(p_node);
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        p_map->next_node(p_node);
+        return temp;
+      }
+
+      const_iterator& operator --()
+      {
+        p_map->prev_node(p_node);
+        return *this;
+      }
+
+      const_iterator operator --(int)
+      {
+        const_iterator temp(*this);
+        p_map->prev_node(p_node);
+        return temp;
+      }
+
+      const_iterator operator =(const const_iterator& other)
+      {
+        p_map = other.p_map;
+        p_node = other.p_node;
+        return *this;
+      }
+
+      const_reference operator *() const
+      {
+        return imap::data_cast(p_node)->value;
+      }
+
+      const_pointer operator &() const
+      {
+        return imap::data_cast(p_node)->value;
+      }
+
+      const_pointer operator ->() const
+      {
+        return &(imap::data_cast(p_node)->value);
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.p_map == rhs.p_map && lhs.p_node == rhs.p_node;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+      // Pointer to map associated with this iterator
+      const imap* p_map;
+
+      // Pointer to the current node for this iterator
+      const Node* p_node;
+    };
+
+    friend class const_iterator;
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+
+    //*************************************************************************
+    /// Gets the beginning of the map.
+    //*************************************************************************
+    iterator begin()
+    {
+      return iterator(*this, find_limit_node(root_node, kLeft));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the map.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(*this, find_limit_node(root_node, kLeft));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the map.
+    //*************************************************************************
+    iterator end()
+    {
+      return iterator(*this);
+    }
+
+    //*************************************************************************
+    /// Gets the end of the map.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(*this);
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the map.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(*this, find_limit_node(root_node, kLeft));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the map.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(*this);
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(iterator(*this));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(const_iterator(*this));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(const_iterator(*this));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'key'
+    ///\param i The index.
+    ///\return A reference to the value at index 'key'
+    //*********************************************************************
+    mapped_type& operator [](key_parameter_t key)
+    {
+      iterator i_element = find(key);
+
+      if (!i_element.p_node)
+      {
+        // Doesn't exist, so create a new one.
+        i_element = insert(std::make_pair(key, mapped_type())).first;
+      }
+
+      return i_element->second;
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'key'
+    /// If asserts or exceptions are enabled, emits an etl::lookup_out_of_bounds if the key is not in the range.
+    ///\param i The index.
+    ///\return A reference to the value at index 'key'
+    //*********************************************************************
+    mapped_type& at(key_parameter_t key)
+    {
+      iterator i_element = find(key);
+
+      ETL_ASSERT(i_element.p_node != std::nullptr, ETL_ERROR(map_out_of_bounds));
+
+      return i_element->second;
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'key'
+    /// If asserts or exceptions are enabled, emits an etl::lookup_out_of_bounds if the key is not in the range.
+    ///\param i The index.
+    ///\return A const reference to the value at index 'key'
+    //*********************************************************************
+    const mapped_type& at(key_parameter_t key) const
+    {
+      const_iterator i_element = find(key);
+
+      ETL_ASSERT(i_element.p_node != std::nullptr, ETL_ERROR(map_out_of_bounds));
+
+      return i_element->second;
+    }
+
+    //*********************************************************************
+    /// Assigns values to the map.
+    /// If asserts or exceptions are enabled, emits map_full if the map does not have enough free space.
+    /// If asserts or exceptions are enabled, emits map_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+      initialise();
+      insert(first, last);
+    }
+
+    //*************************************************************************
+    /// Clears the map.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*********************************************************************
+    /// Counts the number of elements that contain the key specified.
+    ///\param key The key to search for.
+    ///\return 1 if element was found, 0 otherwise.
+    //*********************************************************************
+    size_type count(key_parameter_t key) const
+    {
+      return find_node(root_node, key) ? 1 : 0;
+    }
+
+    //*************************************************************************
+    /// Returns two iterators with bounding (lower bound, upper bound) the key
+    /// provided
+    //*************************************************************************
+    std::pair<iterator, iterator> equal_range(key_parameter_t key)
+    {
+      return std::make_pair<iterator, iterator>(
+        iterator(*this, find_lower_node(root_node, key)),
+        iterator(*this, find_upper_node(root_node, key)));
+    }
+
+    //*************************************************************************
+    /// Returns two const iterators with bounding (lower bound, upper bound)
+    /// the key provided.
+    //*************************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
+    {
+      return std::make_pair<const_iterator, const_iterator>(
+        const_iterator(*this, find_lower_node(root_node, key)),
+        const_iterator(*this, find_upper_node(root_node, key)));
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    void erase(iterator position)
+    {
+      // Remove the node by its key
+      erase((*position).first);
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    iterator erase(const_iterator position)
+    {
+      // Find the parent node to be removed
+      Node*& reference_node = find_node(root_node, position.p_node);
+      iterator next(*this, reference_node);
+      ++next;
+
+      remove_node(root_node, (*position).first);
+
+      return next;
+    }
+
+    //*************************************************************************
+    // Erase the key specified.
+    //*************************************************************************
+    size_type erase(key_parameter_t key)
+    {
+      // Return 1 if key value was found and removed
+      return remove_node(root_node, key) ? 1 : 0;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    //*************************************************************************
+    iterator erase(iterator first, iterator last)
+    {
+      iterator next;
+      while (first != last)
+      {
+        next = erase(const_iterator(first++));
+      }
+
+      return next;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    //*************************************************************************
+    iterator erase(const_iterator first, const_iterator last)
+    {
+      iterator next;
+      while (first != last)
+      {
+        next = erase(first++);
+      }
+
+      return next;
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    iterator find(key_parameter_t key)
+    {
+      return iterator(*this, find_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    const_iterator find(key_parameter_t key) const
+    {
+      return const_iterator(*this, find_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the map.
+    /// If asserts or exceptions are enabled, emits map_full if the map is already full.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(const value_type& value)
+    {
+      // Default to no inserted node
+      Node* inserted_node = std::nullptr;
+      bool inserted = false;
+
+      ETL_ASSERT(!full(), ETL_ERROR(map_full));
+
+      // Get next available free node
+      Data_Node& node = allocate_data_node(value);
+
+      // Obtain the inserted node (might be std::nullptr if node was a duplicate)
+      inserted_node = insert_node(root_node, node);
+      inserted = inserted_node == &node;
+
+      // Insert node into tree and return iterator to new node location in tree
+      return std::make_pair(iterator(*this, inserted_node), inserted);
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the map starting at the position recommended.
+    /// If asserts or exceptions are enabled, emits map_full if the map is already full.
+    ///\param position The position that would precede the value to insert.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator, const value_type& value)
+    {
+      // Default to no inserted node
+      Node* inserted_node = std::nullptr;
+
+      ETL_ASSERT(!full(), ETL_ERROR(map_full));
+
+      // Get next available free node
+      Data_Node& node = allocate_data_node(value);
+
+      // Obtain the inserted node (might be std::nullptr if node was a duplicate)
+      inserted_node = insert_node(root_node, node);
+
+      // Insert node into tree and return iterator to new node location in tree
+      return iterator(*this, inserted_node);
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the map starting at the position recommended.
+    /// If asserts or exceptions are enabled, emits map_full if the map is already full.
+    ///\param position The position that would precede the value to insert.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(const_iterator, const value_type& value)
+    {
+      // Default to no inserted node
+      Node* inserted_node = std::nullptr;
+
+      ETL_ASSERT(!full(), ETL_ERROR(map_full));
+
+      // Get next available free node
+      Data_Node& node = allocate_data_node(value);
+
+      // Obtain the inserted node (might be std::nullptr if node was a duplicate)
+      inserted_node = insert_node(root_node, node);
+
+      // Insert node into tree and return iterator to new node location in tree
+      return iterator(*this, inserted_node);
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the map.
+    /// If asserts or exceptions are enabled, emits map_full if the map does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Returns an iterator pointing to the first element in the container
+    /// whose key is not considered to go before the key provided or end()
+    /// if all keys are considered to go before the key provided.
+    ///\return An iterator pointing to the element not before key or end()
+    //*********************************************************************
+    iterator lower_bound(key_parameter_t key)
+    {
+      return iterator(*this, find_lower_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator pointing to the first element in the
+    /// container whose key is not considered to go before the key provided
+    /// or end() if all keys are considered to go before the key provided.
+    ///\return An const_iterator pointing to the element not before key or end()
+    //*********************************************************************
+    const_iterator lower_bound(key_parameter_t key) const
+    {
+      return const_iterator(*this, find_lower_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Returns an iterator pointing to the first element in the container
+    /// whose key is not considered to go after the key provided or end()
+    /// if all keys are considered to go after the key provided.
+    ///\return An iterator pointing to the element after key or end()
+    //*********************************************************************
+    iterator upper_bound(key_parameter_t key)
+    {
+      return iterator(*this, find_upper_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator pointing to the first element in the
+    /// container whose key is not considered to go after the key provided
+    /// or end() if all keys are considered to go after the key provided.
+    ///\return An const_iterator pointing to the element after key or end()
+    //*********************************************************************
+    const_iterator upper_bound(key_parameter_t key) const
+    {
+      return const_iterator(*this, find_upper_node(root_node, key));
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    imap& operator = (const imap& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    imap(etl::ipool& node_pool, size_t max_size_)
+      : etl::map_base(max_size_)
+      , p_node_pool(&node_pool)
+    {
+    }
+
+    //*************************************************************************
+    /// Initialise the map.
+    //*************************************************************************
+    void initialise()
+    {
+      erase(begin(), end());
+    }
+
+  private:
+
+    //*************************************************************************
+    /// Allocate a Data_Node.
+    //*************************************************************************
+    Data_Node& allocate_data_node(value_type value)
+    {
+      Data_Node& node = *p_node_pool->allocate<Data_Node>();
+      ::new (&node.value) const value_type(value);
+      ++construct_count;
+      return node;
+    }
+
+    //*************************************************************************
+    /// Destroy a Data_Node.
+    //*************************************************************************
+    void destroy_data_node(Data_Node& node)
+    {
+      node.value.~value_type();
+      p_node_pool->release(&node);
+      --construct_count;
+    }
+
+    //*************************************************************************
+    /// Find the value matching the node provided
+    //*************************************************************************
+    Node* find_node(Node* position, key_parameter_t key)
+    {
+      Node* found = position;
+      while (found)
+      {
+        // Downcast found to Data_Node class for comparison and other operations
+        Data_Node& found_data_node = imap::data_cast(*found);
+
+        // Compare the node value to the current position value
+        if (node_comp(key, found_data_node))
+        {
+          // Keep searching for the node on the left
+          found = found->children[kLeft];
+        }
+        else if (node_comp(found_data_node, key))
+        {
+          // Keep searching for the node on the right
+          found = found->children[kRight];
+        }
+        else
+        {
+          // Node that matches the key provided was found, exit loop
+          break;
+        }
+      }
+
+      // Return the node found (might be std::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the value matching the node provided
+    //*************************************************************************
+    const Node* find_node(const Node* position, key_parameter_t key) const
+    {
+      const Node* found = position;
+      while (found)
+      {
+        // Downcast found to Data_Node class for comparison and other operations
+        const Data_Node& found_data_node = imap::data_cast(*found);
+
+        // Compare the node value to the current position value
+        if (node_comp(key, found_data_node))
+        {
+          // Keep searching for the node on the left
+          found = found->children[kLeft];
+        }
+        else if (node_comp(found_data_node, key))
+        {
+          // Keep searching for the node on the right
+          found = found->children[kRight];
+        }
+        else
+        {
+          // Node that matches the key provided was found, exit loop
+          break;
+        }
+      }
+
+      // Return the node found (might be std::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the reference node matching the node provided
+    //*************************************************************************
+    Node*& find_node(Node*& position, const Node* node)
+    {
+      Node* found = position;
+      while (found)
+      {
+        if (found->children[kLeft] == node)
+        {
+          return found->children[kLeft];
+        }
+        else if (found->children[kRight] == node)
+        {
+          return found->children[kRight];
+        }
+        else
+        {
+          // Downcast found to Data_Node class for comparison and other operations
+          Data_Node& found_data_node = imap::data_cast(*found);
+          const Data_Node& data_node = imap::data_cast(*node);
+
+          // Compare the node value to the current position value
+          if (node_comp(data_node, found_data_node))
+          {
+            // Keep searching for the node on the left
+            found = found->children[kLeft];
+          }
+          else if (node_comp(found_data_node, data_node))
+          {
+            // Keep searching for the node on the right
+            found = found->children[kRight];
+          }
+          else
+          {
+            // Return position provided (it matches the node)
+            return position;
+          }
+        }
+      }
+
+      // Return root node if nothing was found
+      return root_node;
+    }
+
+    //*************************************************************************
+    /// Find the parent node that contains the node provided in its left or
+    /// right tree
+    //*************************************************************************
+    Node* find_parent_node(Node* position, const Node* node)
+    {
+      // Default to no parent node found
+      Node* found = std::nullptr;
+
+      // If the position provided is the same as the node then there is no parent
+      if (position && node && position != node)
+      {
+        while (position)
+        {
+          // Is this position not the parent of the node we are looking for?
+          if (position->children[kLeft] != node &&
+            position->children[kRight] != node)
+          {
+            // Downcast node and position to Data_Node references for key comparisons
+            const Data_Node& node_data_node = imap::data_cast(*node);
+            Data_Node& position_data_node = imap::data_cast(*position);
+            // Compare the node value to the current position value
+            if (node_comp(node_data_node, position_data_node))
+            {
+              // Keep looking for parent on the left
+              position = position->children[kLeft];
+            }
+            else if (node_comp(position_data_node, node_data_node))
+            {
+              // Keep looking for parent on the right
+              position = position->children[kRight];
+            }
+          }
+          else
+          {
+            // Return the current position as the parent node found
+            found = position;
+
+            // Parent node found, exit loop
+            break;
+          }
+        }
+      }
+
+      // Return the parent node found (might be std::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the parent node that contains the node provided in its left or
+    /// right tree
+    //*************************************************************************
+    const Node* find_parent_node(const Node* position, const Node* node) const
+    {
+      // Default to no parent node found
+      const Node* found = std::nullptr;
+
+      // If the position provided is the same as the node then there is no parent
+      if (position && node && position != node)
+      {
+        while (position)
+        {
+          // Is this position not the parent of the node we are looking for?
+          if (position->children[kLeft] != node &&
+            position->children[kRight] != node)
+          {
+            // Downcast node and position to Data_Node references for key comparisons
+            const Data_Node& node_data_node = imap::data_cast(*node);
+            const Data_Node& position_data_node = imap::data_cast(*position);
+            // Compare the node value to the current position value
+            if (node_comp(node_data_node, position_data_node))
+            {
+              // Keep looking for parent on the left
+              position = position->children[kLeft];
+            }
+            else if (node_comp(position_data_node, node_data_node))
+            {
+              // Keep looking for parent on the right
+              position = position->children[kRight];
+            }
+          }
+          else
+          {
+            // Return the current position as the parent node found
+            found = position;
+
+            // Parent node found, exit loop
+            break;
+          }
+        }
+      }
+
+      // Return the parent node found (might be std::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the node whose key is not considered to go before the key provided
+    //*************************************************************************
+    Node* find_lower_node(Node* position, key_parameter_t key) const
+    {
+      // Something at this position? keep going
+      Node* lower_node = position;
+      while (lower_node)
+      {
+        // Downcast lower node to Data_Node reference for key comparisons
+        Data_Node& data_node = imap::data_cast(*lower_node);
+        // Compare the key value to the current lower node key value
+        if (node_comp(key, data_node))
+        {
+          if (lower_node->children[kLeft])
+          {
+            lower_node = lower_node->children[kLeft];
+          }
+          else
+          {
+            // Found lowest node
+            break;
+          }
+        }
+        else if (node_comp(data_node, key))
+        {
+          lower_node = lower_node->children[kRight];
+        }
+        else
+        {
+          // Found equal node
+          break;
+        }
+      }
+
+      // Return the lower_node position found
+      return lower_node;
+    }
+
+    //*************************************************************************
+    /// Find the node whose key is considered to go after the key provided
+    //*************************************************************************
+    Node* find_upper_node(Node* position, key_parameter_t key) const
+    {
+      // Keep track of parent of last upper node
+      Node* upper_node = std::nullptr;
+      // Start with position provided
+      Node* node = position;
+      while (node)
+      {
+        // Downcast position to Data_Node reference for key comparisons
+        Data_Node& data_node = imap::data_cast(*node);
+        // Compare the key value to the current upper node key value
+        if (node_comp(key, data_node))
+        {
+          upper_node = node;
+          node = node->children[kLeft];
+        }
+        else if (node_comp(data_node, key))
+        {
+          node = node->children[kRight];
+        }
+        else if (node->children[kRight])
+        {
+          upper_node = find_limit_node(node->children[kRight], kLeft);
+          break;
+        }
+        else
+        {
+          break;
+        }
+      }
+
+      // Return the upper node position found (might be std::nullptr)
+      return upper_node;
+    }
+
+    //*************************************************************************
+    /// Insert a node.
+    //*************************************************************************
+    Node* insert_node(Node*& position, Data_Node& node)
+    {
+      // Find the location where the node belongs
+      Node* found = position;
+
+      // Was position provided not empty? then find where the node belongs
+      if (position)
+      {
+        // Find the critical parent node (default to std::nullptr)
+        Node* critical_parent_node = std::nullptr;
+        Node* critical_node = root_node;
+
+        while (found)
+        {
+          // Search for critical weight node (all nodes whose weight factor
+          // is set to kNeither (balanced)
+          if (kNeither != found->weight)
+          {
+            critical_node = found;
+          }
+
+          // Downcast found to Data_Node class for comparison and other operations
+          Data_Node& found_data_node = imap::data_cast(*found);
+
+          // Is the node provided to the left of the current position?
+          if (node_comp(node, found_data_node))
+          {
+            // Update direction taken to insert new node in parent node
+            found->dir = kLeft;
+          }
+          // Is the node provided to the right of the current position?
+          else if (node_comp(found_data_node, node))
+          {
+            // Update direction taken to insert new node in parent node
+            found->dir = kRight;
+          }
+          else
+          {
+            // Update direction taken to insert new node in parent node
+            found->dir = kNeither;
+
+            // Clear critical node value to skip weight step below
+            critical_node = std::nullptr;
+
+            // Destroy the node provided (its a duplicate)
+            destroy_data_node(node);
+
+            // Exit loop, duplicate node found
+            break;
+          }
+
+          // Is there a child of this parent node?
+          if (found->children[found->dir])
+          {
+            // Will this node be the parent of the next critical node whose
+            // weight factor is set to kNeither (balanced)?
+            if (kNeither != found->children[found->dir]->weight)
+            {
+              critical_parent_node = found;
+            }
+
+            // Keep looking for empty spot to insert new node
+            found = found->children[found->dir];
+          }
+          else
+          {
+            // Attatch node to right
+            attach_node(found->children[found->dir], node);
+
+            // Return newly added node
+            found = found->children[found->dir];
+
+            // Exit loop
+            break;
+          }
+        }
+
+        // Was a critical node found that should be checked for balance?
+        if (critical_node)
+        {
+          if (critical_parent_node == std::nullptr && critical_node == root_node)
+          {
+            balance_node(root_node);
+          }
+          else if (critical_parent_node == std::nullptr && critical_node == position)
+          {
+            balance_node(position);
+          }
+          else
+          {
+            balance_node(critical_parent_node->children[critical_parent_node->dir]);
+          }
+        }
+      }
+      else
+      {
+        // Attatch node to current position
+        attach_node(position, node);
+
+        // Return newly added node at current position
+        found = position;
+      }
+
+      // Return the node found (might be std::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the next node in sequence from the node provided
+    //*************************************************************************
+    void next_node(Node*&position)
+    {
+      if (position)
+      {
+        // Is there a tree on the right? then find the minimum of that tree
+        if (position->children[kRight])
+        {
+          // Return minimum node found
+          position = find_limit_node(position->children[kRight], kLeft);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = find_parent_node(root_node, position);
+            // Repeat while previous position was on right side of parent tree
+          } while (parent && parent->children[kRight] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the next node in sequence from the node provided
+    //*************************************************************************
+    void next_node(const Node*& position) const
+    {
+      if (position)
+      {
+        // Is there a tree on the right? then find the minimum of that tree
+        if (position->children[kRight])
+        {
+          // Return minimum node found
+          position = find_limit_node(position->children[kRight], kLeft);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          const Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = find_parent_node(root_node, position);
+            // Repeat while previous position was on right side of parent tree
+          } while (parent && parent->children[kRight] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the previous node in sequence from the node provided
+    //*************************************************************************
+    void prev_node(Node*&position)
+    {
+      // If starting at the terminal end, the previous node is the maximum node
+      // from the root
+      if (!position)
+      {
+        position = find_limit_node(root_node, kRight);
+      }
+      else
+      {
+        // Is there a tree on the left? then find the maximum of that tree
+        if (position->children[kLeft])
+        {
+          // Return maximum node found
+          position = find_limit_node(position->children[kLeft], kRight);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = find_parent_node(root_node, position);
+            // Repeat while previous position was on left side of parent tree
+          } while (parent && parent->children[kLeft] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the previous node in sequence from the node provided
+    //*************************************************************************
+    void prev_node(const Node*& position) const
+    {
+      // If starting at the terminal end, the previous node is the maximum node
+      // from the root
+      if (!position)
+      {
+        position = find_limit_node(root_node, kRight);
+      }
+      else
+      {
+        // Is there a tree on the left? then find the maximum of that tree
+        if (position->children[kLeft])
+        {
+          // Return maximum node found
+          position = find_limit_node(position->children[kLeft], kRight);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          const Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = find_parent_node(root_node, position);
+            // Repeat while previous position was on left side of parent tree
+          } while (parent && parent->children[kLeft] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Remove the node specified from somewhere starting at the position
+    /// provided
+    //*************************************************************************
+    Node* remove_node(Node*& position, key_parameter_t key)
+    {
+      // Step 1: Find the target node that matches the key provided, the
+      // replacement node (might be the same as target node), and the critical
+      // node to start rebalancing the tree from (up to the replacement node)
+      Node* found_parent = std::nullptr;
+      Node* found = std::nullptr;
+      Node* replace_parent = std::nullptr;
+      Node* replace = position;
+      Node* balance_parent = std::nullptr;
+      Node* balance = root_node;
+      while (replace)
+      {
+        // Downcast found to Data_Node class for comparison and other operations
+        Data_Node& replace_data_node = imap::data_cast(*replace);
+
+        // Compare the key provided to the replace data node key
+        if (node_comp(key, replace_data_node))
+        {
+          // Update the direction to the target/replace node
+          replace->dir = kLeft;
+        }
+        else if (node_comp(replace_data_node, key))
+        {
+          // Update the direction to the target/replace node
+          replace->dir = kRight;
+        }
+        else
+        {
+          // Update the direction to the replace node (target node found here)
+          replace->dir = replace->children[kLeft] ? kLeft : kRight;
+
+          // Note the target node was found (and its parent)
+          found_parent = replace_parent;
+          found = replace;
+        }
+        // Replacement node found if its missing a child in the replace->dir
+        // value set above
+        if (replace->children[replace->dir] == std::nullptr)
+        {
+          // Exit loop once replace node is found (target might not have been)
+          break;
+        }
+
+        // If replacement node weight is kNeither or we are taking the shorter
+        // path of replacement node and our sibling (on longer path) is
+        // balanced then we need to update the balance node to match this
+        // replacement node but all our ancestors will not require rebalancing
+        if ((replace->weight == kNeither) ||
+          (replace->weight == (1 - replace->dir) &&
+            replace->children[1 - replace->dir]->weight == kNeither))
+        {
+          // Update balance node (and its parent) to replacement node
+          balance_parent = replace_parent;
+          balance = replace;
+        }
+
+        // Keep searching for the replacement node
+        replace_parent = replace;
+        replace = replace->children[replace->dir];
+      }
+
+      // If target node was found, proceed with rebalancing and replacement
+      if (found)
+      {
+        // Step 2: Update weights from critical node to replacement parent node
+        while (balance)
+        {
+          if (balance->children[balance->dir] == std::nullptr)
+          {
+            break;
+          }
+
+          if (balance->weight == kNeither)
+          {
+            balance->weight = 1 - balance->dir;
+          }
+          else if (balance->weight == balance->dir)
+          {
+            balance->weight = kNeither;
+          }
+          else
+          {
+            int weight = balance->children[1 - balance->dir]->weight;
+            // Perform a 3 node rotation if weight is same as balance->dir
+            if (weight == balance->dir)
+            {
+              // Is the root node being rebalanced (no parent)
+              if (balance_parent == std::nullptr)
+              {
+                rotate_3node(root_node, 1 - balance->dir,
+                  balance->children[1 - balance->dir]->children[balance->dir]->weight);
+              }
+              else
+              {
+                rotate_3node(balance_parent->children[balance_parent->dir], 1 - balance->dir,
+                  balance->children[1 - balance->dir]->children[balance->dir]->weight);
+              }
+            }
+            // Already balanced, rebalance and make it heavy in opposite
+            // direction of the node being removed
+            else if (weight == kNeither)
+            {
+              // Is the root node being rebalanced (no parent)
+              if (balance_parent == std::nullptr)
+              {
+                rotate_2node(root_node, 1 - balance->dir);
+                root_node->weight = balance->dir;
+              }
+              else
+              {
+                rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
+                balance_parent->children[balance_parent->dir]->weight = balance->dir;
+              }
+              // Update balance node weight in opposite direction of node removed
+              balance->weight = 1 - balance->dir;
+            }
+            // Rebalance and leave it balanced
+            else
+            {
+              // Is the root node being rebalanced (no parent)
+              if (balance_parent == std::nullptr)
+              {
+                rotate_2node(root_node, 1 - balance->dir);
+              }
+              else
+              {
+                rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
+              }
+            }
+
+            // Is balance node the same as the target node found? then update
+            // its parent after the rotation performed above
+            if (balance == found)
+            {
+              if (balance_parent)
+              {
+                found_parent = balance_parent->children[balance_parent->dir];
+                // Update dir since it is likely stale
+                found_parent->dir = found_parent->children[kLeft] == found ? kLeft : kRight;
+              }
+              else
+              {
+                found_parent = root_node;
+                root_node->dir = root_node->children[kLeft] == found ? kLeft : kRight;
+              }
+            }
+          }
+
+          // Next balance node to consider
+          balance_parent = balance;
+          balance = balance->children[balance->dir];
+        } // while(balance)
+
+          // Step 3: Swap found node with replacement node
+        if (found_parent)
+        {
+          // Handle traditional case
+          detach_node(found_parent->children[found_parent->dir],
+            replace_parent->children[replace_parent->dir]);
+        }
+        // Handle root node removal
+        else
+        {
+          // Valid replacement node for root node being removed?
+          if (replace_parent)
+          {
+            detach_node(root_node, replace_parent->children[replace_parent->dir]);
+          }
+          else
+          {
+            // Target node and replacement node are both root node
+            detach_node(root_node, root_node);
+          }
+        }
+
+        // Downcast found into data node
+        Data_Node& found_data_node = imap::data_cast(*found);
+
+        // One less.
+        --current_size;
+
+        // Destroy the node removed
+        destroy_data_node(found_data_node);
+      } // if(found)
+
+        // Return node found (might be std::nullptr)
+      return found;
+    }
+
+    // Disable copy construction.
+    imap(const imap&);
+  };
+
+  //*************************************************************************
+  /// A templated map implementation that uses a fixed size buffer.
+  //*************************************************************************
+  template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> >
+  class map : public etl::imap<TKey, TValue, TCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    map()
+      : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
+    {
+      etl::imap<TKey, TValue, TCompare>::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    map(const map& other)
+      : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
+    {
+      etl::imap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    map(TIterator first, TIterator last)
+      : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
+    {
+      etl::imap<TKey, TValue, TCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~map()
+    {
+      etl::imap<TKey, TValue, TCompare>::initialise();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    map& operator = (const map& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        etl::imap<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    /// The pool of data nodes used for the map.
+    etl::pool<typename etl::imap<TKey, TValue, TCompare>::Data_Node, MAX_SIZE> node_pool;
+  };
+}
+
+//***************************************************************************
+/// Equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator ==(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
+{
+  return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//***************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator !=(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
+{
+  return !(lhs == rhs);
+}
+
+//*************************************************************************
+/// Less than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator <(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
+{
+  return std::lexicographical_compare(lhs.begin(),
+    lhs.end(),
+    rhs.begin(),
+    rhs.end());
+}
+
+//*************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator >(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
+{
+  return (rhs < lhs);
+}
+
+//*************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than or equal
+/// to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator <=(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
+{
+  return !(lhs > rhs);
+}
+
+//*************************************************************************
+/// Greater than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than or
+/// equal to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator >=(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
+{
+  return !(lhs < rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/memory.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,773 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_MEMORY__
+#define __ETL_MEMORY__
+
+#include <iterator>
+#include <algorithm>
+
+#include "platform.h"
+#include "type_traits.h"
+
+///\defgroup memory memory
+///\ingroup etl
+namespace etl
+{
+  //*****************************************************************************
+  /// Gets the address of an object.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T>
+  T* addressof(T& t)
+  {
+      return reinterpret_cast<T*>(&const_cast<char&>(reinterpret_cast<const volatile char&>(t)));
+  }
+
+  //*****************************************************************************
+  /// Fills uninitialised memory range with a value.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename T>
+  typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
+   uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value)
+  {
+    std::fill(o_begin, o_end, value);
+
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Fills uninitialised memory range with a value.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename T>
+  typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
+   uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value)
+  {
+    typedef typename std::iterator_traits<TOutputIterator>::value_type value_type;
+
+    while (o_begin != o_end)
+    {
+      ::new (static_cast<void*>(etl::addressof(*o_begin))) value_type(value);
+      ++o_begin;
+    }
+
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Fills uninitialised memory range with a value.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename T, typename TCounter>
+  typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
+   uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value, TCounter& count)
+  {
+    count += std::distance(o_begin, o_end);
+
+    std::fill(o_begin, o_end, value);
+    
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Fills uninitialised memory range with a value.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename T, typename TCounter>
+  typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
+   uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value, TCounter& count)
+  {
+    count += std::distance(o_begin, o_end);
+
+    etl::uninitialized_fill(o_begin, o_end, value);
+
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Fills uninitialised memory with N values.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename TSize, typename T>
+  inline TOutputIterator uninitialized_fill_n(TOutputIterator o_begin, TSize n, const T& value)
+  {
+    return etl::uninitialized_fill(o_begin, o_begin + n, value);
+  }
+
+  //*****************************************************************************
+  /// Fills uninitialised memory with N values.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename TSize, typename T, typename TCounter>
+  inline TOutputIterator uninitialized_fill_n(TOutputIterator o_begin, TSize n, const T& value, TCounter& count)
+  {
+    count += n;
+
+    return etl::uninitialized_fill(o_begin, o_begin + n, value);
+  }
+
+  //*****************************************************************************
+  /// Copies a range of objects to uninitialised memory.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TInputIterator, typename TOutputIterator>
+  typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
+   uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin)
+  {
+    return std::copy(i_begin, i_end, o_begin);
+  }
+
+  //*****************************************************************************
+  /// Copies a range of objects to uninitialised memory.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TInputIterator, typename TOutputIterator>
+  typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
+   uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin)
+  {
+    typedef typename std::iterator_traits<TOutputIterator>::value_type value_type;
+
+    TOutputIterator o_end = o_begin;
+
+    while (i_begin != i_end)
+    {
+      ::new (static_cast<void*>(etl::addressof(*o_end))) value_type(*i_begin);
+      ++i_begin;
+      ++o_end;
+    }
+
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Copies a range of objects to uninitialised memory.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TInputIterator, typename TOutputIterator, typename TCounter>
+  typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
+   uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count)
+  {
+    TOutputIterator o_end = std::copy(i_begin, i_end, o_begin);
+    count += std::distance(o_begin, o_end);
+
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Copies a range of objects to uninitialised memory.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TInputIterator, typename TOutputIterator, typename TCounter>
+  typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
+   uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count)
+  {
+    TOutputIterator o_end = etl::uninitialized_copy(i_begin, i_end, o_begin);
+
+    count += std::distance(o_begin, o_end);
+
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Copies N objects to uninitialised memory.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TInputIterator, typename TSize, typename TOutputIterator>
+  inline TOutputIterator uninitialized_copy_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin)
+  {
+    return etl::uninitialized_copy(i_begin, i_begin + n, o_begin);
+  }
+
+  //*****************************************************************************
+  /// Copies N objects to uninitialised memory.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TInputIterator, typename TSize, typename TOutputIterator, typename TCounter>
+  inline TOutputIterator uninitialized_copy_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TCounter& count)
+  {
+    count += n;
+
+    return etl::uninitialized_copy(i_begin, i_begin + n, o_begin);
+  }
+
+  //*****************************************************************************
+  /// Default contruct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T>
+  typename etl::enable_if<etl::is_trivially_constructible<T>::value, void>::type
+   create_default_at(T* /*p*/)
+  {
+  }
+
+  //*****************************************************************************
+  /// Default contruct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T, typename TCounter>
+  typename etl::enable_if<etl::is_trivially_constructible<T>::value, void>::type
+   create_default_at(T* /*p*/, TCounter& count)
+  {
+    ++count;
+  }
+
+  //*****************************************************************************
+  /// Default contruct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T>
+  typename etl::enable_if<!etl::is_trivially_constructible<T>::value, void>::type
+   create_default_at(T* p)
+  {
+    ::new (p) T;
+  }
+
+  //*****************************************************************************
+  /// Default contruct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T, typename TCounter>
+  typename etl::enable_if<!etl::is_trivially_constructible<T>::value, void>::type
+   create_default_at(T* p, TCounter& count)
+  {
+    ::new (p) T;
+    ++count;
+  }
+
+  //*****************************************************************************
+  /// Default initialises a range of objects to uninitialised memory.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator>
+  typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, void>::type
+   uninitialized_default_construct(TOutputIterator /*o_begin*/, TOutputIterator /*o_end*/)
+  {
+  }
+
+  //*****************************************************************************
+  /// Default initialises a range of objects to uninitialised memory.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator>
+  typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, void>::type
+   uninitialized_default_construct(TOutputIterator o_begin, TOutputIterator o_end)
+  {
+    typedef typename std::iterator_traits<TOutputIterator>::value_type value_type;
+
+    while (o_begin != o_end)
+    {
+      ::new (static_cast<void*>(etl::addressof(*o_begin))) value_type;
+      ++o_begin;
+    }
+  }
+
+  //*****************************************************************************
+  /// Default initialises a range of objects to uninitialised memory.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename TCounter>
+  typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, void>::type
+   uninitialized_default_construct(TOutputIterator o_begin, TOutputIterator o_end, TCounter& count)
+  {
+    count = std::distance(o_begin, o_end);
+  }
+
+  //*****************************************************************************
+  /// Default initialises a range of objects to uninitialised memory.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename TCounter>
+  typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, void>::type
+   uninitialized_default_construct(TOutputIterator o_begin, TOutputIterator o_end, TCounter& count)
+  {
+    count += std::distance(o_begin, o_end);
+
+    etl::uninitialized_default_construct(o_begin, o_end);
+  }
+
+  //*****************************************************************************
+  /// Default initialises N objects to uninitialised memory.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename TSize>
+  typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
+   uninitialized_default_construct_n(TOutputIterator o_begin, TSize n)
+  {
+    TOutputIterator o_end = o_begin + n;
+
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Default initialises N objects to uninitialised memory.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename TSize>  
+  typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
+   uninitialized_default_construct_n(TOutputIterator o_begin, TSize n)
+  {
+    TOutputIterator o_end = o_begin + n;
+
+    etl::uninitialized_default_construct(o_begin, o_end);
+
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Default initialises N objects to uninitialised memory.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename TSize, typename TCounter>
+  typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
+   uninitialized_default_construct_n(TOutputIterator o_begin, TSize n, TCounter& count)
+  {
+    TOutputIterator o_end = o_begin + n;
+
+    count += n;
+
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Default initialises N objects to uninitialised memory.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename TSize, typename TCounter>
+  typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type
+   uninitialized_default_construct_n(TOutputIterator o_begin, TSize n, TCounter& count)
+  {
+    TOutputIterator o_end = o_begin + n;
+
+    etl::uninitialized_default_construct(o_begin, o_end);
+
+    count += n;
+
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Value construct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T>
+  inline void create_value_at(T* p)
+  {
+    ::new (p) T();
+  }
+
+  //*****************************************************************************
+  /// Value construct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T, typename TCounter>
+  inline void create_value_at(T* p, TCounter& count)
+  {
+    ::new (p) T();
+    ++count;
+  }
+
+  //*****************************************************************************
+  /// Copy construct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T>
+  inline void create_copy_at(T* p, const T& value)
+  {
+    ::new (p) T(value);
+  }
+
+  //*****************************************************************************
+  /// Copy construct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T, typename TCounter>
+  inline void create_copy_at(T* p, const T& value, TCounter& count)
+  {
+    ::new (p) T(value);
+    ++count;
+  }
+
+  //*****************************************************************************
+  /// Construct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T>
+  inline T& make_default_at(T* p)
+  {
+    ::new (p) T();
+    return *reinterpret_cast<T*>(p);
+  }
+
+  //*****************************************************************************
+  /// Construct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T, typename TCounter>
+  inline T& make_default_at(T* p, TCounter& count)
+  {
+    ::new (p) T();
+    ++count;
+    return *reinterpret_cast<T*>(p);
+  }
+
+  //*****************************************************************************
+  /// Construct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T>
+  inline T& make_copy_at(T* p, const T& other)
+  {
+    ::new (p) T(other);
+    return *reinterpret_cast<T*>(p);
+  }
+
+  //*****************************************************************************
+  /// Construct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T, typename TCounter>
+  inline T& make_copy_at(T* p, const T& other, TCounter& count)
+  {
+    ::new (p) T(other);
+    ++count;
+    return *reinterpret_cast<T*>(p);
+  }
+
+  //*****************************************************************************
+  /// Construct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T, typename TParameter>
+  inline T& make_value_at(T* p, const TParameter& value)
+  {
+    ::new (p) T(value);
+    return *reinterpret_cast<T*>(p);
+  }
+
+  //*****************************************************************************
+  /// Construct an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T, typename TParameter, typename TCounter>
+  inline T& make_value_at(T* p, const TParameter& value, TCounter& count)
+  {
+    ::new (p) T(value);
+    ++count;
+    return *reinterpret_cast<T*>(p);
+  }
+
+  //*****************************************************************************
+  /// Default initialises a range of objects to uninitialised memory.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator>
+  typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, void>::type
+   uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end)
+  {
+    typedef typename std::iterator_traits<TOutputIterator>::value_type value_type;
+
+    std::fill(o_begin, o_end, value_type());
+  }
+
+  //*****************************************************************************
+  /// Default initialises a range of objects to uninitialised memory.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator>
+  typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, void>::type
+   uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end)
+  {
+    typedef typename std::iterator_traits<TOutputIterator>::value_type value_type;
+
+    while (o_begin != o_end)
+    {
+      ::new (static_cast<void*>(etl::addressof(*o_begin))) value_type();
+      ++o_begin;
+    }
+  }
+
+  //*****************************************************************************
+  /// Default initialises a range of objects to uninitialised memory.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename TCounter>
+  void uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end, TCounter& count)
+  {
+    count += std::distance(o_begin, o_end);
+
+    etl::uninitialized_value_construct(o_begin, o_end);
+  }
+
+  //*****************************************************************************
+  /// Default initialises N objects to uninitialised memory.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename TSize>
+  TOutputIterator uninitialized_value_construct_n(TOutputIterator o_begin, TSize n)
+  {
+    TOutputIterator o_end = o_begin + n;
+
+    etl::uninitialized_value_construct(o_begin, o_end);
+
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Default initialises N objects to uninitialised memory.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TOutputIterator, typename TSize, typename TCounter>
+  TOutputIterator uninitialized_value_construct_n(TOutputIterator o_begin, TSize n, TCounter& count)
+  {
+    TOutputIterator o_end = o_begin + n;
+
+    etl::uninitialized_value_construct(o_begin, o_end);
+
+    count += n;
+
+    return o_end;
+  }
+
+  //*****************************************************************************
+  /// Destroys an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T>
+  typename etl::enable_if<etl::is_trivially_destructible<T>::value, void>::type
+   destroy_at(T* /*p*/)
+  {
+  }
+
+  //*****************************************************************************
+  /// Destroys an item at address p.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T>
+  typename etl::enable_if<!etl::is_trivially_destructible<T>::value, void>::type
+   destroy_at(T* p)
+  {
+    p->~T();
+  }
+
+  //*****************************************************************************
+  /// Destroys an item at address p.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T, typename TCounter>
+  typename etl::enable_if<etl::is_trivially_destructible<T>::value, void>::type
+   destroy_at(T* /*p*/, TCounter& count)
+  {
+    --count;
+  }
+
+  //*****************************************************************************
+  /// Destroys an item at address p.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T, typename TCounter>
+  typename etl::enable_if<!etl::is_trivially_destructible<T>::value, void>::type
+   destroy_at(T* p, TCounter& count)
+  {
+    p->~T();
+    --count;
+  }
+
+  //*****************************************************************************
+  /// Destroys a range of items.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TIterator>
+  typename etl::enable_if<etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, void>::type
+   destroy(TIterator /*i_begin*/, TIterator /*i_end*/)
+  {
+  }
+
+  //*****************************************************************************
+  /// Destroys a range of items.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TIterator>
+  typename etl::enable_if<!etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, void>::type
+   destroy(TIterator i_begin, TIterator i_end)
+  {
+    while (i_begin != i_end)
+    {
+      etl::destroy_at(etl::addressof(*i_begin));
+      ++i_begin;
+    }
+  }
+
+  //*****************************************************************************
+  /// Destroys a range of items.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TIterator, typename TCounter>
+  typename etl::enable_if<etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, void>::type
+   destroy(TIterator i_begin, TIterator i_end, TCounter& count)
+  {
+    count -= std::distance(i_begin, i_end);
+  }
+
+  //*****************************************************************************
+  /// Destroys a range of items.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TIterator, typename TCounter>
+  typename etl::enable_if<!etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, void>::type
+   destroy(TIterator i_begin, TIterator i_end, TCounter& count)
+  {
+    count -= std::distance(i_begin, i_end);
+
+    while (i_begin != i_end)
+    {
+      etl::destroy_at(etl::addressof(*i_begin));
+      ++i_begin;
+    }
+  }
+
+  //*****************************************************************************
+  /// Destroys a number of items.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TIterator, typename TSize>
+  typename etl::enable_if<etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, TIterator>::type
+   destroy_n(TIterator i_begin, TSize n)
+  {
+    return i_begin + n;
+  }
+
+  //*****************************************************************************
+  /// Destroys a number of items.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TIterator, typename TSize>
+  typename etl::enable_if<!etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, TIterator>::type
+   destroy_n(TIterator i_begin, TSize n)
+  {
+    while (n > 0)
+    {
+      etl::destroy_at(etl::addressof(*i_begin));
+      ++i_begin;
+      --n;
+    }
+
+    return i_begin;
+  }
+
+  //*****************************************************************************
+  /// Destroys a number of items.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TIterator, typename TSize, typename TCounter>
+  typename etl::enable_if<etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, TIterator>::type
+   destroy_n(TIterator i_begin, TSize n, TCounter& count)
+  {
+    count -= n;
+    return i_begin + n;
+  }
+
+  //*****************************************************************************
+  /// Destroys a number of items.
+  /// Debug counter version.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename TIterator, typename TSize, typename TCounter>
+  typename etl::enable_if<!etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, TIterator>::type
+   destroy_n(TIterator i_begin, TSize n, TCounter& count)
+  {
+    count -= n;
+
+    while (n > 0)
+    {
+      etl::destroy_at(etl::addressof(*i_begin));
+      ++i_begin;
+      --n;
+    }
+
+    return i_begin;
+  }
+
+  //*****************************************************************************
+  /// Copy constructs a derived class to an address.
+  ///\tparam T The derived type.
+  ///\ingroup memory
+  //*****************************************************************************
+  template <typename T>
+  struct create_copy
+  {
+    void create_copy_at(void* p)
+    {
+      new (p) T(static_cast<const T&>(*this));
+    }
+
+    template <typename TCounter>
+    void create_copy_at(void* p, TCounter& count)
+    {
+      new (p) T(static_cast<const T&>(*this));
+      ++count;
+    }
+
+    T& make_copy_at(void* p)
+    {
+      new (p) T(static_cast<const T&>(*this));
+      return *reinterpret_cast<T*>(p);
+    }
+
+    template <typename TCounter>
+    T& make_copy_at(void* p, TCounter& count)
+    {
+      new (p) T(static_cast<const T&>(*this));
+      ++count;
+      return *reinterpret_cast<T*>(p);
+    }
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/message.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,106 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_MESSAGE__
+#define __ETL_MESSAGE__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "message_types.h"
+
+#undef ETL_FILE
+#define ETL_FILE "38"
+
+namespace etl
+{
+  //***************************************************************************
+  class message_exception : public etl::exception
+  {
+  public:
+
+    message_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  class unhandled_message_exception : public etl::message_exception
+  {
+  public:
+
+    unhandled_message_exception(string_type file_name_, numeric_type line_number_)
+      : message_exception(ETL_ERROR_TEXT("message:unknown", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  class imessage
+  {
+  public:
+
+#ifdef ETL_MESSAGES_ARE_VIRTUAL
+    virtual ~imessage()
+    {
+    }
+#endif
+
+    imessage(etl::message_id_t id) 
+      : message_id(id)
+    {
+    }
+
+    const etl::message_id_t message_id;
+  };
+
+  //***************************************************************************
+  template <const etl::message_id_t ID_>
+  class message : public imessage
+  {
+  public:
+
+    message()
+      : imessage(ID_)
+    {
+    }
+
+    enum
+    {
+      ID = ID_
+    };
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/message_bus.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,391 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_MESSAGE_BUS_
+#define __ETL_MESSAGE_BUS_
+
+#include <stdint.h>
+#include <algorithm>
+
+#include "platform.h"
+#include "algorithm.h"
+#include "vector.h"
+#include "nullptr.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "message_types.h"
+#include "message.h"
+#include "message_router.h"
+
+#undef ETL_FILE
+#define ETL_FILE "39"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Base exception class for message bus
+  //***************************************************************************
+  class message_bus_exception : public etl::exception
+  {
+  public:
+
+    message_bus_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Too many subscribers.
+  //***************************************************************************
+  class message_bus_too_many_subscribers : public etl::message_bus_exception
+  {
+  public:
+
+    message_bus_too_many_subscribers(string_type file_name_, numeric_type line_number_)
+      : message_bus_exception(ETL_ERROR_TEXT("message bus:too many subscribers", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Interface for message bus
+  //***************************************************************************
+  class imessage_bus : public etl::imessage_router
+  {
+  private:
+
+    typedef etl::ivector<etl::imessage_router*> router_list_t;
+
+  public:
+
+    using etl::imessage_router::receive;
+
+    //*******************************************
+    /// Subscribe to the bus.
+    //*******************************************
+    bool subscribe(etl::imessage_router& router)
+    {
+      bool ok = true;
+
+      // There's no point actually adding null routers.
+      if (!router.is_null_router())
+      {
+        ok = !router_list.full();
+
+        ETL_ASSERT(ok, ETL_ERROR(etl::message_bus_too_many_subscribers));
+
+        if (ok)
+        {
+          if (router.is_bus())
+          {
+            // Message busses get added to the end.
+            router_list.push_back(&router);
+          }
+          else
+          {
+            // Routers get added in id order.
+            router_list_t::iterator irouter = std::upper_bound(router_list.begin(),
+                                                               router_list.end(),
+                                                               router.get_message_router_id(),
+                                                               compare_router_id());
+
+            router_list.insert(irouter, &router);
+          }
+        }
+      }
+
+      return ok;
+    }
+
+    //*******************************************
+    /// Unsubscribe from the bus.
+    //*******************************************
+    void unsubscribe(etl::message_router_id_t id)
+    {
+      if (id == etl::imessage_bus::ALL_MESSAGE_ROUTERS)
+      {
+        clear();
+      }
+      else
+      {
+        std::pair<router_list_t::iterator, router_list_t::iterator> range = std::equal_range(router_list.begin(),
+                                                                                             router_list.end(),
+                                                                                             id,
+                                                                                             compare_router_id());
+
+        router_list.erase(range.first, range.second);
+      }
+    }
+
+    //*******************************************
+    void unsubscribe(etl::imessage_router& router)
+    {
+      router_list_t::iterator irouter = std::find(router_list.begin(),
+                                                  router_list.end(),
+                                                  &router);
+
+      if (irouter != router_list.end())
+      {
+        router_list.erase(irouter);
+      }
+    }
+
+    //*******************************************
+    void receive(const etl::imessage& message)
+    {
+      etl::null_message_router nmr;
+      receive(nmr, etl::imessage_router::ALL_MESSAGE_ROUTERS, message);
+    }
+
+    //*******************************************
+    void receive(etl::message_router_id_t destination_router_id,
+                 const etl::imessage&     message)
+    {
+      etl::null_message_router nmr;
+      receive(nmr, destination_router_id, message);
+    }
+
+    //*******************************************
+    void receive(etl::imessage_router& source,
+                 const etl::imessage&  message)
+    {
+      receive(source, etl::imessage_router::ALL_MESSAGE_ROUTERS, message);
+    }
+
+    //*******************************************
+    void receive(etl::imessage_router&    source,
+                 etl::message_router_id_t destination_router_id,
+                 const etl::imessage&     message)
+    {
+      switch (destination_router_id)
+      {
+        //*****************************
+        // Null message router. These routers can never be subscribed.
+        case etl::imessage_router::NULL_MESSAGE_ROUTER:
+        {
+          break;
+        }
+
+        //*****************************
+        // Broadcast to all routers.
+        case etl::imessage_router::ALL_MESSAGE_ROUTERS:
+        {
+          router_list_t::iterator irouter = router_list.begin();
+
+          // Broadcast to everyone.
+          while (irouter != router_list.end())
+          {
+            etl::imessage_router& router = **irouter;
+
+            if (router.is_bus())
+            {
+              // The router is actually a bus.
+              etl::imessage_bus& bus = static_cast<etl::imessage_bus&>(router);
+
+              // So pass it on.
+              bus.receive(source, destination_router_id, message);
+            }
+            else if (router.accepts(message.message_id))
+            {
+              router.receive(source, message);
+            }
+
+            ++irouter;
+          }
+
+          break;
+        }
+
+        //*****************************
+        // Must be an addressed message.
+        default:
+        {
+          router_list_t::iterator irouter = router_list.begin();
+
+          // Find routers with the id.
+          std::pair<router_list_t::iterator, router_list_t::iterator> range = std::equal_range(router_list.begin(),
+                                                                                               router_list.end(),
+                                                                                               destination_router_id,
+                                                                                               compare_router_id());
+
+          // Call all of them.
+          while (range.first != range.second)
+          {
+            if ((*(range.first))->accepts(message.message_id))
+            {
+              (*(range.first))->receive(source, message);
+            }
+
+            ++range.first;
+          }
+
+          // Do any message buses.
+          // These are always at the end of the list.
+          irouter = std::lower_bound(router_list.begin(),
+                                     router_list.end(),
+                                     etl::imessage_bus::MESSAGE_BUS,
+                                     compare_router_id());
+
+          while (irouter != router_list.end())
+          {
+            // The router is actually a bus.
+            etl::imessage_bus& bus = static_cast<etl::imessage_bus&>(**irouter);
+
+            // So pass it on.
+            bus.receive(source, destination_router_id, message);
+
+            ++irouter;
+          }
+
+          break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //*******************************************
+    /// Does this message bus accept the message id?
+    /// Yes!, it accepts everything!
+    //*******************************************
+    bool accepts(etl::message_id_t) const
+    {
+      return true;
+    }
+
+    //*******************************************
+    size_t size() const
+    {
+      return router_list.size();
+    }
+
+    //*******************************************
+    void clear()
+    {
+      return router_list.clear();
+    }
+
+  protected:
+
+    //*******************************************
+    /// Constructor.
+    //*******************************************
+    imessage_bus(router_list_t& list)
+      : imessage_router(etl::imessage_router::MESSAGE_BUS),
+        router_list(list)
+    {
+    }
+
+  private:
+
+    //*******************************************
+    // How to compare routers to router ids.
+    //*******************************************
+    struct compare_router_id
+    {
+      bool operator()(const etl::imessage_router* prouter, etl::message_router_id_t id) const
+      {
+        return prouter->get_message_router_id() < id;
+      }
+
+      bool operator()(etl::message_router_id_t id, const etl::imessage_router* prouter) const
+      {
+        return id < prouter->get_message_router_id();
+      }
+    };
+
+    router_list_t& router_list;
+  };
+
+  //***************************************************************************
+  /// The message bus
+  //***************************************************************************
+  template <uint_least8_t MAX_ROUTERS_>
+  class message_bus : public etl::imessage_bus
+  {
+  public:
+
+    //*******************************************
+    /// Constructor.
+    //*******************************************
+    message_bus()
+      : imessage_bus(router_list)
+    {
+    }
+
+  private:
+
+    etl::vector<etl::imessage_router*, MAX_ROUTERS_> router_list;
+  };
+
+  //***************************************************************************
+  /// Send a message to a bus.
+  //***************************************************************************
+  inline static void send_message(etl::imessage_bus&   bus,
+                                  const etl::imessage& message)
+  {
+    bus.receive(message);
+  }
+
+  //***************************************************************************
+  /// Send a message to a bus.
+  //***************************************************************************
+  inline static void send_message(etl::imessage_bus&       bus,
+                                  etl::message_router_id_t id,
+                                  const etl::imessage&     message)
+  {
+    bus.receive(id, message);
+  }
+
+  //***************************************************************************
+  /// Send a message to a bus.
+  //***************************************************************************
+  inline static void send_message(etl::imessage_router& source,
+                                  etl::imessage_bus&    bus,
+                                  const etl::imessage&  message)
+  {
+    bus.receive(source, message);
+  }
+
+  //***************************************************************************
+  /// Send a message to a bus.
+  //***************************************************************************
+  inline static void send_message(etl::imessage_router&    source,
+                                  etl::imessage_bus&       bus,
+                                  etl::message_router_id_t id,
+                                  const etl::imessage&     message)
+  {
+    bus.receive(source, id, message);
+  }
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/message_router.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,2531 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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.
+******************************************************************************/
+
+#if 0
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+#endif
+
+//***************************************************************************
+// This file has been auto generated. Do not edit this file.
+//***************************************************************************
+
+//***************************************************************************
+// To generate to header file, run this at the command line.
+// Note: You will need Python and COG installed.
+//
+// python -m cogapp -d -e -omessage_router.h -DHandlers=<n> message_router_generator.h 
+// Where <n> is the number of messages to support.
+//
+// e.g.
+// To generate handlers for up to 16 messages...
+// python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h 
+//
+// See generate.bat
+//***************************************************************************
+
+#ifndef __ETL_MESSAGE_ROUTER__
+#define __ETL_MESSAGE_ROUTER__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "message.h"
+#include "message_types.h"
+#include "alignment.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "largest.h"
+#include "nullptr.h"
+
+#undef ETL_FILE
+#define ETL_FILE "35"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Base exception class for message router
+  //***************************************************************************
+  class message_router_exception : public etl::exception
+  {
+  public:
+
+    message_router_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Router id is out of the legal range.
+  //***************************************************************************
+  class message_router_illegal_id : public etl::message_router_exception
+  {
+  public:
+
+    message_router_illegal_id(string_type file_name_, numeric_type line_number_)
+      : message_router_exception(ETL_ERROR_TEXT("message router:illegal id", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  class imessage_router
+  {
+  public:
+
+    virtual ~imessage_router() {}
+    virtual void receive(const etl::imessage& message) = 0;
+    virtual void receive(imessage_router& source, const etl::imessage& message) = 0;
+    virtual bool accepts(etl::message_id_t id) const = 0;
+
+    //********************************************
+    bool accepts(const etl::imessage& msg) const
+    {
+      return accepts(msg.message_id);
+    }
+
+    //********************************************
+    etl::message_router_id_t get_message_router_id() const
+    {
+      return message_router_id;
+    }
+
+    //********************************************
+    bool is_null_router() const
+    {
+      return (message_router_id == NULL_MESSAGE_ROUTER);
+    }
+
+    //********************************************
+    bool is_bus() const
+    {
+      return (message_router_id == MESSAGE_BUS);
+    }
+
+    //********************************************
+    void set_successor(imessage_router& successor_)
+    {
+      successor = &successor_;
+    }
+
+    //********************************************
+    imessage_router& get_successor() const
+    {
+      return *successor;
+    }
+
+    //********************************************
+    bool has_successor() const
+    {
+      return (successor != nullptr);
+    }
+
+    enum
+    {
+      NULL_MESSAGE_ROUTER = 255,
+      MESSAGE_BUS         = 254,
+      ALL_MESSAGE_ROUTERS = 253,
+      MAX_MESSAGE_ROUTER  = 249
+    };
+
+  protected:
+
+    imessage_router(etl::message_router_id_t id_)
+      : successor(nullptr),
+        message_router_id(id_)
+    {
+    }
+
+    imessage_router(etl::message_router_id_t id_, 
+                    imessage_router&         successor_)
+      : successor(&successor_),
+        message_router_id(id_)        
+    {
+    }
+
+  private:
+
+    // Disabled.
+    imessage_router(const imessage_router&);
+    imessage_router& operator =(const imessage_router&);
+
+    etl::imessage_router* successor;
+
+    etl::message_router_id_t  message_router_id;
+  };
+
+  //***************************************************************************
+  /// This router can be used either as a sink for messages
+  /// or as a producer-only of messages such an interrupt routine.
+  //***************************************************************************
+  class null_message_router : public imessage_router
+  {
+  public:
+
+    null_message_router()
+      : imessage_router(imessage_router::NULL_MESSAGE_ROUTER)
+    {
+    }
+
+    //********************************************
+    void receive(const etl::imessage&)
+    {
+    }
+
+    //********************************************
+    void receive(etl::imessage_router&, const etl::imessage&)
+    {
+    }
+
+    //********************************************
+    bool accepts(etl::message_id_t) const
+    {
+      return false;
+    }
+
+    //********************************************
+    static null_message_router& instance()
+    {
+      static null_message_router nmr;
+      return nmr;
+    }
+  };
+
+  //***************************************************************************
+  /// Send a message to a router.
+  /// Sets the 'sender' to etl::null_message_router type.
+  //***************************************************************************
+  inline static void send_message(etl::imessage_router& destination, 
+                                  const etl::imessage&  message)
+  {
+    destination.receive(message);
+  }
+
+  //***************************************************************************
+  /// Send a message to a router.
+  //***************************************************************************
+  inline static void send_message(etl::imessage_router& source, 
+                                  etl::imessage_router& destination, 
+                                  const etl::imessage&  message)
+  {
+    destination.receive(source, message);
+  }
+  
+  //***************************************************************************
+  // The definition for all 16 message types.
+  //***************************************************************************
+  template <typename TDerived,
+            typename T1, typename T2 = void, typename T3 = void, typename T4 = void, 
+            typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, 
+            typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, 
+            typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
+  class message_router  : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break;
+          case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break;
+          case T13::ID: ::new (p) T13(static_cast<const T13&>(msg)); break;
+          case T14::ID: ::new (p) T14(static_cast<const T14&>(msg)); break;
+          case T15::ID: ::new (p) T15(static_cast<const T15&>(msg)); break;
+          case T16::ID: ::new (p) T16(static_cast<const T16&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const etl::message_id_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break;
+        case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break;
+        case T13::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T13&>(msg)); break;
+        case T14::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T14&>(msg)); break;
+        case T15::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T15&>(msg)); break;
+        case T16::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T16&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: case T16::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 15 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11, typename T12, 
+            typename T13, typename T14, typename T15>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break;
+          case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break;
+          case T13::ID: ::new (p) T13(static_cast<const T13&>(msg)); break;
+          case T14::ID: ::new (p) T14(static_cast<const T14&>(msg)); break;
+          case T15::ID: ::new (p) T15(static_cast<const T15&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break;
+        case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break;
+        case T13::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T13&>(msg)); break;
+        case T14::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T14&>(msg)); break;
+        case T15::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T15&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 14 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11, typename T12, 
+            typename T13, typename T14>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break;
+          case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break;
+          case T13::ID: ::new (p) T13(static_cast<const T13&>(msg)); break;
+          case T14::ID: ::new (p) T14(static_cast<const T14&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break;
+        case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break;
+        case T13::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T13&>(msg)); break;
+        case T14::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T14&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 13 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11, typename T12, 
+            typename T13>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break;
+          case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break;
+          case T13::ID: ::new (p) T13(static_cast<const T13&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break;
+        case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break;
+        case T13::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T13&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 12 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11, typename T12>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break;
+          case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break;
+        case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: case T11::ID: case T12::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 11 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: case T11::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 10 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 9 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 8 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 7 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 6 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, void, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 5 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5>
+  class message_router<TDerived, T1, T2, T3, T4, T5, void, void, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 4 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4>
+  class message_router<TDerived, T1, T2, T3, T4, void, void, void, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 3 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3>
+  class message_router<TDerived, T1, T2, T3, void, void, void, void, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 2 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2>
+  class message_router<TDerived, T1, T2, void, void, void, void, void, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2>::size,
+        ALIGNMENT = etl::largest<T1, T2>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 1 message type.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1>
+  class message_router<TDerived, T1, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1>::size,
+        ALIGNMENT = etl::largest<T1>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
+      : imessage_router(id_, successor_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/message_router_generator.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,589 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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.
+******************************************************************************/
+
+/*[[[cog
+import cog
+cog.outl("#if 0")
+]]]*/
+/*[[[end]]]*/
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+/*[[[cog
+import cog
+cog.outl("#endif")
+]]]*/
+/*[[[end]]]*/
+
+/*[[[cog
+import cog
+cog.outl("//***************************************************************************")
+cog.outl("// This file has been auto generated. Do not edit this file.")
+cog.outl("//***************************************************************************")
+]]]*/
+/*[[[end]]]*/
+
+//***************************************************************************
+// To generate to header file, run this at the command line.
+// Note: You will need Python and COG installed.
+//
+// python -m cogapp -d -e -omessage_router.h -DHandlers=<n> message_router_generator.h 
+// Where <n> is the number of messages to support.
+//
+// e.g.
+// To generate handlers for up to 16 messages...
+// python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h 
+//
+// See generate.bat
+//***************************************************************************
+
+#ifndef __ETL_MESSAGE_ROUTER__
+#define __ETL_MESSAGE_ROUTER__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "message.h"
+#include "message_types.h"
+#include "alignment.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "largest.h"
+#include "nullptr.h"
+
+#undef ETL_FILE
+#define ETL_FILE "35"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Base exception class for message router
+  //***************************************************************************
+  class message_router_exception : public etl::exception
+  {
+  public:
+
+    message_router_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Router id is out of the legal range.
+  //***************************************************************************
+  class message_router_illegal_id : public etl::message_router_exception
+  {
+  public:
+
+    message_router_illegal_id(string_type file_name_, numeric_type line_number_)
+      : message_router_exception(ETL_ERROR_TEXT("message router:illegal id", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  class imessage_router
+  {
+  public:
+
+    virtual ~imessage_router() {}
+    virtual void receive(const etl::imessage& message) = 0;
+    virtual void receive(imessage_router& source, const etl::imessage& message) = 0;
+    virtual bool accepts(etl::message_id_t id) const = 0;
+
+    //********************************************
+    bool accepts(const etl::imessage& msg) const
+    {
+      return accepts(msg.message_id);
+    }
+
+    //********************************************
+    etl::message_router_id_t get_message_router_id() const
+    {
+      return message_router_id;
+    }
+
+    //********************************************
+    bool is_null_router() const
+    {
+      return (message_router_id == NULL_MESSAGE_ROUTER);
+    }
+
+    //********************************************
+    bool is_bus() const
+    {
+      return (message_router_id == MESSAGE_BUS);
+    }
+
+    //********************************************
+    void set_successor(imessage_router& successor_)
+    {
+      successor = &successor_;
+    }
+
+    //********************************************
+    imessage_router& get_successor() const
+    {
+      return *successor;
+    }
+
+    //********************************************
+    bool has_successor() const
+    {
+      return (successor != std::nullptr);
+    }
+
+    enum
+    {
+      NULL_MESSAGE_ROUTER = 255,
+      MESSAGE_BUS         = 254,
+      ALL_MESSAGE_ROUTERS = 253,
+      MAX_MESSAGE_ROUTER  = 249
+    };
+
+  protected:
+
+    imessage_router(etl::message_router_id_t id_)
+      : successor(std::nullptr),
+        message_router_id(id_)
+    {
+    }
+
+    imessage_router(etl::message_router_id_t id_, 
+                    imessage_router&         successor_)
+      : successor(&successor_),
+        message_router_id(id_)        
+    {
+    }
+
+  private:
+
+    // Disabled.
+    imessage_router(const imessage_router&);
+    imessage_router& operator =(const imessage_router&);
+
+    etl::imessage_router* successor;
+
+    etl::message_router_id_t  message_router_id;
+  };
+
+  //***************************************************************************
+  /// This router can be used either as a sink for messages
+  /// or as a producer-only of messages such an interrupt routine.
+  //***************************************************************************
+  class null_message_router : public imessage_router
+  {
+  public:
+
+    null_message_router()
+      : imessage_router(imessage_router::NULL_MESSAGE_ROUTER)
+    {
+    }
+
+    //********************************************
+    void receive(const etl::imessage&)
+    {
+    }
+
+    //********************************************
+    void receive(etl::imessage_router&, const etl::imessage&)
+    {
+    }
+
+    //********************************************
+    bool accepts(etl::message_id_t) const
+    {
+      return false;
+    }
+
+    //********************************************
+    static null_message_router& instance()
+    {
+      static null_message_router nmr;
+      return nmr;
+    }
+  };
+
+  //***************************************************************************
+  /// Send a message to a router.
+  /// Sets the 'sender' to etl::null_message_router type.
+  //***************************************************************************
+  inline static void send_message(etl::imessage_router& destination, 
+                                  const etl::imessage&  message)
+  {
+    destination.receive(message);
+  }
+
+  //***************************************************************************
+  /// Send a message to a router.
+  //***************************************************************************
+  inline static void send_message(etl::imessage_router& source, 
+                                  etl::imessage_router& destination, 
+                                  const etl::imessage&  message)
+  {
+    destination.receive(source, message);
+  }
+  
+  /*[[[cog
+      import cog
+      ################################################
+      # The first definition for all of the messages.
+      ################################################
+      cog.outl("//***************************************************************************")
+      cog.outl("// The definition for all %s message types." % Handlers)
+      cog.outl("//***************************************************************************")
+      cog.outl("template <typename TDerived,")
+      cog.out("          ")
+      cog.out("typename T1, ")
+      for n in range(2, int(Handlers)):
+          cog.out("typename T%s = void, " % n)
+          if n % 4 == 0:
+              cog.outl("")
+              cog.out("          ")
+      cog.outl("typename T%s = void>" % int(Handlers))
+      cog.out("class message_router")
+      cog.outl("  : public imessage_router")
+      cog.outl("{")
+      cog.outl("public:")
+      cog.outl("")
+      cog.outl("  //**********************************************")
+      cog.outl("  class message_packet")
+      cog.outl("  {")
+      cog.outl("  public:")
+      cog.outl("")
+      cog.outl("    //********************************************")
+      cog.outl("    explicit message_packet(const etl::imessage& msg)")
+      cog.outl("    {")
+      cog.outl("      const size_t id = msg.message_id;")
+      cog.outl("")
+      cog.outl("      void* p = data;")
+      cog.outl("")
+      cog.outl("      switch (id)")
+      cog.outl("      {")
+      for n in range(1, int(Handlers) + 1):
+          cog.outl("        case T%s::ID: ::new (p) T%s(static_cast<const T%s&>(msg)); break;" % (n, n, n))
+      cog.outl("        default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;")
+      cog.outl("      }")
+      cog.outl("    }")
+      cog.outl("")      
+      cog.outl("    //********************************************")
+      cog.outl("    template <typename T>")
+      cog.outl("    explicit message_packet(const T& msg)")
+      cog.outl("    {")
+      cog.out("      STATIC_ASSERT((etl::is_one_of<T, ")
+      for n in range(1, int(Handlers)):
+          cog.out("T%s, " % n)
+          if n % 16 == 0:
+              cog.outl("")
+              cog.out("                                       ")
+      cog.outl("""T%s>::value), "Unsupported type for this message packet");""" % int(Handlers))
+      cog.outl("")
+      cog.outl("      void* p = data;")
+      cog.outl("      ::new (p) T(static_cast<const T&>(msg));")
+      cog.outl("    }")
+      cog.outl("")
+      cog.outl("    //********************************************")
+      cog.outl("    ~message_packet()")
+      cog.outl("    {")
+      cog.outl("      static_cast<etl::imessage*>(data)->~imessage();")
+      cog.outl("    }")
+      cog.outl("")
+      cog.outl("    //********************************************")
+      cog.outl("    etl::imessage& get()")
+      cog.outl("    {")
+      cog.outl("      return *static_cast<etl::imessage*>(data);")
+      cog.outl("    }")
+      cog.outl("")
+      cog.outl("    //********************************************")
+      cog.outl("    const etl::imessage& get() const")
+      cog.outl("    {")
+      cog.outl("      return *static_cast<const etl::imessage*>(data);")
+      cog.outl("    }")
+      cog.outl("")
+      cog.outl("    enum")
+      cog.outl("    {")
+      cog.out("      SIZE      = etl::largest<")
+      for n in range(1, int(Handlers)):
+          cog.out("T%s, " % n)
+      cog.outl("T%s>::size," % int(Handlers))
+      cog.out("      ALIGNMENT = etl::largest<")
+      for n in range(1, int(Handlers)):
+          cog.out("T%s, " % n)
+      cog.outl("T%s>::alignment" % int(Handlers))
+      cog.outl("    };")
+      cog.outl("")
+      cog.outl("  private:")
+      cog.outl("")
+      cog.outl("    typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;")
+      cog.outl("  };")
+      cog.outl("")
+      cog.outl("  //**********************************************")
+      cog.outl("  message_router(etl::message_router_id_t id_)")
+      cog.outl("    : imessage_router(id_)")
+      cog.outl("  {")
+      cog.outl("    ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));")
+      cog.outl("  }")
+      cog.outl("")
+      cog.outl("  //**********************************************")
+      cog.outl("  message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)")
+      cog.outl("    : imessage_router(id_, successor_)")
+      cog.outl("  {")
+      cog.outl("    ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));")
+      cog.outl("  }")
+      cog.outl("")
+      cog.outl("  //**********************************************")
+      cog.outl("  void receive(const etl::imessage& msg)")
+      cog.outl("  {")
+      cog.outl("    receive(etl::null_message_router::instance(), msg);")
+      cog.outl("  }")
+      cog.outl("")
+      cog.outl("  //**********************************************")
+      cog.outl("  void receive(etl::imessage_router& source, const etl::imessage& msg)")
+      cog.outl("  {")
+      cog.outl("    const etl::message_id_t id = msg.message_id;")
+      cog.outl("")
+      cog.outl("    switch (id)")
+      cog.outl("    {")
+      for n in range(1, int(Handlers) + 1):
+          cog.out("      case T%d::ID:" % n)
+          cog.out(" static_cast<TDerived*>(this)->on_receive(source, static_cast<const T%d&>(msg));" % n)
+          cog.outl(" break;")
+      cog.outl("      default:")
+      cog.outl("      {")
+      cog.outl("         if (has_successor())")
+      cog.outl("         {")
+      cog.outl("           get_successor().receive(source, msg);")
+      cog.outl("         }")
+      cog.outl("         else")
+      cog.outl("         {")
+      cog.outl("           static_cast<TDerived*>(this)->on_receive_unknown(source, msg);")
+      cog.outl("         }")
+      cog.outl("         break;")
+      cog.outl("      }")
+      cog.outl("    }")
+      cog.outl("  }")
+      cog.outl("")
+      cog.outl("  using imessage_router::accepts;")
+      cog.outl("")
+      cog.outl("  //**********************************************")
+      cog.outl("  bool accepts(etl::message_id_t id) const")
+      cog.outl("  {")
+      cog.outl("    switch (id)")
+      cog.outl("    {")
+      cog.out("      ")
+      for n in range(1, int(Handlers) + 1):
+          cog.out("case T%d::ID: " % n)
+          if n % 8 == 0:
+              cog.outl("")
+              cog.out("      ")
+      cog.outl("  return true; break;")
+      cog.outl("      default:")
+      cog.outl("        return false; break;")
+      cog.outl("    }")
+      cog.outl("  }")
+      cog.outl("};")
+
+      ####################################
+      # All of the other specialisations.
+      ####################################
+      for n in range(int(Handlers) - 1, 0, -1):
+          cog.outl("")
+          cog.outl("//***************************************************************************")
+          if n == 1:
+              cog.outl("// Specialisation for %d message type." % n)
+          else:
+              cog.outl("// Specialisation for %d message types." % n)
+          cog.outl("//***************************************************************************")
+          cog.outl("template <typename TDerived, ")
+          cog.out("          ")
+          for t in range(1, n):
+              cog.out("typename T%d, " % t)
+              if t % 4 == 0:
+                  cog.outl("")
+                  cog.out("          ")
+          cog.outl("typename T%d>" % n)
+          cog.out("class message_router<TDerived, ")
+          for t in range(1, n + 1):
+              cog.out("T%d, " % t)
+              if t % 16 == 0:
+                  cog.outl("")
+                  cog.out("               ")
+          for t in range(n + 1, int(Handlers)):
+              cog.out("void, ")
+              if t % 16 == 0:
+                  cog.outl("")
+                  cog.out("               ")
+          cog.outl("void>")
+          cog.outl(" : public imessage_router")
+          cog.outl("{")
+          cog.outl("public:")
+          cog.outl("")
+          cog.outl("  //**********************************************")
+          cog.outl("  class message_packet")
+          cog.outl("  {")
+          cog.outl("  public:")
+          cog.outl("")
+          cog.outl("    //********************************************")
+          cog.outl("    explicit message_packet(const etl::imessage& msg)")
+          cog.outl("    {")
+          cog.outl("      const size_t id = msg.message_id;")
+          cog.outl("")
+          cog.outl("      void* p = data;")
+          cog.outl("")
+          cog.outl("      switch (id)")
+          cog.outl("      {")
+          for t in range(1, n + 1):
+              cog.outl("        case T%s::ID: ::new (p) T%s(static_cast<const T%s&>(msg)); break;" % (t, t, t))
+          cog.outl("        default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;")
+          cog.outl("      }")
+          cog.outl("    }")
+          cog.outl("")
+          cog.outl("    //********************************************")
+          cog.outl("    template <typename T>")
+          cog.outl("    explicit message_packet(const T& msg)")
+          cog.outl("    {")
+          cog.out("      STATIC_ASSERT((etl::is_one_of<T, ")
+          for t in range(1, n):
+              cog.out("T%s, " % t)
+              if t % 16 == 0:
+                  cog.outl("")
+                  cog.out("                                       ")
+          cog.outl("""T%s>::value), "Unsupported type for this message packet");""" % n)
+          cog.outl("")
+          cog.outl("      void* p = data;")
+          cog.outl("      ::new (p) T(static_cast<const T&>(msg));")
+          cog.outl("    }")
+          cog.outl("")
+          cog.outl("    //********************************************")
+          cog.outl("    ~message_packet()")
+          cog.outl("    {")
+          cog.outl("      static_cast<etl::imessage*>(data)->~imessage();")
+          cog.outl("    }")
+          cog.outl("")
+          cog.outl("    //********************************************")
+          cog.outl("    etl::imessage& get()")
+          cog.outl("    {")
+          cog.outl("      return *static_cast<etl::imessage*>(data);")
+          cog.outl("    }")
+          cog.outl("")
+          cog.outl("    //********************************************")
+          cog.outl("    const etl::imessage& get() const")
+          cog.outl("    {")
+          cog.outl("      return *static_cast<const etl::imessage*>(data);")
+          cog.outl("    }")
+          cog.outl("")
+          cog.outl("    enum")
+          cog.outl("    {")
+          cog.out("      SIZE      = etl::largest<")
+          for t in range(1, n):
+              cog.out("T%s, " % t)
+          cog.outl("T%s>::size," % n)
+          cog.out("      ALIGNMENT = etl::largest<")
+          for t in range(1, n):
+              cog.out("T%s, " % t)
+          cog.outl("T%s>::alignment" % n)
+          cog.outl("    };")
+          cog.outl("")
+          cog.outl("  private:")
+          cog.outl("")
+          cog.outl("    typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;")
+          cog.outl("  };")
+          cog.outl("")
+          cog.outl("  //**********************************************")
+          cog.outl("  message_router(etl::message_router_id_t id_)")
+          cog.outl("    : imessage_router(id_)")
+          cog.outl("  {")
+          cog.outl("    ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));")
+          cog.outl("  }")
+          cog.outl("")
+          cog.outl("  //**********************************************")
+          cog.outl("  message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)")
+          cog.outl("    : imessage_router(id_, successor_)")
+          cog.outl("  {")
+          cog.outl("    ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));")
+          cog.outl("  }")
+          cog.outl("")
+          cog.outl("  //**********************************************")
+          cog.outl("  void receive(const etl::imessage& msg)")
+          cog.outl("  {")
+          cog.outl("    receive(etl::null_message_router::instance(), msg);")
+          cog.outl("  }")
+          cog.outl("")
+          cog.outl("  //**********************************************")
+          cog.outl("  void receive(etl::imessage_router& source, const etl::imessage& msg)")
+          cog.outl("  {")
+          cog.outl("    const size_t id = msg.message_id;")
+          cog.outl("")
+          cog.outl("    switch (id)")
+          cog.outl("    {")
+          for t in range(1, n + 1):
+              cog.out("      case T%d::ID:" % t)
+              cog.out(" static_cast<TDerived*>(this)->on_receive(source, static_cast<const T%d&>(msg));" % t)
+              cog.outl(" break;")
+          cog.outl("      default:")
+          cog.outl("      {")
+          cog.outl("         if (has_successor())")
+          cog.outl("         {")
+          cog.outl("           get_successor().receive(source, msg);")
+          cog.outl("         }")
+          cog.outl("         else")
+          cog.outl("         {")
+          cog.outl("           static_cast<TDerived*>(this)->on_receive_unknown(source, msg);")
+          cog.outl("         }")
+          cog.outl("         break;")
+          cog.outl("      }")
+          cog.outl("    }")
+          cog.outl("  }")
+          cog.outl("")
+          cog.outl("  using imessage_router::accepts;")
+          cog.outl("")
+          cog.outl("  //**********************************************")
+          cog.outl("  bool accepts(etl::message_id_t id) const")
+          cog.outl("  {")
+          cog.outl("    switch (id)")
+          cog.outl("    {")
+          cog.out("      ")
+          for t in range(1, n + 1):
+              cog.out("case T%d::ID: " % t)
+              if t % 8 == 0:
+                  cog.outl("")
+                  cog.out("      ")
+          cog.outl("")
+          cog.outl("        return true; break;")
+          cog.outl("      default:")
+          cog.outl("        return false; break;")
+          cog.outl("    }")
+          cog.outl("  }")
+          cog.outl("};")
+  ]]]*/
+  /*[[[end]]]*/
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/message_timer.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,659 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_MESSAGE_TIMER__
+#define __ETL_MESSAGE_TIMER__
+
+#include <stdint.h>
+#include <algorithm>
+
+#include "platform.h"
+#include "nullptr.h"
+#include "message_types.h"
+#include "message.h"
+#include "message_router.h"
+#include "message_bus.h"
+#include "static_assert.h"
+#include "timer.h"
+#include "atomic.h"
+
+#undef ETL_FILE
+#define ETL_FILE "41"
+
+namespace etl
+{
+  //*************************************************************************
+  /// The configuration of a timer.
+  struct message_timer_data
+  {
+    //*******************************************
+    message_timer_data()
+      : p_message(std::nullptr),
+        p_router(std::nullptr),
+        period(0),
+        delta(etl::timer::state::INACTIVE),
+        destination_router_id(etl::imessage_bus::ALL_MESSAGE_ROUTERS),
+        id(etl::timer::id::NO_TIMER),
+        previous(etl::timer::id::NO_TIMER),
+        next(etl::timer::id::NO_TIMER),
+        repeating(true)
+    {
+    }
+
+    //*******************************************
+    message_timer_data(etl::timer::id::type     id_,
+                       const etl::imessage&     message_,
+                       etl::imessage_router&    irouter_,
+                       uint32_t                 period_,
+                       bool                     repeating_,
+                       etl::message_router_id_t destination_router_id_)
+      : p_message(&message_),
+        p_router(&irouter_),
+        period(period_),
+        delta(etl::timer::state::INACTIVE),
+        id(id_),
+        previous(etl::timer::id::NO_TIMER),
+        next(etl::timer::id::NO_TIMER),
+        repeating(repeating_)
+    {
+      if (irouter_.is_bus())
+      {
+        destination_router_id = destination_router_id_;
+      }
+      else
+      {
+        destination_router_id = etl::imessage_bus::ALL_MESSAGE_ROUTERS;
+      }
+    }
+
+    //*******************************************
+    /// Returns true if the timer is active.
+    //*******************************************
+    bool is_active() const
+    {
+      return delta != etl::timer::state::INACTIVE;
+    }
+
+    //*******************************************
+    /// Sets the timer to the inactive state.
+    //*******************************************
+    void set_inactive()
+    {
+      delta = etl::timer::state::INACTIVE;
+    }
+
+    const etl::imessage*     p_message;
+    etl::imessage_router*    p_router;
+    uint32_t                 period;
+    uint32_t                 delta;
+    etl::message_router_id_t destination_router_id;
+    etl::timer::id::type     id;
+    uint_least8_t            previous;
+    uint_least8_t            next;
+    bool                     repeating;
+
+  private:
+
+    // Disabled.
+    message_timer_data(const message_timer_data& other);
+    message_timer_data& operator =(const message_timer_data& other);
+  };
+
+  namespace __private_message_timer__
+  {
+    //*************************************************************************
+    /// A specialised intrusive linked list for timer data.
+    //*************************************************************************
+    class list
+    {
+    public:
+
+      //*******************************
+      list(etl::message_timer_data* ptimers_)
+        : head(etl::timer::id::NO_TIMER),
+          tail(etl::timer::id::NO_TIMER),
+          current(etl::timer::id::NO_TIMER),
+          ptimers(ptimers_)
+      {
+      }
+
+      //*******************************
+      bool empty() const
+      {
+        return head == etl::timer::id::NO_TIMER;
+      }
+
+      //*******************************
+      // Inserts the timer at the correct delta position
+      //*******************************
+      void insert(etl::timer::id::type id_)
+      {
+        etl::message_timer_data& timer = ptimers[id_];
+
+        if (head == etl::timer::id::NO_TIMER)
+        {
+          // No entries yet.
+          head = id_;
+          tail = id_;
+          timer.previous = etl::timer::id::NO_TIMER;
+          timer.next     = etl::timer::id::NO_TIMER;
+        }
+        else
+        {
+          // We already have entries.
+          etl::timer::id::type test_id = begin();
+
+          while (test_id != etl::timer::id::NO_TIMER)
+          {
+            etl::message_timer_data& test = ptimers[test_id];
+
+            // Find the correct place to insert.
+            if (timer.delta <= test.delta)
+            {
+              if (test.id == head)
+              {
+                head = timer.id;
+              }
+
+              // Insert before test.
+              timer.previous = test.previous;
+              test.previous  = timer.id;
+              timer.next     = test.id;
+
+              // Adjust the next delta to compensate.
+              test.delta -= timer.delta;
+
+              if (timer.previous != etl::timer::id::NO_TIMER)
+              {
+                ptimers[timer.previous].next = timer.id;
+              }
+              break;
+            }
+            else
+            {
+              timer.delta -= test.delta;
+            }
+
+            test_id = next(test_id);
+          }
+
+          // Reached the end?
+          if (test_id == etl::timer::id::NO_TIMER)
+          {
+            // Tag on to the tail.
+            ptimers[tail].next = timer.id;
+            timer.previous     = tail;
+            timer.next         = etl::timer::id::NO_TIMER;
+            tail               = timer.id;
+          }
+        }
+      }
+
+      //*******************************
+      void remove(etl::timer::id::type id_, bool has_expired)
+      {
+        etl::message_timer_data& timer = ptimers[id_];
+
+        if (head == id_)
+        {
+          head = timer.next;
+        }
+        else
+        {
+          ptimers[timer.previous].next = timer.next;
+        }
+
+        if (tail == id_)
+        {
+          tail = timer.previous;
+        }
+        else
+        {
+          ptimers[timer.next].previous = timer.previous;
+        }
+
+        if (!has_expired)
+        {
+          // Adjust the next delta.
+          if (timer.next != etl::timer::id::NO_TIMER)
+          {
+            ptimers[timer.next].delta += timer.delta;
+          }
+        }
+
+        timer.previous = etl::timer::id::NO_TIMER;
+        timer.next     = etl::timer::id::NO_TIMER;
+        timer.delta    = etl::timer::state::INACTIVE;
+      }
+
+      //*******************************
+      etl::message_timer_data& front()
+      {
+        return ptimers[head];
+      }
+
+      //*******************************
+      etl::timer::id::type begin()
+      {
+        current = head;
+        return current;
+      }
+
+      //*******************************
+      etl::timer::id::type previous(etl::timer::id::type last)
+      {
+        current = ptimers[last].previous;
+        return current;
+      }
+
+      //*******************************
+      etl::timer::id::type next(etl::timer::id::type last)
+      {
+        current = ptimers[last].next;
+        return current;
+      }
+
+      //*******************************
+      void clear()
+      {
+        etl::timer::id::type id = begin();
+
+        while (id != etl::timer::id::NO_TIMER)
+        {
+          etl::message_timer_data& timer = ptimers[id];
+          id = next(id);
+          timer.next = etl::timer::id::NO_TIMER;
+        }
+
+        head    = etl::timer::id::NO_TIMER;
+        tail    = etl::timer::id::NO_TIMER;
+        current = etl::timer::id::NO_TIMER;
+      }
+
+    private:
+
+      etl::timer::id::type head;
+      etl::timer::id::type tail;
+      etl::timer::id::type current;
+
+      etl::message_timer_data* const ptimers;
+    };
+  }
+
+  //***************************************************************************
+  /// Interface for message timer
+  //***************************************************************************
+  class imessage_timer
+  {
+  public:
+
+    //*******************************************
+    /// Register a timer.
+    //*******************************************
+    etl::timer::id::type register_timer(const etl::imessage&     message_,
+                                        etl::imessage_router&    router_,
+                                        uint32_t                 period_,
+                                        bool                     repeating_,
+                                        etl::message_router_id_t destination_router_id_ = etl::imessage_router::ALL_MESSAGE_ROUTERS)
+    {
+      etl::timer::id::type id = etl::timer::id::NO_TIMER;
+
+      disable_timer_updates();
+
+      bool is_space = (registered_timers < MAX_TIMERS);
+
+      if (is_space)
+      {
+        // There's no point adding null message routers.
+        if (!router_.is_null_router())
+        {
+          // Search for the free space.
+          for (uint_least8_t i = 0; i < MAX_TIMERS; ++i)
+          {
+            etl::message_timer_data& timer = timer_array[i];
+
+            if (timer.id == etl::timer::id::NO_TIMER)
+            {
+              // Create in-place.
+              new (&timer) message_timer_data(i, message_, router_, period_, repeating_, destination_router_id_);
+              ++registered_timers;
+              id = i;
+              break;
+            }
+          }
+        }
+      }
+
+      enable_timer_updates();
+
+      return id;
+    }
+
+    //*******************************************
+    /// Unregister a timer.
+    //*******************************************
+    bool unregister_timer(etl::timer::id::type id_)
+    {
+      bool result = false;
+
+      if (id_ != etl::timer::id::NO_TIMER)
+      {
+        disable_timer_updates();
+
+        etl::message_timer_data& timer = timer_array[id_];
+
+        if (timer.id != etl::timer::id::NO_TIMER)
+        {
+          if (timer.is_active())
+          {
+            active_list.remove(timer.id, true);
+
+            // Reset in-place.
+            new (&timer) message_timer_data();
+            --registered_timers;
+
+            result = true;
+          }
+        }
+
+        enable_timer_updates();
+      }
+
+      return result;
+    }
+
+    //*******************************************
+    /// Enable/disable the timer.
+    //*******************************************
+    void enable(bool state_)
+    {
+      enabled = state_;
+    }
+
+    //*******************************************
+    /// Get the enable/disable state.
+    //*******************************************
+    bool is_running() const
+    {
+      return enabled;
+    }
+
+    //*******************************************
+    /// Clears the timer of data.
+    //*******************************************
+    void clear()
+    {
+      disable_timer_updates();
+
+      active_list.clear();
+
+      for (int i = 0; i < MAX_TIMERS; ++i)
+      {
+        new (&timer_array[i]) message_timer_data();
+      }
+
+      registered_timers = 0;
+
+      enable_timer_updates();
+    }
+
+    //*******************************************
+    // Called by the timer service to indicate the
+    // amount of time that has elapsed since the last successful call to 'tick'.
+    // Returns true if the tick was processed,
+    // false if not.
+    //*******************************************
+    bool tick(uint32_t count)
+    {
+      if (enabled)
+      {
+        if (process_semaphore.load() == 0)
+        {
+          // We have something to do?
+          bool has_active = !active_list.empty();
+
+          if (has_active)
+          {
+            while (has_active && (count >= active_list.front().delta))
+            {
+              etl::message_timer_data& timer = active_list.front();
+
+              count -= timer.delta;
+
+              active_list.remove(timer.id, true);
+
+              if (timer.repeating)
+              {
+                timer.delta = timer.period;
+                active_list.insert(timer.id);
+              }
+
+              if (timer.p_router != std::nullptr)
+              {
+                if (timer.p_router->is_bus())
+                {
+                  // Send to a message bus.
+                  etl::imessage_bus& bus = static_cast<etl::imessage_bus&>(*(timer.p_router));
+                  bus.receive(timer.destination_router_id, *(timer.p_message));
+                }
+                else
+                {
+                  // Send to a router.
+                  timer.p_router->receive(*(timer.p_message));
+                }
+              }
+
+              has_active = !active_list.empty();
+            }
+
+            if (has_active)
+            {
+              // Subtract any remainder from the next due timeout.
+              active_list.front().delta -= count;
+            }
+          }
+
+          return true;
+        }
+      }
+
+      return false;
+    }
+
+    //*******************************************
+    /// Starts a timer.
+    //*******************************************
+    bool start(etl::timer::id::type id_, bool immediate_ = false)
+    {
+      bool result = false;
+
+      disable_timer_updates();
+
+      // Valid timer id?
+      if (id_ != etl::timer::id::NO_TIMER)
+      {
+        etl::message_timer_data& timer = timer_array[id_];
+
+        // Registered timer?
+        if (timer.id != etl::timer::id::NO_TIMER)
+        {
+          // Has a valid period.
+          if (timer.period != etl::timer::state::INACTIVE)
+          {
+            if (timer.is_active())
+            {
+              active_list.remove(timer.id, false);
+            }
+
+            timer.delta = immediate_ ? 0 : timer.period;
+            active_list.insert(timer.id);
+
+            result = true;
+          }
+        }
+      }
+
+      enable_timer_updates();
+
+      return result;
+    }
+
+    //*******************************************
+    /// Stops a timer.
+    //*******************************************
+    bool stop(etl::timer::id::type id_)
+    {
+      bool result = false;
+
+      disable_timer_updates();
+
+      // Valid timer id?
+      if (id_ != etl::timer::id::NO_TIMER)
+      {
+        etl::message_timer_data& timer = timer_array[id_];
+
+        // Registered timer?
+        if (timer.id != etl::timer::id::NO_TIMER)
+        {
+          if (timer.is_active())
+          {
+            active_list.remove(timer.id, false);
+            result = true;
+          }
+        }
+      }
+
+      enable_timer_updates();
+
+      return result;
+    }
+
+    //*******************************************
+    /// Sets a timer's period.
+    //*******************************************
+    bool set_period(etl::timer::id::type id_, uint32_t period_)
+    {
+      if (stop(id_))
+      {
+        timer_array[id_].period = period_;
+        return start(id_);
+      }
+      
+      return false;
+    }
+
+    //*******************************************
+    /// Sets a timer's mode.
+    //*******************************************
+    bool set_mode(etl::timer::id::type id_, bool repeating_)
+    {
+      if (stop(id_))
+      {
+        timer_array[id_].repeating = repeating_;
+        return start(id_);
+      }
+
+      return false;
+    }
+
+  protected:
+
+    //*******************************************
+    /// Constructor.
+    //*******************************************
+    imessage_timer(message_timer_data* const timer_array_, const uint_least8_t  MAX_TIMERS_)
+      : timer_array(timer_array_),
+        active_list(timer_array_),
+        enabled(false),
+        process_semaphore(0),
+        registered_timers(0),
+        MAX_TIMERS(MAX_TIMERS_)
+    {
+    }
+
+  private:
+
+    //*******************************************
+    /// Enable timer callback events.
+    //*******************************************
+    void enable_timer_updates()
+    {
+      --process_semaphore;
+    }
+
+    //*******************************************
+    /// Disable timer callback events.
+    //*******************************************
+    void disable_timer_updates()
+    {
+      ++process_semaphore;
+    }
+
+    // The array of timer data structures.
+    message_timer_data* const timer_array;
+
+    // The list of active timers.
+    __private_message_timer__::list active_list;
+
+    volatile bool enabled;
+    volatile etl::timer_semaphore_t process_semaphore;
+    volatile uint_least8_t registered_timers;
+
+  public:
+
+    const uint_least8_t MAX_TIMERS;
+  };
+
+  //***************************************************************************
+  /// The message timer
+  //***************************************************************************
+  template <uint_least8_t MAX_TIMERS_>
+  class message_timer : public etl::imessage_timer
+  {
+  public:
+
+    STATIC_ASSERT(MAX_TIMERS_ <= 254, "No more than 254 timers are allowed");
+
+    //*******************************************
+    /// Constructor.
+    //*******************************************
+    message_timer()
+      : imessage_timer(timer_array, MAX_TIMERS_)
+    {
+    }
+
+  private:
+
+    message_timer_data timer_array[MAX_TIMERS_];
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/message_types.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,49 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_MESSAGE_DEFS__
+#define __ETL_MESSAGE_DEFS__
+
+#include <stdint.h>
+
+#include "platform.h"
+
+namespace etl
+{
+  /// Allow alternative type for message id.
+#if !defined(ETL_MESSAGE_ID_TYPE)
+  typedef uint_least8_t message_id_t;
+#else
+  typedef ETL_MESSAGE_ID_TYPE message_id_t;
+#endif
+
+  typedef uint_least8_t message_router_id_t;
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimap.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,2045 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+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 __ETL_MULTIMAP__
+#define __ETL_MULTIMAP__
+
+#include <stddef.h>
+#include <iterator>
+#include <algorithm>
+#include <functional>
+
+#include "platform.h"
+#include "container.h"
+#include "pool.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "debug_count.h"
+#include "nullptr.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#undef ETL_FILE
+#define ETL_FILE "9"
+
+//*****************************************************************************
+/// A multimap with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the map.
+  ///\ingroup map
+  //***************************************************************************
+  class multimap_exception : public etl::exception
+  {
+  public:
+
+    multimap_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Full exception for the map.
+  ///\ingroup map
+  //***************************************************************************
+  class multimap_full : public etl::multimap_exception
+  {
+  public:
+
+    multimap_full(string_type file_name_, numeric_type line_number_)
+      : etl::multimap_exception("multimap:full", file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Map out of bounds exception.
+  ///\ingroup map
+  //***************************************************************************
+  class multimap_out_of_bounds : public etl::multimap_exception
+  {
+  public:
+
+    multimap_out_of_bounds(string_type file_name_, numeric_type line_number_)
+      : etl::multimap_exception("multimap:bounds", file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the map.
+  ///\ingroup map
+  //***************************************************************************
+  class multimap_iterator : public etl::multimap_exception
+  {
+  public:
+
+    multimap_iterator(string_type file_name_, numeric_type line_number_)
+      : etl::multimap_exception("multimap:iterator", file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for all maps.
+  ///\ingroup map
+  //***************************************************************************
+  class multimap_base
+  {
+  public:
+
+    typedef size_t size_type; ///< The type used for determining the size of map.
+
+    //*************************************************************************
+    /// Gets the size of the map.
+    //*************************************************************************
+    size_type size() const
+    {
+      return current_size;
+    }
+
+    //*************************************************************************
+    /// Gets the maximum possible size of the map.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Checks to see if the map is empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return current_size == 0;
+    }
+
+    //*************************************************************************
+    /// Checks to see if the map is full.
+    //*************************************************************************
+    bool full() const
+    {
+      return current_size == CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the vector.
+    ///\return The capacity of the vector.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return max_size() - size();
+    }
+
+  protected:
+
+    enum
+    {
+      kLeft,
+      kRight,
+      kNeither
+    };
+
+    //*************************************************************************
+    /// The node element in the multimap.
+    //*************************************************************************
+    struct Node
+    {
+      //***********************************************************************
+      /// Constructor
+      //***********************************************************************
+      Node() :
+        weight(kNeither),
+        dir(kNeither)
+      {
+      }
+
+      //***********************************************************************
+      /// Marks the node as a leaf.
+      //***********************************************************************
+      void mark_as_leaf()
+      {
+        weight = kNeither;
+        dir = kNeither;
+        parent = std::nullptr;
+        children[0] = std::nullptr;
+        children[1] = std::nullptr;
+      }
+
+      Node* parent;
+      Node* children[2];
+      uint_least8_t weight;
+      uint_least8_t dir;
+    };
+
+    //*************************************************************************
+    /// The constructor that is called from derived classes.
+    //*************************************************************************
+    multimap_base(size_type max_size_)
+      : current_size(0)
+      , CAPACITY(max_size_)
+      , root_node(std::nullptr)
+
+    {
+    }
+
+    //*************************************************************************
+    /// Balance the critical node at the position provided as needed
+    //*************************************************************************
+    void balance_node(Node*& critical_node)
+    {
+      // Step 1: Update weights for all children of the critical node up to the
+      // newly inserted node. This step is costly (in terms of traversing nodes
+      // multiple times during insertion) but doesn't require as much recursion
+      Node* weight_node = critical_node->children[critical_node->dir];
+      while (weight_node)
+      {
+        // Keep going until we reach a terminal node (dir == kNeither)
+        if (kNeither != weight_node->dir)
+        {
+          // Does this insert balance the previous weight factor value?
+          if (weight_node->weight == 1 - weight_node->dir)
+          {
+            weight_node->weight = kNeither;
+          }
+          else
+          {
+            weight_node->weight = weight_node->dir;
+          }
+
+          // Update weight factor node to point to next node
+          weight_node = weight_node->children[weight_node->dir];
+        }
+        else
+        {
+          // Stop loop, terminal node found
+          break;
+        }
+      } // while(weight_node)
+
+        // Step 2: Update weight for critical_node or rotate tree to balance node
+      if (kNeither == critical_node->weight)
+      {
+        critical_node->weight = critical_node->dir;
+      }
+      // If direction is different than weight, then it will now be balanced
+      else if (critical_node->dir != critical_node->weight)
+      {
+        critical_node->weight = kNeither;
+      }
+      // Rotate is required to balance the tree at the critical node
+      else
+      {
+        // If critical node matches child node direction then perform a two
+        // node rotate in the direction of the critical node
+        if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
+        {
+          rotate_2node(critical_node, critical_node->dir);
+        }
+        // Otherwise perform a three node rotation in the direction of the
+        // critical node
+        else
+        {
+          rotate_3node(critical_node, critical_node->dir,
+            critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Rotate two nodes at the position provided the to balance the tree
+    //*************************************************************************
+    void rotate_2node(Node*& position, uint_least8_t dir)
+    {
+      //     A            C             A          B
+      //   B   C   ->   A   E   OR    B   C  ->  D   A
+      //      D E      B D           D E            E C
+      // C (new position) becomes the root
+      // A (position) takes ownership of D as its children[kRight] child
+      // C (new position) takes ownership of A as its left child
+      //                 OR
+      // B (new position) becomes the root
+      // A (position) takes ownership of E as its left child
+      // B (new position) takes ownership of A as its right child
+
+      // Capture new root (either B or C depending on dir) and its parent
+      Node* new_root = position->children[dir];
+
+      // Replace position's previous child with new root's other child
+      position->children[dir] = new_root->children[1 - dir];
+      // Update new root's other child parent pointer
+      if (position->children[dir])
+      {
+        position->children[dir]->parent = position;
+      }
+
+      // New root's parent becomes current position's parent
+      new_root->parent = position->parent;
+      new_root->children[1 - dir] = position;
+      new_root->dir = 1 - dir;
+
+      // Clear weight factor from current position
+      position->weight = kNeither;
+      // Position's parent becomes new_root
+      position->parent = new_root;
+      position = new_root;
+      // Clear weight factor from new root
+      position->weight = kNeither;
+    }
+
+    //*************************************************************************
+    /// Rotate three nodes at the position provided the to balance the tree
+    //*************************************************************************
+    void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third)
+    {
+      //        __A__             __E__            __A__             __D__
+      //      _B_    C    ->     B     A    OR    B    _C_   ->     A     C
+      //     D   E              D F   G C             D   E        B F   G E
+      //        F G                                  F G
+      // E (new position) becomes the root
+      // B (position) takes ownership of F as its left child
+      // A takes ownership of G as its right child
+      //                  OR
+      // D (new position) becomes the root
+      // A (position) takes ownership of F as its right child
+      // C takes ownership of G as its left child
+
+      // Capture new root (either E or D depending on dir)
+      Node* new_root = position->children[dir]->children[1 - dir];
+      // Set weight factor for B or C based on F or G existing and being a different than dir
+      position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither;
+
+      // Detach new root from its tree (replace with new roots child)
+      position->children[dir]->children[1 - dir] = new_root->children[dir];
+      // Update new roots child parent pointer
+      if (new_root->children[dir])
+      {
+        new_root->children[dir]->parent = position->children[dir];
+      }
+
+      // Attach current left tree to new root and update its parent
+      new_root->children[dir] = position->children[dir];
+      position->children[dir]->parent = new_root;
+
+      // Set weight factor for A based on F or G
+      position->weight = third != kNeither && third == dir ? 1 - dir : kNeither;
+
+      // Move new root's right tree to current roots left tree
+      position->children[dir] = new_root->children[1 - dir];
+      if (new_root->children[1 - dir])
+      {
+        new_root->children[1 - dir]->parent = position;
+      }
+
+      // Attach current root to new roots right tree and assume its parent
+      new_root->parent = position->parent;
+      new_root->children[1 - dir] = position;
+      new_root->dir = 1 - dir;
+
+      // Update current position's parent and replace with new root
+      position->parent = new_root;
+      position = new_root;
+      // Clear weight factor for new current position
+      position->weight = kNeither;
+    }
+
+    //*************************************************************************
+    /// Find the next node in sequence from the node provided
+    //*************************************************************************
+    void next_node(Node*& position) const
+    {
+      if (position)
+      {
+        // Is there a tree on the right? then find the minimum of that tree
+        if (position->children[kRight])
+        {
+          // Return minimum node found
+          position = find_limit_node(position->children[kRight], kLeft);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = position->parent; // find_parent_node(root_node, position);
+                                       // Repeat while previous position was on right side of parent tree
+          } while (parent && parent->children[kRight] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the next node in sequence from the node provided
+    //*************************************************************************
+    void next_node(const Node*& position) const
+    {
+      if (position)
+      {
+        // Is there a tree on the right? then find the minimum of that tree
+        if (position->children[kRight])
+        {
+          // Return minimum node found
+          position = find_limit_node(position->children[kRight], kLeft);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          const Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = position->parent;
+            // Repeat while previous position was on right side of parent tree
+          } while (parent && parent->children[kRight] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the previous node in sequence from the node provided
+    //*************************************************************************
+    void prev_node(Node*& position) const
+    {
+      // If starting at the terminal end, the previous node is the maximum node
+      // from the root
+      if (!position)
+      {
+        position = find_limit_node(root_node, kRight);
+      }
+      else
+      {
+        // Is there a tree on the left? then find the maximum of that tree
+        if (position->children[kLeft])
+        {
+          // Return maximum node found
+          position = find_limit_node(position->children[kLeft], kRight);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = position->parent;
+            // Repeat while previous position was on left side of parent tree
+          } while (parent && parent->children[kLeft] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the previous node in sequence from the node provided
+    //*************************************************************************
+    void prev_node(const Node*& position) const
+    {
+      // If starting at the terminal end, the previous node is the maximum node
+      // from the root
+      if (!position)
+      {
+        position = find_limit_node(root_node, kRight);
+      }
+      else
+      {
+        // Is there a tree on the left? then find the maximum of that tree
+        if (position->children[kLeft])
+        {
+          // Return maximum node found
+          position = find_limit_node(position->children[kLeft], kRight);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          const Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = position->parent;
+            // Repeat while previous position was on left side of parent tree
+          } while (parent && parent->children[kLeft] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the node whose key would go before all the other keys from the
+    /// position provided
+    //*************************************************************************
+    Node* find_limit_node(Node* position, const int8_t dir) const
+    {
+      // Something at this position and in the direction specified? keep going
+      Node* limit_node = position;
+      while (limit_node && limit_node->children[dir])
+      {
+        limit_node = limit_node->children[dir];
+      }
+
+      // Return the limit node position found
+      return limit_node;
+    }
+
+    //*************************************************************************
+    /// Attach the provided node to the position provided
+    //*************************************************************************
+    void attach_node(Node* parent, Node*& position, Node& node)
+    {
+      // Mark new node as leaf on attach to tree at position provided
+      node.mark_as_leaf();
+
+      // Keep track of this node's parent
+      node.parent = parent;
+
+      // Add the node here
+      position = &node;
+
+      // One more.
+      ++current_size;
+    }
+
+    //*************************************************************************
+    /// Detach the node at the position provided
+    //*************************************************************************
+    void detach_node(Node*& position, Node*& replacement)
+    {
+      // Make temporary copy of actual nodes involved because we might lose
+      // their references in the process (e.g. position is the same as
+      // replacement or replacement is a child of position)
+      Node* detached = position;
+      Node* swap = replacement;
+
+      // Update current position to point to swap (replacement) node first
+      position = swap;
+
+      // Update replacement node to point to child in opposite direction
+      // otherwise we might lose the other child of the swap node
+      replacement = swap->children[1 - swap->dir];
+
+      // Point swap node to detached node's parent, children and weight
+      swap->parent = detached->parent;
+      swap->children[kLeft] = detached->children[kLeft];
+      swap->children[kRight] = detached->children[kRight];
+      if (swap->children[kLeft])
+      {
+        swap->children[kLeft]->parent = swap;
+      }
+      if (swap->children[kRight])
+      {
+        swap->children[kRight]->parent = swap;
+      }
+      swap->weight = detached->weight;
+    }
+
+    size_type current_size;   ///< The number of the used nodes.
+    const size_type CAPACITY; ///< The maximum size of the map.
+    Node* root_node;          ///< The node that acts as the multimap root.
+    etl::debug_count construct_count;
+  };
+
+  //***************************************************************************
+  /// A templated base for all etl::multimap types.
+  ///\ingroup map
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  class imultimap : public etl::multimap_base
+  {
+  public:
+
+    typedef std::pair<const TKey, TMapped> value_type;
+    typedef const TKey                     key_type;
+    typedef TMapped                        mapped_type;
+    typedef TKeyCompare                    key_compare;
+    typedef value_type&                    reference;
+    typedef const value_type&              const_reference;
+    typedef value_type*                    pointer;
+    typedef const value_type*              const_pointer;
+    typedef size_t                         size_type;
+
+    //*************************************************************************
+    /// How to compare two key elements.
+    //*************************************************************************
+    struct key_comp
+    {
+      bool operator ()(const key_type& key1, const key_type& key2) const
+      {
+        return key_compare()(key1, key2);
+      }
+    };
+
+    //*************************************************************************
+    /// How to compare two value elements.
+    //*************************************************************************
+    struct value_comp
+    {
+      bool operator ()(const value_type& value1, const value_type& value2) const
+      {
+        return key_compare()(value1.first, value2.first);
+      }
+    };
+
+  protected:
+
+    //*************************************************************************
+    /// The data node element in the multimap.
+    //*************************************************************************
+    struct Data_Node : public Node
+    {
+      explicit Data_Node(value_type value_)
+        : value(value_)
+      {
+      }
+
+      value_type value;
+    };
+
+    /// Defines the key value parameter type
+    typedef typename etl::parameter_type<TKey>::type key_parameter_t;
+
+    //*************************************************************************
+    /// How to compare node elements.
+    //*************************************************************************
+    bool node_comp(const Data_Node& node1, const Data_Node& node2) const
+    {
+      return key_compare()(node1.value.first, node2.value.first);
+    }
+
+    bool node_comp(const Data_Node& node, key_parameter_t key) const
+    {
+      return key_compare()(node.value.first, key);
+    }
+
+    bool node_comp(key_parameter_t key, const Data_Node& node) const
+    {
+      return key_compare()(key, node.value.first);
+    }
+
+  private:
+
+    /// The pool of data nodes used in the multimap.
+    ipool* p_node_pool;
+
+    //*************************************************************************
+    /// Downcast a Node* to a Data_Node*
+    //*************************************************************************
+    static Data_Node* data_cast(Node* p_node)
+    {
+      return static_cast<Data_Node*>(p_node);
+    }
+
+    //*************************************************************************
+    /// Downcast a Node& to a Data_Node&
+    //*************************************************************************
+    static Data_Node& data_cast(Node& node)
+    {
+      return static_cast<Data_Node&>(node);
+    }
+
+    //*************************************************************************
+    /// Downcast a const Node* to a const Data_Node*
+    //*************************************************************************
+    static const Data_Node* data_cast(const Node* p_node)
+    {
+      return static_cast<const Data_Node*>(p_node);
+    }
+
+    //*************************************************************************
+    /// Downcast a const Node& to a const Data_Node&
+    //*************************************************************************
+    static const Data_Node& data_cast(const Node& node)
+    {
+      return static_cast<const Data_Node&>(node);
+    }
+
+  public:
+    //*************************************************************************
+    /// iterator.
+    //*************************************************************************
+    class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+    {
+    public:
+
+      friend class imultimap;
+
+      iterator()
+        : p_multimap(std::nullptr)
+        , p_node(std::nullptr)
+      {
+      }
+
+      iterator(imultimap& multimap)
+        : p_multimap(&multimap)
+        , p_node(std::nullptr)
+      {
+      }
+
+      iterator(imultimap& multimap, Node* node)
+        : p_multimap(&multimap)
+        , p_node(node)
+      {
+      }
+
+      iterator(const iterator& other)
+        : p_multimap(other.p_multimap)
+        , p_node(other.p_node)
+      {
+      }
+
+      ~iterator()
+      {
+      }
+
+      iterator& operator ++()
+      {
+        p_multimap->next_node(p_node);
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        p_multimap->next_node(p_node);
+        return temp;
+      }
+
+      iterator& operator --()
+      {
+        p_multimap->prev_node(p_node);
+        return *this;
+      }
+
+      iterator operator --(int)
+      {
+        iterator temp(*this);
+        p_multimap->prev_node(p_node);
+        return temp;
+      }
+
+      iterator operator =(const iterator& other)
+      {
+        p_multimap = other.p_multimap;
+        p_node = other.p_node;
+        return *this;
+      }
+
+      reference operator *()
+      {
+        return imultimap::data_cast(p_node)->value;
+      }
+
+      const_reference operator *() const
+      {
+        return imultimap::data_cast(p_node)->value;
+      }
+
+      pointer operator &()
+      {
+        return &(imultimap::data_cast(p_node)->value);
+      }
+
+      const_pointer operator &() const
+      {
+        return &(imultimap::data_cast(p_node)->value);
+      }
+
+      pointer operator ->()
+      {
+        return &(imultimap::data_cast(p_node)->value);
+      }
+
+      const_pointer operator ->() const
+      {
+        return &(imultimap::data_cast(p_node)->value);
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.p_multimap == rhs.p_multimap && lhs.p_node == rhs.p_node;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      // Pointer to multimap associated with this iterator
+      imultimap* p_multimap;
+
+      // Pointer to the current node for this iterator
+      Node* p_node;
+    };
+    friend class iterator;
+
+    //*************************************************************************
+    /// const_iterator
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+    {
+    public:
+
+      friend class imultimap;
+
+      const_iterator()
+        : p_multimap(std::nullptr)
+        , p_node(std::nullptr)
+      {
+      }
+
+      const_iterator(const imultimap& multimap)
+        : p_multimap(&multimap)
+        , p_node(std::nullptr)
+      {
+      }
+
+      const_iterator(const imultimap& multimap, const Node* node)
+        : p_multimap(&multimap)
+        , p_node(node)
+      {
+      }
+
+      const_iterator(const typename imultimap::iterator& other)
+        : p_multimap(other.p_multimap)
+        , p_node(other.p_node)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : p_multimap(other.p_multimap)
+        , p_node(other.p_node)
+      {
+      }
+
+      ~const_iterator()
+      {
+      }
+
+      const_iterator& operator ++()
+      {
+        p_multimap->next_node(p_node);
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        p_multimap->next_node(p_node);
+        return temp;
+      }
+
+      const_iterator& operator --()
+      {
+        p_multimap->prev_node(p_node);
+        return *this;
+      }
+
+      const_iterator operator --(int)
+      {
+        const_iterator temp(*this);
+        p_multimap->prev_node(p_node);
+        return temp;
+      }
+
+      const_iterator operator =(const const_iterator& other)
+      {
+        p_multimap = other.p_multimap;
+        p_node = other.p_node;
+        return *this;
+      }
+
+      const_reference operator *() const
+      {
+        return imultimap::data_cast(p_node)->value;
+      }
+
+      const_pointer operator &() const
+      {
+        return imultimap::data_cast(p_node)->value;
+      }
+
+      const_pointer operator ->() const
+      {
+        return &(imultimap::data_cast(p_node)->value);
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.p_multimap == rhs.p_multimap && lhs.p_node == rhs.p_node;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+      // Pointer to multimap associated with this iterator
+      const imultimap* p_multimap;
+
+      // Pointer to the current node for this iterator
+      const Node* p_node;
+    };
+    friend class const_iterator;
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+
+    //*************************************************************************
+    /// Gets the beginning of the multimap.
+    //*************************************************************************
+    iterator begin()
+    {
+      return iterator(*this, find_limit_node(root_node, kLeft));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the multimap.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(*this, find_limit_node(root_node, kLeft));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the multimap.
+    //*************************************************************************
+    iterator end()
+    {
+      return iterator(*this);
+    }
+
+    //*************************************************************************
+    /// Gets the end of the multimap.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(*this);
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the multimap.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(*this, find_limit_node(root_node, kLeft));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the multimap.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(*this);
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(iterator(*this));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(const_iterator(*this));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(const_iterator(*this));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
+    }
+
+    //*********************************************************************
+    /// Assigns values to the multimap.
+    /// If asserts or exceptions are enabled, emits map_full if the multimap does not have enough free space.
+    /// If asserts or exceptions are enabled, emits map_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+      initialise();
+      insert(first, last);
+    }
+
+    //*************************************************************************
+    /// Clears the multimap.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*********************************************************************
+    /// Counts the number of elements that contain the key specified.
+    ///\param key The key to search for.
+    ///\return 1 if element was found, 0 otherwise.
+    //*********************************************************************
+    size_type count(key_parameter_t key) const
+    {
+      return count_nodes(key);
+    }
+
+    //*************************************************************************
+    /// Returns two iterators with bounding (lower bound, upper bound) the key
+    /// provided
+    //*************************************************************************
+    std::pair<iterator, iterator> equal_range(key_parameter_t key)
+    {
+      return std::make_pair<iterator, iterator>(
+        iterator(*this, find_lower_node(root_node, key)),
+        iterator(*this, find_upper_node(root_node, key)));
+    }
+
+    //*************************************************************************
+    /// Returns two const iterators with bounding (lower bound, upper bound)
+    /// the key provided.
+    //*************************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
+    {
+      return std::make_pair<const_iterator, const_iterator>(
+        const_iterator(*this, find_lower_node(root_node, key)),
+        const_iterator(*this, find_upper_node(root_node, key)));
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    void erase(iterator position)
+    {
+      // Remove the node by its node specified in iterator position
+      (void)erase(const_iterator(position));
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    iterator erase(const_iterator position)
+    {
+      // Cast const away from node to be removed. This is necessary because the
+      // STL definition of this method requires we provide the next node in the
+      // sequence as an iterator.
+      Node* node = const_cast<Node*>(position.p_node);
+      iterator next(*this, node);
+      ++next;
+
+      // Remove the non-const node provided
+      remove_node(node);
+
+      return next;
+    }
+
+    //*************************************************************************
+    // Erase the key specified.
+    //*************************************************************************
+    size_type erase(key_parameter_t key)
+    {
+      // Number of nodes removed
+      size_type d = 0;
+      const_iterator lower(*this, find_lower_node(root_node, key));
+      const_iterator upper(*this, find_upper_node(root_node, key));
+      while (lower != upper)
+      {
+        // Increment count for each node removed
+        ++d;
+        // Remove node using the other erase method
+        (void)erase(lower++);
+      }
+
+      // Return the total count erased
+      return d;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    //*************************************************************************
+    iterator erase(iterator first, iterator last)
+    {
+      iterator next;
+      while (first != last)
+      {
+        next = erase(const_iterator(first++));
+      }
+
+      return next;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    //*************************************************************************
+    iterator erase(const_iterator first, const_iterator last)
+    {
+      iterator next;
+      while (first != last)
+      {
+        next = erase(first++);
+      }
+
+      return next;
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    iterator find(key_parameter_t key)
+    {
+      return iterator(*this, find_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    const_iterator find(key_parameter_t key) const
+    {
+      return const_iterator(*this, find_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the multimap.
+    /// If asserts or exceptions are enabled, emits map_full if the multimap is already full.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(const value_type& value)
+    {
+      // Default to no inserted node
+      Node* inserted_node = std::nullptr;
+
+      ETL_ASSERT(!full(), ETL_ERROR(multimap_full));
+
+      // Get next available free node
+      Data_Node& node = allocate_data_node(value);
+
+      // Obtain the inserted node (might be std::nullptr if node was a duplicate)
+      inserted_node = insert_node(root_node, node);
+
+      // Insert node into tree and return iterator to new node location in tree
+      return iterator(*this, inserted_node);
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the multimap starting at the position recommended.
+    /// If asserts or exceptions are enabled, emits map_full if the multimap is already full.
+    ///\param position The position that would precede the value to insert.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator /*position*/, const value_type& value)
+    {
+      // Ignore position provided and just do a normal insert
+      return insert(value);
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the multimap starting at the position recommended.
+    /// If asserts or exceptions are enabled, emits map_full if the multimap is already full.
+    ///\param position The position that would precede the value to insert.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(const_iterator /*position*/, const value_type& value)
+    {
+      // Ignore position provided and just do a normal insert
+      return insert(value);
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the multimap.
+    /// If asserts or exceptions are enabled, emits map_full if the multimap does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Returns an iterator pointing to the first element in the container
+    /// whose key is not considered to go before the key provided or end()
+    /// if all keys are considered to go before the key provided.
+    ///\return An iterator pointing to the element not before key or end()
+    //*********************************************************************
+    iterator lower_bound(key_parameter_t key)
+    {
+      return iterator(*this, find_lower_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator pointing to the first element in the
+    /// container whose key is not considered to go before the key provided
+    /// or end() if all keys are considered to go before the key provided.
+    ///\return An const_iterator pointing to the element not before key or end()
+    //*********************************************************************
+    const_iterator lower_bound(key_parameter_t key) const
+    {
+      return const_iterator(*this, find_lower_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Returns an iterator pointing to the first element in the container
+    /// whose key is not considered to go after the key provided or end()
+    /// if all keys are considered to go after the key provided.
+    ///\return An iterator pointing to the element after key or end()
+    //*********************************************************************
+    iterator upper_bound(key_parameter_t key)
+    {
+      return iterator(*this, find_upper_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator pointing to the first element in the
+    /// container whose key is not considered to go after the key provided
+    /// or end() if all keys are considered to go after the key provided.
+    ///\return An const_iterator pointing to the element after key or end()
+    //*********************************************************************
+    const_iterator upper_bound(key_parameter_t key) const
+    {
+      return const_iterator(*this, find_upper_node(root_node, key));
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    imultimap& operator = (const imultimap& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    imultimap(etl::ipool& node_pool, size_t max_size_)
+      : multimap_base(max_size_)
+      , p_node_pool(&node_pool)
+    {
+    }
+
+    //*************************************************************************
+    /// Initialise the multimap.
+    //*************************************************************************
+    void initialise()
+    {
+      erase(begin(), end());
+    }
+
+  private:
+
+    //*************************************************************************
+    /// Allocate a Data_Node.
+    //*************************************************************************
+    Data_Node& allocate_data_node(value_type value)
+    {
+      Data_Node& node = *p_node_pool->allocate<Data_Node>();
+      ::new (&node.value) const value_type(value);
+      ++construct_count;
+      return node;
+    }
+
+    //*************************************************************************
+    /// Destroy a Data_Node.
+    //*************************************************************************
+    void destroy_data_node(Data_Node& node)
+    {
+      node.value.~value_type();
+      p_node_pool->release(&node);
+      --construct_count;
+    }
+
+    //*************************************************************************
+    /// Count the nodes that match the key provided
+    //*************************************************************************
+    size_type count_nodes(key_parameter_t key) const
+    {
+      // Number of nodes that match the key provided result
+      size_type result = 0;
+
+      // Find lower and upper nodes for the key provided
+      const Node* lower = find_lower_node(root_node, key);
+      const Node* upper = find_upper_node(root_node, key);
+
+      // Loop from lower node to upper node and find nodes that match
+      while (lower != upper)
+      {
+        // Downcast found to Data_Node class for comparison and other operations
+        const Data_Node& data_node = imultimap::data_cast(*lower);
+
+        if (!node_comp(key, data_node) && !node_comp(data_node, key))
+        {
+          // This node matches the key provided
+          ++result;
+        }
+
+        // Move on to the next node
+        next_node(lower);
+      }
+
+      // Return the number of nodes that match
+      return result;
+    }
+
+    //*************************************************************************
+    /// Find the value matching the node provided
+    //*************************************************************************
+    Node* find_node(Node* position, key_parameter_t key) const
+    {
+      Node* found = std::nullptr;
+      while (position)
+      {
+        // Downcast found to Data_Node class for comparison and other operations
+        Data_Node& data_node = imultimap::data_cast(*position);
+        // Compare the node value to the current position value
+        if (node_comp(key, data_node))
+        {
+          // Keep searching for the node on the left
+          position = position->children[kLeft];
+        }
+        else if (node_comp(data_node, key))
+        {
+          // Keep searching for the node on the right
+          position = position->children[kRight];
+        }
+        else
+        {
+          // We found one, keep looking for more on the left
+          found = position;
+          position = position->children[kLeft];
+        }
+      }
+
+      // Return the node found (might be std::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the value matching the node provided
+    //*************************************************************************
+    const Node* find_node(const Node* position, key_parameter_t key) const
+    {
+      const Node* found = std::nullptr;
+      while (position)
+      {
+        // Downcast found to Data_Node class for comparison and other operations
+        const Data_Node& data_node = imultimap::data_cast(*position);
+        // Compare the node value to the current position value
+        if (node_comp(key, data_node))
+        {
+          // Keep searching for the node on the left
+          position = position->children[kLeft];
+        }
+        else if (node_comp(data_node, key))
+        {
+          // Keep searching for the node on the right
+          position = position->children[kRight];
+        }
+        else
+        {
+          // We found one, keep looking for more on the left
+          found = position;
+          position = position->children[kLeft];
+        }
+      }
+
+      // Return the node found (might be std::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the node whose key is not considered to go before the key provided
+    //*************************************************************************
+    Node* find_lower_node(Node* position, key_parameter_t key) const
+    {
+      // Something at this position? keep going
+      Node* lower_node = std::nullptr;
+      while (position)
+      {
+        // Downcast lower node to Data_Node reference for key comparisons
+        Data_Node& data_node = imultimap::data_cast(*position);
+        // Compare the key value to the current lower node key value
+        if (node_comp(key, data_node))
+        {
+          lower_node = position;
+          if (position->children[kLeft])
+          {
+            position = position->children[kLeft];
+          }
+          else
+          {
+            // Found lowest node
+            break;
+          }
+        }
+        else if (node_comp(data_node, key))
+        {
+          position = position->children[kRight];
+        }
+        else
+        {
+          // Make note of current position, but keep looking to left for more
+          lower_node = position;
+          position = position->children[kLeft];
+        }
+      }
+
+      // Return the lower_node position found
+      return lower_node;
+    }
+
+    //*************************************************************************
+    /// Find the node whose key is considered to go after the key provided
+    //*************************************************************************
+    Node* find_upper_node(Node* position, key_parameter_t key) const
+    {
+      // Keep track of parent of last upper node
+      Node* upper_node = std::nullptr;
+      // Has an equal node been found? start with no
+      bool found = false;
+      while (position)
+      {
+        // Downcast position to Data_Node reference for key comparisons
+        Data_Node& data_node = imultimap::data_cast(*position);
+        // Compare the key value to the current upper node key value
+        if (node_comp(data_node, key))
+        {
+          position = position->children[kRight];
+        }
+        else if (node_comp(key, data_node))
+        {
+          upper_node = position;
+          // If a node equal to key hasn't been found go left
+          if (!found && position->children[kLeft])
+          {
+            position = position->children[kLeft];
+          }
+          else
+          {
+            break;
+          }
+        }
+        else
+        {
+          // We found an equal item, break on next bigger item
+          found = true;
+          next_node(position);
+        }
+      }
+
+      // Return the upper node position found (might be std::nullptr)
+      return upper_node;
+    }
+
+    //*************************************************************************
+    /// Insert a node.
+    //*************************************************************************
+    Node* insert_node(Node*& position, Data_Node& node)
+    {
+      // Find the location where the node belongs
+      Node* found = position;
+
+      // Was position provided not empty? then find where the node belongs
+      if (position)
+      {
+        // Find the critical parent node (default to std::nullptr)
+        Node* critical_parent_node = std::nullptr;
+        Node* critical_node = root_node;
+
+        while (found)
+        {
+          // Search for critical weight node (all nodes whose weight factor
+          // is set to kNeither (balanced)
+          if (kNeither != found->weight)
+          {
+            critical_node = found;
+          }
+
+          // Downcast found to Data_Node class for comparison and other operations
+          Data_Node& found_data_node = imultimap::data_cast(*found);
+
+          // Is the node provided to the left of the current position?
+          if (node_comp(node, found_data_node))
+          {
+            // Update direction taken to insert new node in parent node
+            found->dir = kLeft;
+          }
+          // Is the node provided to the right of the current position?
+          else if (node_comp(found_data_node, node))
+          {
+            // Update direction taken to insert new node in parent node
+            found->dir = kRight;
+          }
+          else
+          {
+            // Update direction taken to insert new node in parent (and
+            // duplicate) node to the right.
+            found->dir = kRight;
+          }
+
+          // Is there a child of this parent node?
+          if (found->children[found->dir])
+          {
+            // Will this node be the parent of the next critical node whose
+            // weight factor is set to kNeither (balanced)?
+            if (kNeither != found->children[found->dir]->weight)
+            {
+              critical_parent_node = found;
+            }
+
+            // Keep looking for empty spot to insert new node
+            found = found->children[found->dir];
+          }
+          else
+          {
+            // Attach node as a child of the parent node found
+            attach_node(found, found->children[found->dir], node);
+
+            // Return newly added node
+            found = found->children[found->dir];
+
+            // Exit loop
+            break;
+          }
+        }
+
+        // Was a critical node found that should be checked for balance?
+        if (critical_node)
+        {
+          if (critical_parent_node == std::nullptr && critical_node == root_node)
+          {
+            balance_node(root_node);
+          }
+          else if (critical_parent_node == std::nullptr && critical_node == position)
+          {
+            balance_node(position);
+          }
+          else
+          {
+            balance_node(critical_parent_node->children[critical_parent_node->dir]);
+          }
+        }
+      }
+      else
+      {
+        // Attach node to current position (which is assumed to be root)
+        attach_node(std::nullptr, position, node);
+
+        // Return newly added node at current position
+        found = position;
+      }
+
+      // Return the node found (might be std::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Remove the node specified from somewhere starting at the position
+    /// provided
+    //*************************************************************************
+    void remove_node(Node* node)
+    {
+      // If valid found node was provided then proceed with steps 1 through 5
+      if (node)
+      {
+        // Downcast found node provided to Data_Node class
+        Data_Node& data_node = imultimap::data_cast(*node);
+
+        // Keep track of node as found node
+        Node* found = node;
+
+        // Step 1: Mark path from node provided back to the root node using the
+        // internal temporary dir member value and using the parent pointer. This
+        // will allow us to avoid recursion in finding the node in a tree that
+        //might contain duplicate keys to be found.
+        while (node)
+        {
+          if (node->parent)
+          {
+            // Which direction does parent use to get to this node?
+            node->parent->dir =
+              node->parent->children[kLeft] == node ? kLeft : kRight;
+
+            // Make this nodes parent the next node
+            node = node->parent;
+          }
+          else
+          {
+            // Root node found - break loop
+            break;
+          }
+        }
+
+        // Step 2: Follow the path provided above until we reach the node
+        // provided and look for the balance node to start rebalancing the tree
+        // from (up to the replacement node that will be found in step 3)
+        Node* balance = root_node;
+        while (node)
+        {
+          // Did we reach the node provided originally (found) then go to step 3
+          if (node == found)
+          {
+            // Update the direction towards a replacement node at the found node
+            node->dir = node->children[kLeft] ? kLeft : kRight;
+
+            // Exit loop and proceed with step 3
+            break;
+          }
+          else
+          {
+            // If this nodes weight is kNeither or we are taking the shorter path
+            // to the next node and our sibling (on longer path) is balanced then
+            // we need to update the balance node to this node but all our
+            // ancestors will not require rebalancing
+            if ((node->weight == kNeither) ||
+              (node->weight == (1 - node->dir) &&
+                node->children[1 - node->dir]->weight == kNeither))
+            {
+              // Update balance node to this node
+              balance = node;
+            }
+
+            // Keep searching for found in the direction provided in step 1
+            node = node->children[node->dir];
+          }
+        }
+        // The value for node should not be std::nullptr at this point otherwise
+        // step 1 failed to provide the correct path to found. Step 5 will fail
+        // (probably subtly) if node should be std::nullptr at this point
+
+        // Step 3: Find the node (node should be equal to found at this point)
+        // to replace found with (might end up equal to found) while also
+        // continuing to update balance the same as in step 2 above.
+        while (node)
+        {
+          // Replacement node found if its missing a child in the replace->dir
+          // value set at the end of step 2 above
+          if (node->children[node->dir] == std::nullptr)
+          {
+            // Exit loop once node to replace found is determined
+            break;
+          }
+
+          // If this nodes weight is kNeither or we are taking the shorter path
+          // to the next node and our sibling (on longer path) is balanced then
+          // we need to update the balance node to this node but all our
+          // ancestors will not require rebalancing
+          if ((node->weight == kNeither) ||
+            (node->weight == (1 - node->dir) &&
+              node->children[1 - node->dir]->weight == kNeither))
+          {
+            // Update balance node to this node
+            balance = node;
+          }
+
+          // Keep searching for replacement node in the direction specified above
+          node = node->children[node->dir];
+
+          // Downcast node to Data_Node class for comparison operations
+          Data_Node& replace_data_node = imultimap::data_cast(*node);
+
+          // Compare the key provided to the replace data node key
+          if (node_comp(data_node, replace_data_node))
+          {
+            // Update the direction to the replace node
+            node->dir = kLeft;
+          }
+          else if (node_comp(replace_data_node, data_node))
+          {
+            // Update the direction to the replace node
+            node->dir = kRight;
+          }
+          else
+          {
+            // Update the direction to the replace node
+            node->dir = node->children[kLeft] ? kLeft : kRight;
+          }
+        } // while(node)
+
+          // Step 4: Update weights from balance to parent of node determined
+          // in step 3 above rotating (2 or 3 node rotations) as needed.
+        while (balance)
+        {
+          // Break when balance node reaches the parent of replacement node
+          if (balance->children[balance->dir] == std::nullptr)
+          {
+            break;
+          }
+
+          // If balance node is balanced already (kNeither) then just imbalance
+          // the node in the opposite direction of the node being removed
+          if (balance->weight == kNeither)
+          {
+            balance->weight = 1 - balance->dir;
+          }
+          // If balance node is imbalanced in the opposite direction of the
+          // node being removed then the node now becomes balanced
+          else if (balance->weight == balance->dir)
+          {
+            balance->weight = kNeither;
+          }
+          // Otherwise a rotation is required at this node
+          else
+          {
+            int weight = balance->children[1 - balance->dir]->weight;
+            // Perform a 3 node rotation if weight is same as balance->dir
+            if (weight == balance->dir)
+            {
+              // Is the root node being rebalanced (no parent)
+              if (balance->parent == std::nullptr)
+              {
+                rotate_3node(root_node, 1 - balance->dir,
+                  balance->children[1 - balance->dir]->children[balance->dir]->weight);
+              }
+              else
+              {
+                rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir,
+                  balance->children[1 - balance->dir]->children[balance->dir]->weight);
+              }
+            }
+            // Already balanced, rebalance and make it heavy in opposite
+            // direction of the node being removed
+            else if (weight == kNeither)
+            {
+              // Is the root node being rebalanced (no parent)
+              if (balance->parent == std::nullptr)
+              {
+                rotate_2node(root_node, 1 - balance->dir);
+                root_node->weight = balance->dir;
+              }
+              else
+              {
+                // Balance parent might change during rotate, keep local copy
+                // to old parent so its weight can be updated after the 2 node
+                // rotate is completed
+                Node* old_parent = balance->parent;
+                rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
+                old_parent->children[old_parent->dir]->weight = balance->dir;
+              }
+              // Update balance node weight in opposite direction of node removed
+              balance->weight = 1 - balance->dir;
+            }
+            // Rebalance and leave it balanced
+            else
+            {
+              // Is the root node being rebalanced (no parent)
+              if (balance->parent == std::nullptr)
+              {
+                rotate_2node(root_node, 1 - balance->dir);
+              }
+              else
+              {
+                rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
+              }
+            }
+          }
+
+          // Next balance node to consider
+          balance = balance->children[balance->dir];
+        } // while(balance)
+
+          // Step 5: Swap found with node (replacement)
+        if (found->parent)
+        {
+          // Handle traditional case
+          detach_node(found->parent->children[found->parent->dir],
+            node->parent->children[node->parent->dir]);
+        }
+        // Handle root node removal
+        else
+        {
+          // Valid replacement node for root node being removed?
+          if (node->parent)
+          {
+            detach_node(root_node, node->parent->children[node->parent->dir]);
+          }
+          else
+          {
+            // Found node and replacement node are both root node
+            detach_node(root_node, root_node);
+          }
+        }
+
+        // One less.
+        --current_size;
+
+        // Destroy the node detached above
+        destroy_data_node(data_node);
+      } // if(found)
+    }
+
+    // Disable copy construction.
+    imultimap(const imultimap&);
+  };
+
+  //*************************************************************************
+  /// A templated multimap implementation that uses a fixed size buffer.
+  //*************************************************************************
+  template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> >
+  class multimap : public etl::imultimap<TKey, TValue, TCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    multimap()
+      : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
+    {
+      etl::imultimap<TKey, TValue, TCompare>::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    multimap(const multimap& other)
+      : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
+    {
+      etl::imultimap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    multimap(TIterator first, TIterator last)
+      : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
+    {
+      etl::imultimap<TKey, TValue, TCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~multimap()
+    {
+      etl::imultimap<TKey, TValue, TCompare>::initialise();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    multimap& operator = (const multimap& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        etl::imultimap<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    /// The pool of data nodes used for the multimap.
+    etl::pool<typename etl::imultimap<TKey, TValue, TCompare>::Data_Node, MAX_SIZE> node_pool;
+  };
+}
+
+//***************************************************************************
+/// Equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator ==(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
+{
+  return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//***************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator !=(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
+{
+  return !(lhs == rhs);
+}
+
+//*************************************************************************
+/// Less than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator <(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
+{
+  return std::lexicographical_compare(lhs.begin(),
+    lhs.end(),
+    rhs.begin(),
+    rhs.end());
+}
+
+//*************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator >(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
+{
+  return (rhs < lhs);
+}
+
+//*************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than or equal
+/// to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator <=(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
+{
+  return !(lhs > rhs);
+}
+
+//*************************************************************************
+/// Greater than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than or
+/// equal to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename TKey, typename TMapped, typename TKeyCompare>
+bool operator >=(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
+{
+  return !(lhs < rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multiset.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,2025 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+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 __ETL_MULTISET__
+#define __ETL_MULTISET__
+
+#include <stddef.h>
+#include <iterator>
+#include <algorithm>
+#include <functional>
+
+#include "platform.h"
+#include "parameter_type.h"
+#include "container.h"
+#include "pool.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "debug_count.h"
+#include "nullptr.h"
+#include "type_traits.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#undef ETL_FILE
+#define ETL_FILE "10"
+
+//*****************************************************************************
+/// A multiset with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the set.
+  ///\ingroup set
+  //***************************************************************************
+  class multiset_exception : public etl::exception
+  {
+  public:
+
+    multiset_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Full exception for the set.
+  ///\ingroup set
+  //***************************************************************************
+  class multiset_full : public etl::multiset_exception
+  {
+  public:
+
+    multiset_full(string_type file_name_, numeric_type line_number_)
+      : etl::multiset_exception(ETL_ERROR_TEXT("multiset:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Map out of bounds exception.
+  ///\ingroup set
+  //***************************************************************************
+  class multiset_out_of_bounds : public etl::multiset_exception
+  {
+  public:
+
+    multiset_out_of_bounds(string_type file_name_, numeric_type line_number_)
+      : etl::multiset_exception(ETL_ERROR_TEXT("multiset:bounds", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the set.
+  ///\ingroup set
+  //***************************************************************************
+  class multiset_iterator : public etl::multiset_exception
+  {
+  public:
+
+    multiset_iterator(string_type file_name_, numeric_type line_number_)
+      : etl::multiset_exception(ETL_ERROR_TEXT("multiset:iterator", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for all sets.
+  ///\ingroup set
+  //***************************************************************************
+  class multiset_base
+  {
+  public:
+
+    typedef size_t size_type; ///< The type used for determining the size of set.
+
+    //*************************************************************************
+    /// Gets the size of the set.
+    //*************************************************************************
+    size_type size() const
+    {
+      return current_size;
+    }
+
+    //*************************************************************************
+    /// Gets the maximum possible size of the set.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Checks to see if the set is empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return current_size == 0;
+    }
+
+    //*************************************************************************
+    /// Checks to see if the set is full.
+    //*************************************************************************
+    bool full() const
+    {
+      return current_size == CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the vector.
+    ///\return The capacity of the vector.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return max_size() - size();
+    }
+
+  protected:
+
+    enum
+    {
+      kLeft,
+      kRight,
+      kNeither
+    };
+
+    //*************************************************************************
+    /// The node element in the multiset.
+    //*************************************************************************
+    struct Node
+    {
+      //***********************************************************************
+      /// Constructor
+      //***********************************************************************
+      Node() :
+        weight(kNeither),
+        dir(kNeither)
+      {
+      }
+
+      //***********************************************************************
+      /// Marks the node as a leaf.
+      //***********************************************************************
+      void mark_as_leaf()
+      {
+        weight = kNeither;
+        dir = kNeither;
+        parent = std::nullptr;
+        children[0] = std::nullptr;
+        children[1] = std::nullptr;
+      }
+
+      Node* parent;
+      Node* children[2];
+      uint_least8_t weight;
+      uint_least8_t dir;
+    };
+
+    //*************************************************************************
+    /// The constructor that is called from derived classes.
+    //*************************************************************************
+    multiset_base(size_type max_size_)
+      : current_size(0)
+      , CAPACITY(max_size_)
+      , root_node(std::nullptr)
+    {
+    }
+
+    //*************************************************************************
+    /// Attach the provided node to the position provided
+    //*************************************************************************
+    void attach_node(Node* parent, Node*& position, Node& node)
+    {
+      // Mark new node as leaf on attach to tree at position provided
+      node.mark_as_leaf();
+
+      // Keep track of this node's parent
+      node.parent = parent;
+
+      // Add the node here
+      position = &node;
+
+      // One more.
+      ++current_size;
+    }
+
+    //*************************************************************************
+    /// Detach the node at the position provided
+    //*************************************************************************
+    void detach_node(Node*& position, Node*& replacement)
+    {
+      // Make temporary copy of actual nodes involved because we might lose
+      // their references in the process (e.g. position is the same as
+      // replacement or replacement is a child of position)
+      Node* detached = position;
+      Node* swap = replacement;
+
+      // Update current position to point to swap (replacement) node first
+      position = swap;
+
+      // Update replacement node to point to child in opposite direction
+      // otherwise we might lose the other child of the swap node
+      replacement = swap->children[1 - swap->dir];
+
+      // Point swap node to detached node's parent, children and weight
+      swap->parent = detached->parent;
+      swap->children[kLeft] = detached->children[kLeft];
+      swap->children[kRight] = detached->children[kRight];
+      if (swap->children[kLeft])
+      {
+        swap->children[kLeft]->parent = swap;
+      }
+      if (swap->children[kRight])
+      {
+        swap->children[kRight]->parent = swap;
+      }
+      swap->weight = detached->weight;
+    }
+
+    //*************************************************************************
+    /// Balance the critical node at the position provided as needed
+    //*************************************************************************
+    void balance_node(Node*& critical_node)
+    {
+      // Step 1: Update weights for all children of the critical node up to the
+      // newly inserted node. This step is costly (in terms of traversing nodes
+      // multiple times during insertion) but doesn't require as much recursion
+      Node* weight_node = critical_node->children[critical_node->dir];
+      while (weight_node)
+      {
+        // Keep going until we reach a terminal node (dir == kNeither)
+        if (kNeither != weight_node->dir)
+        {
+          // Does this insert balance the previous weight factor value?
+          if (weight_node->weight == 1 - weight_node->dir)
+          {
+            weight_node->weight = kNeither;
+          }
+          else
+          {
+            weight_node->weight = weight_node->dir;
+          }
+
+          // Update weight factor node to point to next node
+          weight_node = weight_node->children[weight_node->dir];
+        }
+        else
+        {
+          // Stop loop, terminal node found
+          break;
+        }
+      } // while(weight_node)
+
+        // Step 2: Update weight for critical_node or rotate tree to balance node
+      if (kNeither == critical_node->weight)
+      {
+        critical_node->weight = critical_node->dir;
+      }
+      // If direction is different than weight, then it will now be balanced
+      else if (critical_node->dir != critical_node->weight)
+      {
+        critical_node->weight = kNeither;
+      }
+      // Rotate is required to balance the tree at the critical node
+      else
+      {
+        // If critical node matches child node direction then perform a two
+        // node rotate in the direction of the critical node
+        if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
+        {
+          rotate_2node(critical_node, critical_node->dir);
+        }
+        // Otherwise perform a three node rotation in the direction of the
+        // critical node
+        else
+        {
+          rotate_3node(critical_node, critical_node->dir,
+            critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the node whose key would go before all the other keys from the
+    /// position provided
+    //*************************************************************************
+    Node* find_limit_node(Node* position, const int8_t dir) const
+    {
+      // Something at this position and in the direction specified? keep going
+      Node* limit_node = position;
+      while (limit_node && limit_node->children[dir])
+      {
+        limit_node = limit_node->children[dir];
+      }
+
+      // Return the limit node position found
+      return limit_node;
+    }
+
+    //*************************************************************************
+    /// Find the next node in sequence from the node provided
+    //*************************************************************************
+    void next_node(Node*& position) const
+    {
+      if (position)
+      {
+        // Is there a tree on the right? then find the minimum of that tree
+        if (position->children[kRight])
+        {
+          // Return minimum node found
+          position = find_limit_node(position->children[kRight], kLeft);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = position->parent; // find_parent_node(root_node, position);
+                                       // Repeat while previous position was on right side of parent tree
+          } while (parent && parent->children[kRight] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the next node in sequence from the node provided
+    //*************************************************************************
+    void next_node(const Node*& position) const
+    {
+      if (position)
+      {
+        // Is there a tree on the right? then find the minimum of that tree
+        if (position->children[kRight])
+        {
+          // Return minimum node found
+          position = find_limit_node(position->children[kRight], kLeft);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          const Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = position->parent;
+            // Repeat while previous position was on right side of parent tree
+          } while (parent && parent->children[kRight] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the previous node in sequence from the node provided
+    //*************************************************************************
+    void prev_node(Node*& position) const
+    {
+      // If starting at the terminal end, the previous node is the maximum node
+      // from the root
+      if (!position)
+      {
+        position = find_limit_node(root_node, kRight);
+      }
+      else
+      {
+        // Is there a tree on the left? then find the maximum of that tree
+        if (position->children[kLeft])
+        {
+          // Return maximum node found
+          position = find_limit_node(position->children[kLeft], kRight);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = position->parent;
+            // Repeat while previous position was on left side of parent tree
+          } while (parent && parent->children[kLeft] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the previous node in sequence from the node provided
+    //*************************************************************************
+    void prev_node(const Node*& position) const
+    {
+      // If starting at the terminal end, the previous node is the maximum node
+      // from the root
+      if (!position)
+      {
+        position = find_limit_node(root_node, kRight);
+      }
+      else
+      {
+        // Is there a tree on the left? then find the maximum of that tree
+        if (position->children[kLeft])
+        {
+          // Return maximum node found
+          position = find_limit_node(position->children[kLeft], kRight);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          const Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = position->parent;
+            // Repeat while previous position was on left side of parent tree
+          } while (parent && parent->children[kLeft] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Rotate two nodes at the position provided the to balance the tree
+    //*************************************************************************
+    void rotate_2node(Node*& position, uint_least8_t dir)
+    {
+      //     A            C             A          B
+      //   B   C   ->   A   E   OR    B   C  ->  D   A
+      //      D E      B D           D E            E C
+      // C (new position) becomes the root
+      // A (position) takes ownership of D as its children[kRight] child
+      // C (new position) takes ownership of A as its left child
+      //                 OR
+      // B (new position) becomes the root
+      // A (position) takes ownership of E as its left child
+      // B (new position) takes ownership of A as its right child
+
+      // Capture new root (either B or C depending on dir) and its parent
+      Node* new_root = position->children[dir];
+
+      // Replace position's previous child with new root's other child
+      position->children[dir] = new_root->children[1 - dir];
+      // Update new root's other child parent pointer
+      if (position->children[dir])
+      {
+        position->children[dir]->parent = position;
+      }
+
+      // New root's parent becomes current position's parent
+      new_root->parent = position->parent;
+      new_root->children[1 - dir] = position;
+      new_root->dir = 1 - dir;
+
+      // Clear weight factor from current position
+      position->weight = kNeither;
+      // Position's parent becomes new_root
+      position->parent = new_root;
+      position = new_root;
+      // Clear weight factor from new root
+      position->weight = kNeither;
+    }
+
+    //*************************************************************************
+    /// Rotate three nodes at the position provided the to balance the tree
+    //*************************************************************************
+    void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third)
+    {
+      //        __A__             __E__            __A__             __D__
+      //      _B_    C    ->     B     A    OR    B    _C_   ->     A     C
+      //     D   E              D F   G C             D   E        B F   G E
+      //        F G                                  F G
+      // E (new position) becomes the root
+      // B (position) takes ownership of F as its left child
+      // A takes ownership of G as its right child
+      //                  OR
+      // D (new position) becomes the root
+      // A (position) takes ownership of F as its right child
+      // C takes ownership of G as its left child
+
+      // Capture new root (either E or D depending on dir)
+      Node* new_root = position->children[dir]->children[1 - dir];
+      // Set weight factor for B or C based on F or G existing and being a different than dir
+      position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither;
+
+      // Detach new root from its tree (replace with new roots child)
+      position->children[dir]->children[1 - dir] = new_root->children[dir];
+      // Update new roots child parent pointer
+      if (new_root->children[dir])
+      {
+        new_root->children[dir]->parent = position->children[dir];
+      }
+
+      // Attach current left tree to new root and update its parent
+      new_root->children[dir] = position->children[dir];
+      position->children[dir]->parent = new_root;
+
+      // Set weight factor for A based on F or G
+      position->weight = third != kNeither && third == dir ? 1 - dir : kNeither;
+
+      // Move new root's right tree to current roots left tree
+      position->children[dir] = new_root->children[1 - dir];
+      if (new_root->children[1 - dir])
+      {
+        new_root->children[1 - dir]->parent = position;
+      }
+
+      // Attach current root to new roots right tree and assume its parent
+      new_root->parent = position->parent;
+      new_root->children[1 - dir] = position;
+      new_root->dir = 1 - dir;
+
+      // Update current position's parent and replace with new root
+      position->parent = new_root;
+      position = new_root;
+      // Clear weight factor for new current position
+      position->weight = kNeither;
+    }
+
+    size_type current_size;   ///< The number of the used nodes.
+    const size_type CAPACITY; ///< The maximum size of the set.
+    Node* root_node;          ///< The node that acts as the multiset root.
+    etl::debug_count construct_count;
+  };
+
+  //***************************************************************************
+  /// A templated base for all etl::multiset types.
+  ///\ingroup set
+  //***************************************************************************
+  template <typename T, typename TCompare>
+  class imultiset : public etl::multiset_base
+  {
+  public:
+
+    typedef const T                        key_type;
+    typedef const T                        value_type;
+    typedef TCompare                       key_compare;
+    typedef TCompare                       value_compare;
+    typedef value_type&                    const_reference;
+    typedef value_type*                    const_pointer;
+    typedef size_t                         size_type;
+
+    //*************************************************************************
+    /// How to compare two key elements.
+    //*************************************************************************
+    struct key_comp
+    {
+      bool operator ()(key_type& key1, key_type& key2) const
+      {
+        return key_compare()(key1, key2);
+      }
+    };
+
+    //*************************************************************************
+    /// How to compare two value elements.
+    //*************************************************************************
+    struct value_comp
+    {
+      bool operator ()(value_type& value1, value_type& value2) const
+      {
+        return value_compare()(value1, value2);
+      }
+    };
+
+  protected:
+
+    //*************************************************************************
+    /// The data node element in the multiset.
+    //*************************************************************************
+    struct Data_Node : public Node
+    {
+      explicit Data_Node(value_type value_)
+        : value(value_)
+      {
+      }
+
+      value_type value;
+    };
+
+    /// Defines the key value parameter type
+    typedef typename etl::parameter_type<T>::type key_parameter_t;
+
+    //*************************************************************************
+    /// How to compare node elements.
+    //*************************************************************************
+    bool node_comp(const Data_Node& node1, const Data_Node& node2) const
+    {
+      return key_compare()(node1.value, node2.value);
+    }
+    bool node_comp(const Data_Node& node, key_parameter_t key) const
+    {
+      return key_compare()(node.value, key);
+    }
+    bool node_comp(key_parameter_t key, const Data_Node& node) const
+    {
+      return key_compare()(key, node.value);
+    }
+
+  private:
+
+    /// The pool of data nodes used in the multiset.
+    ipool* p_node_pool;
+
+    //*************************************************************************
+    /// Downcast a Node* to a Data_Node*
+    //*************************************************************************
+    static Data_Node* data_cast(Node* p_node)
+    {
+      return static_cast<Data_Node*>(p_node);
+    }
+
+    //*************************************************************************
+    /// Downcast a Node& to a Data_Node&
+    //*************************************************************************
+    static Data_Node& data_cast(Node& node)
+    {
+      return static_cast<Data_Node&>(node);
+    }
+
+    //*************************************************************************
+    /// Downcast a const Node* to a const Data_Node*
+    //*************************************************************************
+    static const Data_Node* data_cast(const Node* p_node)
+    {
+      return static_cast<const Data_Node*>(p_node);
+    }
+
+    //*************************************************************************
+    /// Downcast a const Node& to a const Data_Node&
+    //*************************************************************************
+    static const Data_Node& data_cast(const Node& node)
+    {
+      return static_cast<const Data_Node&>(node);
+    }
+
+  public:
+    //*************************************************************************
+    /// iterator.
+    //*************************************************************************
+    class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+    {
+    public:
+
+      friend class imultiset;
+
+      iterator()
+        : p_multiset(std::nullptr)
+        , p_node(std::nullptr)
+      {
+      }
+
+      iterator(imultiset& multiset)
+        : p_multiset(&multiset)
+        , p_node(std::nullptr)
+      {
+      }
+
+      iterator(imultiset& multiset, Node* node)
+        : p_multiset(&multiset)
+        , p_node(node)
+      {
+      }
+
+      iterator(const iterator& other)
+        : p_multiset(other.p_multiset)
+        , p_node(other.p_node)
+      {
+      }
+
+      ~iterator()
+      {
+      }
+
+      iterator& operator ++()
+      {
+        p_multiset->next_node(p_node);
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        p_multiset->next_node(p_node);
+        return temp;
+      }
+
+      iterator& operator --()
+      {
+        p_multiset->prev_node(p_node);
+        return *this;
+      }
+
+      iterator operator --(int)
+      {
+        iterator temp(*this);
+        p_multiset->prev_node(p_node);
+        return temp;
+      }
+
+      iterator operator =(const iterator& other)
+      {
+        p_multiset = other.p_multiset;
+        p_node = other.p_node;
+        return *this;
+      }
+
+      const_reference operator *() const
+      {
+        return imultiset::data_cast(p_node)->value;
+      }
+
+      const_pointer operator &() const
+      {
+        return &(imultiset::data_cast(p_node)->value);
+      }
+
+      const_pointer operator ->() const
+      {
+        return &(imultiset::data_cast(p_node)->value);
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.p_multiset == rhs.p_multiset && lhs.p_node == rhs.p_node;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      // Pointer to multiset associated with this iterator
+      imultiset* p_multiset;
+
+      // Pointer to the current node for this iterator
+      Node* p_node;
+    };
+    friend class iterator;
+
+    //*************************************************************************
+    /// const_iterator
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+    {
+    public:
+
+      friend class imultiset;
+
+      const_iterator()
+        : p_multiset(std::nullptr)
+        , p_node(std::nullptr)
+      {
+      }
+
+      const_iterator(const imultiset& multiset)
+        : p_multiset(&multiset)
+        , p_node(std::nullptr)
+      {
+      }
+
+      const_iterator(const imultiset& multiset, const Node* node)
+        : p_multiset(&multiset)
+        , p_node(node)
+      {
+      }
+
+      const_iterator(const typename imultiset::iterator& other)
+        : p_multiset(other.p_multiset)
+        , p_node(other.p_node)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : p_multiset(other.p_multiset)
+        , p_node(other.p_node)
+      {
+      }
+
+      ~const_iterator()
+      {
+      }
+
+      const_iterator& operator ++()
+      {
+        p_multiset->next_node(p_node);
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        p_multiset->next_node(p_node);
+        return temp;
+      }
+
+      const_iterator& operator --()
+      {
+        p_multiset->prev_node(p_node);
+        return *this;
+      }
+
+      const_iterator operator --(int)
+      {
+        const_iterator temp(*this);
+        p_multiset->prev_node(p_node);
+        return temp;
+      }
+
+      const_iterator operator =(const const_iterator& other)
+      {
+        p_multiset = other.p_multiset;
+        p_node = other.p_node;
+        return *this;
+      }
+
+      const_reference operator *() const
+      {
+        return imultiset::data_cast(p_node)->value;
+      }
+
+      const_pointer operator &() const
+      {
+        return imultiset::data_cast(p_node)->value;
+      }
+
+      const_pointer operator ->() const
+      {
+        return &(imultiset::data_cast(p_node)->value);
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.p_multiset == rhs.p_multiset && lhs.p_node == rhs.p_node;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+      // Pointer to multiset associated with this iterator
+      const imultiset* p_multiset;
+
+      // Pointer to the current node for this iterator
+      const Node* p_node;
+    };
+    friend class const_iterator;
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+
+    //*************************************************************************
+    /// Gets the beginning of the multiset.
+    //*************************************************************************
+    iterator begin()
+    {
+      return iterator(*this, find_limit_node(root_node, kLeft));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the multiset.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(*this, find_limit_node(root_node, kLeft));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the multiset.
+    //*************************************************************************
+    iterator end()
+    {
+      return iterator(*this);
+    }
+
+    //*************************************************************************
+    /// Gets the end of the multiset.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(*this);
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the multiset.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(*this, find_limit_node(root_node, kLeft));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the multiset.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(*this);
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(iterator(*this));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(const_iterator(*this));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(const_iterator(*this));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
+    }
+
+    //*********************************************************************
+    /// Assigns values to the multiset.
+    /// If asserts or exceptions are enabled, emits set_full if the multiset does not have enough free space.
+    /// If asserts or exceptions are enabled, emits set_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+      initialise();
+      insert(first, last);
+    }
+
+    //*************************************************************************
+    /// Clears the multiset.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*********************************************************************
+    /// Counts the number of elements that contain the key specified.
+    ///\param key The key to search for.
+    ///\return 1 if element was found, 0 otherwise.
+    //*********************************************************************
+    size_type count(key_parameter_t key) const
+    {
+      return count_nodes(key);
+    }
+
+    //*************************************************************************
+    /// Returns two iterators with bounding (lower bound, upper bound) the key
+    /// provided
+    //*************************************************************************
+    std::pair<iterator, iterator> equal_range(const value_type& key)
+    {
+      return std::make_pair<iterator, iterator>(
+        iterator(*this, find_lower_node(root_node, key)),
+        iterator(*this, find_upper_node(root_node, key)));
+    }
+
+    //*************************************************************************
+    /// Returns two const iterators with bounding (lower bound, upper bound)
+    /// the key provided.
+    //*************************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(const value_type& key) const
+    {
+      return std::make_pair<const_iterator, const_iterator>(
+        const_iterator(*this, find_lower_node(root_node, key)),
+        const_iterator(*this, find_upper_node(root_node, key)));
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    void erase(iterator position)
+    {
+      // Remove the node by its node specified in iterator position
+      (void)erase(const_iterator(position));
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    iterator erase(const_iterator position)
+    {
+      // Cast const away from node to be removed. This is necessary because the
+      // STL definition of this method requires we provide the next node in the
+      // sequence as an iterator.
+      Node* node = const_cast<Node*>(position.p_node);
+      iterator next(*this, node);
+      ++next;
+
+      // Remove the non-const node provided
+      remove_node(node);
+
+      return next;
+    }
+
+    //*************************************************************************
+    // Erase the key specified.
+    //*************************************************************************
+    size_type erase(key_parameter_t key_value)
+    {
+      // Number of nodes removed
+      size_type d = 0;
+      const_iterator lower(*this, find_lower_node(root_node, key_value));
+      const_iterator upper(*this, find_upper_node(root_node, key_value));
+      while (lower != upper)
+      {
+        // Increment count for each node removed
+        ++d;
+        // Remove node using the other erase method
+        (void)erase(lower++);
+      }
+
+      // Return the total count erased
+      return d;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    //*************************************************************************
+    iterator erase(iterator first, iterator last)
+    {
+      iterator next;
+      while (first != last)
+      {
+        next = erase(const_iterator(first++));
+      }
+
+      return next;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    //*************************************************************************
+    iterator erase(const_iterator first, const_iterator last)
+    {
+      iterator next;
+      while (first != last)
+      {
+        next = erase(first++);
+      }
+
+      return next;
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    iterator find(key_parameter_t key_value)
+    {
+      return iterator(*this, find_node(root_node, key_value));
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    const_iterator find(key_parameter_t key_value) const
+    {
+      return const_iterator(*this, find_node(root_node, key_value));
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the multiset.
+    /// If asserts or exceptions are enabled, emits set_full if the multiset is already full.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(const value_type& value)
+    {
+      // Default to no inserted node
+      Node* inserted_node = std::nullptr;
+
+      ETL_ASSERT(!full(), ETL_ERROR(multiset_full));
+
+      // Get next available free node
+      Data_Node& node = allocate_data_node(value);
+
+      // Obtain the inserted node (might be std::nullptr if node was a duplicate)
+      inserted_node = insert_node(root_node, node);
+
+      // Insert node into tree and return iterator to new node location in tree
+      return iterator(*this, inserted_node);
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the multiset starting at the position recommended.
+    /// If asserts or exceptions are enabled, emits set_full if the multiset is already full.
+    ///\param position The position that would precede the value to insert.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator /*position*/, const value_type& value)
+    {
+      // Ignore position provided and just do a normal insert
+      return insert(value);
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the multiset starting at the position recommended.
+    /// If asserts or exceptions are enabled, emits set_full if the multiset is already full.
+    ///\param position The position that would precede the value to insert.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(const_iterator /*position*/, const value_type& value)
+    {
+      // Ignore position provided and just do a normal insert
+      return insert(value);
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the multiset.
+    /// If asserts or exceptions are enabled, emits set_full if the multiset does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Returns an iterator pointing to the first element in the container
+    /// whose key is not considered to go before the key provided or end()
+    /// if all keys are considered to go before the key provided.
+    ///\return An iterator pointing to the element not before key or end()
+    //*********************************************************************
+    iterator lower_bound(key_parameter_t key)
+    {
+      return iterator(*this, find_lower_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator pointing to the first element in the
+    /// container whose key is not considered to go before the key provided
+    /// or end() if all keys are considered to go before the key provided.
+    ///\return An const_iterator pointing to the element not before key or end()
+    //*********************************************************************
+    const_iterator lower_bound(key_parameter_t key) const
+    {
+      return const_iterator(*this, find_lower_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Returns an iterator pointing to the first element in the container
+    /// whose key is not considered to go after the key provided or end()
+    /// if all keys are considered to go after the key provided.
+    ///\return An iterator pointing to the element after key or end()
+    //*********************************************************************
+    iterator upper_bound(key_parameter_t key)
+    {
+      return iterator(*this, find_upper_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator pointing to the first element in the
+    /// container whose key is not considered to go after the key provided
+    /// or end() if all keys are considered to go after the key provided.
+    ///\return An const_iterator pointing to the element after key or end()
+    //*********************************************************************
+    const_iterator upper_bound(key_parameter_t key) const
+    {
+      return const_iterator(*this, find_upper_node(root_node, key));
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    imultiset& operator = (const imultiset& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    imultiset(etl::ipool& node_pool, size_t max_size_)
+      : etl::multiset_base(max_size_)
+      , p_node_pool(&node_pool)
+    {
+    }
+
+    //*************************************************************************
+    /// Initialise the multiset.
+    //*************************************************************************
+    void initialise()
+    {
+      erase(begin(), end());
+    }
+
+  private:
+
+    //*************************************************************************
+    /// Allocate a Data_Node.
+    //*************************************************************************
+    Data_Node& allocate_data_node(value_type value)
+    {
+      Data_Node& node = *p_node_pool->allocate<Data_Node>();
+      ::new ((void*)&node.value) value_type(value);
+      ++construct_count;
+      return node;
+    }
+
+    //*************************************************************************
+    /// Destroy a Data_Node.
+    //*************************************************************************
+    void destroy_data_node(Data_Node& node)
+    {
+      node.value.~value_type();
+      p_node_pool->release(&node);
+      --construct_count;
+    }
+
+    //*************************************************************************
+    /// Count the nodes that match the key provided
+    //*************************************************************************
+    size_type count_nodes(key_parameter_t key) const
+    {
+      // Number of nodes that match the key provided result
+      size_type result = 0;
+
+      // Find lower and upper nodes for the key provided
+      const Node* lower = find_lower_node(root_node, key);
+      const Node* upper = find_upper_node(root_node, key);
+
+      // Loop from lower node to upper node and find nodes that match
+      while (lower != upper)
+      {
+        // Downcast found to Data_Node class for comparison and other operations
+        const Data_Node& data_node = imultiset::data_cast(*lower);
+
+        if (!node_comp(key, data_node) && !node_comp(data_node, key))
+        {
+          // This node matches the key provided
+          ++result;
+        }
+
+        // Move on to the next node
+        next_node(lower);
+      }
+
+      // Return the number of nodes that match
+      return result;
+    }
+
+    //*************************************************************************
+    /// Find the value matching the node provided
+    //*************************************************************************
+    Node* find_node(Node* position, key_parameter_t key) const
+    {
+      Node* found = std::nullptr;
+      while (position)
+      {
+        // Downcast found to Data_Node class for comparison and other operations
+        Data_Node& data_node = imultiset::data_cast(*position);
+        // Compare the node value to the current position value
+        if (node_comp(key, data_node))
+        {
+          // Keep searching for the node on the left
+          position = position->children[kLeft];
+        }
+        else if (node_comp(data_node, key))
+        {
+          // Keep searching for the node on the right
+          position = position->children[kRight];
+        }
+        else
+        {
+          // We found one, keep looking for more on the left
+          found = position;
+          position = position->children[kLeft];
+        }
+      }
+
+      // Return the node found (might be std::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the value matching the node provided
+    //*************************************************************************
+    const Node* find_node(const Node* position, key_parameter_t key) const
+    {
+      const Node* found = std::nullptr;
+      while (position)
+      {
+        // Downcast found to Data_Node class for comparison and other operations
+        const Data_Node& data_node = imultiset::data_cast(*position);
+        // Compare the node value to the current position value
+        if (node_comp(key, data_node))
+        {
+          // Keep searching for the node on the left
+          position = position->children[kLeft];
+        }
+        else if (node_comp(data_node, key))
+        {
+          // Keep searching for the node on the right
+          position = position->children[kRight];
+        }
+        else
+        {
+          // We found one, keep looking for more on the left
+          found = position;
+          position = position->children[kLeft];
+        }
+      }
+
+      // Return the node found (might be std::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the node whose key is not considered to go before the key provided
+    //*************************************************************************
+    Node* find_lower_node(Node* position, key_parameter_t key) const
+    {
+      // Something at this position? keep going
+      Node* lower_node = std::nullptr;
+      while (position)
+      {
+        // Downcast lower node to Data_Node reference for key comparisons
+        Data_Node& data_node = imultiset::data_cast(*position);
+        // Compare the key value to the current lower node key value
+        if (node_comp(key, data_node))
+        {
+          lower_node = position;
+          if (position->children[kLeft])
+          {
+            position = position->children[kLeft];
+          }
+          else
+          {
+            // Found lowest node
+            break;
+          }
+        }
+        else if (node_comp(data_node, key))
+        {
+          position = position->children[kRight];
+        }
+        else
+        {
+          // Make note of current position, but keep looking to left for more
+          lower_node = position;
+          position = position->children[kLeft];
+        }
+      }
+
+      // Return the lower_node position found
+      return lower_node;
+    }
+
+    //*************************************************************************
+    /// Find the node whose key is considered to go after the key provided
+    //*************************************************************************
+    Node* find_upper_node(Node* position, key_parameter_t key) const
+    {
+      // Keep track of parent of last upper node
+      Node* upper_node = std::nullptr;
+      // Has an equal node been found? start with no
+      bool found = false;
+      while (position)
+      {
+        // Downcast position to Data_Node reference for key comparisons
+        Data_Node& data_node = imultiset::data_cast(*position);
+        // Compare the key value to the current upper node key value
+        if (node_comp(data_node, key))
+        {
+          position = position->children[kRight];
+        }
+        else if (node_comp(key, data_node))
+        {
+          upper_node = position;
+          // If a node equal to key hasn't been found go left
+          if (!found && position->children[kLeft])
+          {
+            position = position->children[kLeft];
+          }
+          else
+          {
+            break;
+          }
+        }
+        else
+        {
+          // We found an equal item, break on next bigger item
+          found = true;
+          next_node(position);
+        }
+      }
+
+      // Return the upper node position found (might be std::nullptr)
+      return upper_node;
+    }
+
+    //*************************************************************************
+    /// Insert a node.
+    //*************************************************************************
+    Node* insert_node(Node*& position, Data_Node& node)
+    {
+      // Find the location where the node belongs
+      Node* found = position;
+
+      // Was position provided not empty? then find where the node belongs
+      if (position)
+      {
+        // Find the critical parent node (default to std::nullptr)
+        Node* critical_parent_node = std::nullptr;
+        Node* critical_node = root_node;
+
+        while (found)
+        {
+          // Search for critical weight node (all nodes whose weight factor
+          // is set to kNeither (balanced)
+          if (kNeither != found->weight)
+          {
+            critical_node = found;
+          }
+
+          // Downcast found to Data_Node class for comparison and other operations
+          Data_Node& found_data_node = imultiset::data_cast(*found);
+
+          // Is the node provided to the left of the current position?
+          if (node_comp(node, found_data_node))
+          {
+            // Update direction taken to insert new node in parent node
+            found->dir = kLeft;
+          }
+          // Is the node provided to the right of the current position?
+          else if (node_comp(found_data_node, node))
+          {
+            // Update direction taken to insert new node in parent node
+            found->dir = kRight;
+          }
+          else
+          {
+            // Update direction taken to insert new node in parent (and
+            // duplicate) node to the right.
+            found->dir = kRight;
+          }
+
+          // Is there a child of this parent node?
+          if (found->children[found->dir])
+          {
+            // Will this node be the parent of the next critical node whose
+            // weight factor is set to kNeither (balanced)?
+            if (kNeither != found->children[found->dir]->weight)
+            {
+              critical_parent_node = found;
+            }
+
+            // Keep looking for empty spot to insert new node
+            found = found->children[found->dir];
+          }
+          else
+          {
+            // Attach node as a child of the parent node found
+            attach_node(found, found->children[found->dir], node);
+
+            // Return newly added node
+            found = found->children[found->dir];
+
+            // Exit loop
+            break;
+          }
+        }
+
+        // Was a critical node found that should be checked for balance?
+        if (critical_node)
+        {
+          if (critical_parent_node == std::nullptr && critical_node == root_node)
+          {
+            balance_node(root_node);
+          }
+          else if (critical_parent_node == std::nullptr && critical_node == position)
+          {
+            balance_node(position);
+          }
+          else
+          {
+            balance_node(critical_parent_node->children[critical_parent_node->dir]);
+          }
+        }
+      }
+      else
+      {
+        // Attatch node to current position (which is assumed to be root)
+        attach_node(std::nullptr, position, node);
+
+        // Return newly added node at current position
+        found = position;
+      }
+
+      // Return the node found (might be std::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Remove the node specified from somewhere starting at the position
+    /// provided
+    //*************************************************************************
+    void remove_node(Node* node)
+    {
+      // If valid found node was provided then proceed with steps 1 through 5
+      if (node)
+      {
+        // Downcast found node provided to Data_Node class
+        Data_Node& data_node = imultiset::data_cast(*node);
+
+        // Keep track of node as found node
+        Node* found = node;
+
+        // Step 1: Mark path from node provided back to the root node using the
+        // internal temporary dir member value and using the parent pointer. This
+        // will allow us to avoid recursion in finding the node in a tree that
+        //might contain duplicate keys to be found.
+        while (node)
+        {
+          if (node->parent)
+          {
+            // Which direction does parent use to get to this node?
+            node->parent->dir =
+              node->parent->children[kLeft] == node ? kLeft : kRight;
+
+            // Make this nodes parent the next node
+            node = node->parent;
+          }
+          else
+          {
+            // Root node found - break loop
+            break;
+          }
+        }
+
+        // Step 2: Follow the path provided above until we reach the node
+        // provided and look for the balance node to start rebalancing the tree
+        // from (up to the replacement node that will be found in step 3)
+        Node* balance = root_node;
+        while (node)
+        {
+          // Did we reach the node provided originally (found) then go to step 3
+          if (node == found)
+          {
+            // Update the direction towards a replacement node at the found node
+            node->dir = node->children[kLeft] ? kLeft : kRight;
+
+            // Exit loop and proceed with step 3
+            break;
+          }
+          else
+          {
+            // If this nodes weight is kNeither or we are taking the shorter path
+            // to the next node and our sibling (on longer path) is balanced then
+            // we need to update the balance node to this node but all our
+            // ancestors will not require rebalancing
+            if ((node->weight == kNeither) ||
+              (node->weight == (1 - node->dir) &&
+                node->children[1 - node->dir]->weight == kNeither))
+            {
+              // Update balance node to this node
+              balance = node;
+            }
+
+            // Keep searching for found in the direction provided in step 1
+            node = node->children[node->dir];
+          }
+        }
+        // The value for node should not be std::nullptr at this point otherwise
+        // step 1 failed to provide the correct path to found. Step 5 will fail
+        // (probably subtly) if node should be std::nullptr at this point
+
+        // Step 3: Find the node (node should be equal to found at this point)
+        // to replace found with (might end up equal to found) while also
+        // continuing to update balance the same as in step 2 above.
+        while (node)
+        {
+          // Replacement node found if its missing a child in the replace->dir
+          // value set at the end of step 2 above
+          if (node->children[node->dir] == std::nullptr)
+          {
+            // Exit loop once node to replace found is determined
+            break;
+          }
+
+          // If this nodes weight is kNeither or we are taking the shorter path
+          // to the next node and our sibling (on longer path) is balanced then
+          // we need to update the balance node to this node but all our
+          // ancestors will not require rebalancing
+          if ((node->weight == kNeither) ||
+            (node->weight == (1 - node->dir) &&
+              node->children[1 - node->dir]->weight == kNeither))
+          {
+            // Update balance node to this node
+            balance = node;
+          }
+
+          // Keep searching for replacement node in the direction specified above
+          node = node->children[node->dir];
+
+          // Downcast node to Data_Node class for comparison operations
+          Data_Node& replace_data_node = imultiset::data_cast(*node);
+
+          // Compare the key provided to the replace data node key
+          if (node_comp(data_node, replace_data_node))
+          {
+            // Update the direction to the replace node
+            node->dir = kLeft;
+          }
+          else if (node_comp(replace_data_node, data_node))
+          {
+            // Update the direction to the replace node
+            node->dir = kRight;
+          }
+          else
+          {
+            // Update the direction to the replace node
+            node->dir = node->children[kLeft] ? kLeft : kRight;
+          }
+        } // while(node)
+
+          // Step 4: Update weights from balance to parent of node determined
+          // in step 3 above rotating (2 or 3 node rotations) as needed.
+        while (balance)
+        {
+          // Break when balance node reaches the parent of replacement node
+          if (balance->children[balance->dir] == std::nullptr)
+          {
+            break;
+          }
+
+          // If balance node is balanced already (kNeither) then just imbalance
+          // the node in the opposite direction of the node being removed
+          if (balance->weight == kNeither)
+          {
+            balance->weight = 1 - balance->dir;
+          }
+          // If balance node is imbalanced in the opposite direction of the
+          // node being removed then the node now becomes balanced
+          else if (balance->weight == balance->dir)
+          {
+            balance->weight = kNeither;
+          }
+          // Otherwise a rotation is required at this node
+          else
+          {
+            int weight = balance->children[1 - balance->dir]->weight;
+            // Perform a 3 node rotation if weight is same as balance->dir
+            if (weight == balance->dir)
+            {
+              // Is the root node being rebalanced (no parent)
+              if (balance->parent == std::nullptr)
+              {
+                rotate_3node(root_node, 1 - balance->dir,
+                  balance->children[1 - balance->dir]->children[balance->dir]->weight);
+              }
+              else
+              {
+                rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir,
+                  balance->children[1 - balance->dir]->children[balance->dir]->weight);
+              }
+            }
+            // Already balanced, rebalance and make it heavy in opposite
+            // direction of the node being removed
+            else if (weight == kNeither)
+            {
+              // Is the root node being rebalanced (no parent)
+              if (balance->parent == std::nullptr)
+              {
+                rotate_2node(root_node, 1 - balance->dir);
+                root_node->weight = balance->dir;
+              }
+              else
+              {
+                // Balance parent might change during rotate, keep local copy
+                // to old parent so its weight can be updated after the 2 node
+                // rotate is completed
+                Node* old_parent = balance->parent;
+                rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
+                old_parent->children[old_parent->dir]->weight = balance->dir;
+              }
+              // Update balance node weight in opposite direction of node removed
+              balance->weight = 1 - balance->dir;
+            }
+            // Rebalance and leave it balanced
+            else
+            {
+              // Is the root node being rebalanced (no parent)
+              if (balance->parent == std::nullptr)
+              {
+                rotate_2node(root_node, 1 - balance->dir);
+              }
+              else
+              {
+                rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
+              }
+            }
+          }
+
+          // Next balance node to consider
+          balance = balance->children[balance->dir];
+        } // while(balance)
+
+          // Step 5: Swap found with node (replacement)
+        if (found->parent)
+        {
+          // Handle traditional case
+          detach_node(found->parent->children[found->parent->dir],
+            node->parent->children[node->parent->dir]);
+        }
+        // Handle root node removal
+        else
+        {
+          // Valid replacement node for root node being removed?
+          if (node->parent)
+          {
+            detach_node(root_node, node->parent->children[node->parent->dir]);
+          }
+          else
+          {
+            // Found node and replacement node are both root node
+            detach_node(root_node, root_node);
+          }
+        }
+
+        // One less.
+        --current_size;
+
+        // Destroy the node detached above
+        destroy_data_node(data_node);
+      } // if(found)
+    }
+
+    // Disable copy construction.
+    imultiset(const imultiset&);
+  };
+
+  //*************************************************************************
+  /// A templated multiset implementation that uses a fixed size buffer.
+  //*************************************************************************
+  template <typename T, const size_t MAX_SIZE_, typename TCompare = std::less<T> >
+  class multiset : public etl::imultiset<T, TCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    multiset()
+      : etl::imultiset<T, TCompare>(node_pool, MAX_SIZE)
+    {
+      etl::imultiset<T, TCompare>::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    multiset(const multiset& other)
+      : etl::imultiset<T, TCompare>(node_pool, MAX_SIZE)
+    {
+      etl::imultiset<T, TCompare>::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    multiset(TIterator first, TIterator last)
+      : etl::imultiset<T, TCompare>(node_pool, MAX_SIZE)
+    {
+      etl::imultiset<T, TCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~multiset()
+    {
+      etl::imultiset<T, TCompare>::initialise();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    multiset& operator = (const multiset& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        etl::imultiset<T, TCompare>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    /// The pool of data nodes used for the multiset.
+    etl::pool<typename etl::imultiset<T, TCompare>::Data_Node, MAX_SIZE> node_pool;
+  };
+}
+
+//***************************************************************************
+/// Equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename T, typename TCompare>
+bool operator ==(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs)
+{
+  return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//***************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename T, typename TCompare>
+bool operator !=(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs)
+{
+  return !(lhs == rhs);
+}
+
+//*************************************************************************
+/// Less than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator <(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs)
+{
+  return std::lexicographical_compare(lhs.begin(),
+    lhs.end(),
+    rhs.begin(),
+    rhs.end());
+}
+
+//*************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator >(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs)
+{
+  return (rhs < lhs);
+}
+
+//*************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than or equal
+/// to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator <=(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs)
+{
+  return !(lhs > rhs);
+}
+
+//*************************************************************************
+/// Greater than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than or
+/// equal to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator >=(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs)
+{
+  return !(lhs < rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/murmur3.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,236 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_MURMUR3__
+#define __ETL_MURMUR3__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "ihash.h"
+#include "binary.h"
+#include "error_handler.h"
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup murmur3 Murmur3 hash calculations
+///\ingroup maths
+
+namespace etl
+{
+  //***************************************************************************
+  /// Calculates the murmur3 hash.
+  /// See https://en.wikipedia.org/wiki/MurmurHash for more details.
+  ///\ingroup murmur3
+  //***************************************************************************
+  template <typename THash>
+  class murmur3
+  {
+  public:
+
+    STATIC_ASSERT((etl::is_same<THash, uint32_t>::value || etl::is_same<THash, uint64_t>::value), "Only 32 & 64 bit types supported");
+
+    typedef THash value_type;
+
+    //*************************************************************************
+    /// Default constructor.
+    /// \param seed The seed value. Default = 0.
+    //*************************************************************************
+    murmur3(value_type seed_ = 0)
+      : seed(seed_)
+    {
+      reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    /// \param seed  The seed value. Default = 0.
+    //*************************************************************************
+    template<typename TIterator>
+    murmur3(TIterator begin, const TIterator end, value_type seed_ = 0)
+      : seed(seed_)
+    {
+      STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Incompatible type");
+
+      reset();
+      while (begin != end)
+      {
+        block |= (*begin++) << (block_fill_count * 8);
+
+        if (++block_fill_count == FULL_BLOCK)
+        {
+          add_block();
+          block_fill_count = 0;
+          block = 0;
+        }
+
+        ++char_count;
+      }
+    }
+
+    //*************************************************************************
+    /// Resets the hash to the initial state.
+    //*************************************************************************
+    void reset()
+    {
+      hash             = seed;
+      char_count       = 0;
+      block            = 0;
+      block_fill_count = 0;
+      is_finalised     = false;
+    }
+
+    //*************************************************************************
+    /// Adds a range.
+    /// \param begin
+    /// \param end
+    //*************************************************************************
+    template<typename TIterator>
+    void add(TIterator begin, const TIterator end)
+    {
+      STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Incompatible type");
+      ETL_ASSERT(!is_finalised, ETL_ERROR(hash_finalised));
+
+      while (begin != end)
+      {
+        block |= (*begin++) << (block_fill_count * 8);
+
+        if (++block_fill_count == FULL_BLOCK)
+        {
+          add_block();
+          block_fill_count = 0;
+          block = 0;
+        }
+
+        ++char_count;
+      }
+    }
+
+    //*************************************************************************
+    /// Adds a uint8_t value.
+    /// If the hash has already been finalised then a 'hash_finalised' error will be emitted.
+    /// \param value The char to add to the hash.
+    //*************************************************************************
+    void add(uint8_t value_)
+    {
+      // We can't add to a finalised hash!
+      ETL_ASSERT(!is_finalised, ETL_ERROR(hash_finalised));
+
+      block |= value_ << (block_fill_count * 8);
+
+      if (++block_fill_count == FULL_BLOCK)
+      {
+        add_block();
+        block_fill_count = 0;
+        block = 0;
+      }
+
+      ++char_count;
+    }
+
+    //*************************************************************************
+    /// Gets the hash value.
+    //*************************************************************************
+    value_type value()
+    {
+      finalise();
+      return hash;
+    }
+
+    //*************************************************************************
+    /// Conversion operator to value_type.
+    //*************************************************************************
+    operator value_type ()
+    {
+      return value();
+    }
+
+  private:
+
+    //*************************************************************************
+    /// Adds a filled block to the hash.
+    //*************************************************************************
+    void add_block()
+    {
+      block *= CONSTANT1;
+      block = rotate_left(block, SHIFT1);
+      block *= CONSTANT2;
+
+      hash ^= block;
+      hash = rotate_left(hash, SHIFT2);
+      hash = (hash * MULTIPLY) + ADD;
+    }
+
+    //*************************************************************************
+    /// Finalises the hash.
+    //*************************************************************************
+    void finalise()
+    {
+      if (!is_finalised)
+      {
+        block *= CONSTANT1;
+        block = rotate_left(block, SHIFT1);
+        block *= CONSTANT2;
+
+        hash ^= block;
+        hash ^= char_count;
+        hash ^= (hash >> 16);
+        hash *= 0x85EBCA6B;
+        hash ^= (hash >> 13);
+        hash *= 0xC2B2AE35;
+        hash ^= (hash >> 16);
+
+        is_finalised = true;
+      }
+    }
+
+    bool       is_finalised;
+    uint8_t    block_fill_count;
+    size_t     char_count;
+    value_type block;
+    value_type hash;
+    value_type seed;
+
+    static const uint8_t    FULL_BLOCK = 4;
+    static const value_type CONSTANT1  = 0xCC9E2D51;
+    static const value_type CONSTANT2  = 0x1B873593;
+    static const value_type SHIFT1     = 15;
+    static const value_type SHIFT2     = 13;
+    static const value_type MULTIPLY   = 5;
+    static const value_type ADD        = 0xE6546B64;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nullptr.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,97 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_NULLPTR__
+#define __ETL_NULLPTR__
+
+#include "platform.h"
+
+///\defgroup nullptr nullptr
+/// A definition of nullptr for compilers that don't support it as standard.
+///\ingroup utilities
+
+#if (ETL_NO_NULLPTR_SUPPORT && !defined(ARDUINO))
+namespace std
+{
+  //*****************************************************************************
+  /// A null pointer type.
+  ///\ingroup nullptr
+  //*****************************************************************************
+  class nullptr_t
+  {
+  public:
+
+    // Convertible to any type of null non-member pointer.
+    template<typename T>
+    operator T*() const
+    {
+      return 0;
+    }
+
+    // Or any type of null member pointer.
+    template<typename ANYCLASS, typename T>
+    operator T ANYCLASS::*() const
+    {
+      return 0;
+    }
+
+  private:
+
+    // Can't take address of nullptr.
+    void operator&() const;
+  };
+
+  //*****************************************************************************
+  /// A null pointer.
+  ///\ingroup nullptr
+  //*****************************************************************************
+  const nullptr_t nullptr = {};
+}
+
+//*****************************************************************************
+/// A null pointer.
+///\ingroup nullptr
+//*****************************************************************************
+const std::nullptr_t nullptr = {};
+
+#else 
+    #include <cstddef>
+#endif
+
+#if defined(ARDUINO)
+namespace std
+{
+  typedef ::nullptr_t nullptr_t;
+}
+#endif
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/numeric.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,61 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_NUMERIC__
+#define __ETL_NUMERIC__
+
+#include "platform.h"
+
+///\defgroup numeric numeric
+///\ingroup utilities
+
+namespace etl
+{ 
+  //***************************************************************************
+  /// iota
+  /// Reverse engineered version of std::iota for non C++ 0x11 compilers.
+  /// Fills a range of elements with sequentially increasing values starting with <b>value</b>.
+  ///\param first An iterator to the first position to fill.
+  ///\param last  An iterator to the last + 1 position.
+  ///\ingroup numeric
+  //***************************************************************************
+  template <typename TIterator, typename T>
+  void iota(TIterator first, TIterator last, T value)
+  {
+    while (first != last)
+    {
+      *first++ = value++;
+    }
+  }
+}
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/observer.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,351 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_OBSERVER__
+#define __ETL_OBSERVER__
+
+//*****************************************************************************
+///\defgroup observer observer
+/// A templated implementation to simplify the creation of the observer pattern
+/// and attempts to eliminate certain runtime errors by turning them into compile errors.
+/// The pattern consists of two template classes.
+/// \li <b>Observer</b><br>
+/// This template may take up to eight notification types.
+/// Each notification type will generate a pure virtual 'notification'
+/// function. The class that inherits from this *must* define all
+/// of the 'notification' function overloads otherwise the object will
+/// remain 'abstract' and will not compile.
+/// This ensures that no overload can be forgotten.<br>
+///
+/// \li <b>observable</b><br>
+/// The class derived from this will be observed by the above class.
+/// It keeps a list of registered observers and will notify all
+/// of them with the notifications.
+///\ingroup patterns
+//*****************************************************************************
+
+#include <algorithm>
+
+#include "platform.h"
+#include "vector.h"
+#include "exception.h"
+#include "error_handler.h"
+
+#undef ETL_FILE
+#define ETL_FILE "18"
+
+namespace etl
+{
+  //***************************************************************************
+  ///\ingroup observer
+  /// The base class for observer exceptions.
+  //***************************************************************************
+  class observer_exception : public exception
+  {
+  public:
+
+    observer_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup observer
+  /// The exception thrown when the observer list is full.
+  //***************************************************************************
+  class observer_list_full : public observer_exception
+  {
+  public:
+
+    observer_list_full(string_type file_name_, numeric_type line_number_)
+      : observer_exception(ETL_ERROR_TEXT("observer:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //*********************************************************************
+  /// The object that is being observed.
+  ///\tparam TObserver     The observer type.
+  ///\tparam MAX_OBSERVERS The maximum number of observers that can be accomodated.
+  ///\ingroup observer
+  //*********************************************************************
+  template <typename TObserver, const size_t MAX_OBSERVERS>
+  class observable
+  {
+  public:
+
+    typedef size_t size_type;
+
+    typedef etl::vector<TObserver*, MAX_OBSERVERS> Observer_List;
+
+    //*****************************************************************
+    /// Add an observer to the list.
+    /// If asserts or exceptions are enabled then an etl::observable_observer_list_full
+    /// is emitted if the observer list is already full.
+    ///\param observer A reference to the observer.
+    //*****************************************************************
+    void add_observer(TObserver& observer)
+    {
+		  // See if we already have it in our list.
+      typename Observer_List::const_iterator i_observer = std::find(observer_list.begin(),
+                                                                    observer_list.end(),
+                                                                    &observer);
+
+		  // Not there?
+      if (i_observer == observer_list.end())
+      {
+        // Is there enough room?
+        ETL_ASSERT(!observer_list.full(), ETL_ERROR(etl::observer_list_full));
+
+        // Add it.
+        observer_list.push_back(&observer);
+      }
+    }
+
+    //*****************************************************************
+    /// Remove a particular observer from the list.
+    ///\param observer A reference to the observer.
+    //*****************************************************************
+    void remove_observer(TObserver& observer)
+    {
+      // See if we have it in our list.
+      typename Observer_List::iterator i_observer = std::find(observer_list.begin(),
+                                                              observer_list.end(),
+                                                              &observer);
+
+      // Found it?
+      if (i_observer != observer_list.end())
+      {
+        // Erase it.
+        observer_list.erase(i_observer);
+      }
+    }
+
+    //*****************************************************************
+    /// Clear all observers from the list.
+    //*****************************************************************
+    void clear_observers()
+    {
+      observer_list.clear();
+    }
+
+    //*****************************************************************
+    /// Returns the number of observers.
+    //*****************************************************************
+    size_type number_of_observers() const
+    {
+      return observer_list.size();
+    }
+
+    //*****************************************************************
+    /// Notify all of the observers, sending them the notification.
+    ///\tparam TNotification the notification type.
+    ///\param n The notification.
+    //*****************************************************************
+    template <typename TNotification>
+    void notify_observers(TNotification n)
+    {
+      for (size_t i = 0; i < observer_list.size(); ++i)
+      {
+        observer_list[i]->notification(n);
+      }
+    }
+
+  private:
+
+    /// The list of observers.
+    Observer_List observer_list;
+  };
+
+  //*********************************************************************
+  /// The observer interface for eight notification types.
+  ///\ingroup observer
+  //*********************************************************************
+  template <typename T1,
+            typename T2  = void,
+            typename T3  = void,
+            typename T4  = void,
+            typename T5  = void,
+            typename T6  = void,
+            typename T7  = void,
+            typename T8  = void>
+  class observer
+  {
+  public:
+    virtual ~observer() {}
+    virtual void notification(T1) = 0;
+    virtual void notification(T2) = 0;
+    virtual void notification(T3) = 0;
+    virtual void notification(T4) = 0;
+    virtual void notification(T5) = 0;
+    virtual void notification(T6) = 0;
+    virtual void notification(T7) = 0;
+    virtual void notification(T8) = 0;
+  };
+
+  //*********************************************************************
+  /// The observer interface for seven notification types.
+  ///\ingroup observer
+  //*********************************************************************
+  template <typename T1,
+            typename T2,
+            typename T3,
+            typename T4,
+            typename T5,
+            typename T6,
+            typename T7>
+  class observer<T1, T2, T3, T4, T5, T6, T7>
+  {
+  public:
+
+    virtual ~observer() {}
+    virtual void notification(T1) = 0;
+    virtual void notification(T2) = 0;
+    virtual void notification(T3) = 0;
+    virtual void notification(T4) = 0;
+    virtual void notification(T5) = 0;
+    virtual void notification(T6) = 0;
+    virtual void notification(T7) = 0;
+  };
+
+  //*********************************************************************
+  /// The observer interface for six notification types.
+  ///\ingroup observer
+  //*********************************************************************
+  template <typename T1,
+            typename T2,
+            typename T3,
+            typename T4,
+            typename T5,
+            typename T6>
+  class observer<T1, T2, T3, T4, T5, T6>
+  {
+  public:
+
+    virtual ~observer() {}
+    virtual void notification(T1) = 0;
+    virtual void notification(T2) = 0;
+    virtual void notification(T3) = 0;
+    virtual void notification(T4) = 0;
+    virtual void notification(T5) = 0;
+    virtual void notification(T6) = 0;
+  };
+
+  //*********************************************************************
+  /// The observer interface for five notification types.
+  ///\ingroup observer
+  //*********************************************************************
+  template <typename T1,
+            typename T2,
+            typename T3,
+            typename T4,
+            typename T5>
+  class observer<T1, T2, T3, T4, T5>
+  {
+  public:
+
+    virtual ~observer() {}
+    virtual void notification(T1) = 0;
+    virtual void notification(T2) = 0;
+    virtual void notification(T3) = 0;
+    virtual void notification(T4) = 0;
+    virtual void notification(T5) = 0;
+  };
+
+  //*********************************************************************
+  /// The observer interface for four notification types.
+  ///\ingroup observer
+  //*********************************************************************
+  template <typename T1,
+            typename T2,
+            typename T3,
+            typename T4>
+  class observer<T1, T2, T3, T4>
+  {
+  public:
+
+    virtual ~observer() {}
+    virtual void notification(T1) = 0;
+    virtual void notification(T2) = 0;
+    virtual void notification(T3) = 0;
+    virtual void notification(T4) = 0;
+  };
+
+  //*********************************************************************
+  /// The observer interface for three notification types.
+  ///\ingroup observer
+  //*********************************************************************
+  template <typename T1,
+            typename T2,
+            typename T3>
+  class observer<T1, T2, T3>
+  {
+  public:
+
+    virtual ~observer() {}
+    virtual void notification(T1) = 0;
+    virtual void notification(T2) = 0;
+    virtual void notification(T3) = 0;
+  };
+
+  //*********************************************************************
+  /// The observer interface for two notification types.
+  ///\ingroup observer
+  //*********************************************************************
+  template <typename T1,
+            typename T2>
+  class observer<T1, T2>
+  {
+  public:
+
+    virtual ~observer() {}
+    virtual void notification(T1) = 0;
+    virtual void notification(T2) = 0;
+  };
+
+  //*********************************************************************
+  /// The observer interface for one notification type.
+  ///\ingroup observer
+  //*********************************************************************
+  template <typename T1>
+  class observer<T1>
+  {
+  public:
+
+    virtual ~observer() {}
+    virtual void notification(T1) = 0;
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/optional.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,444 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+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 __ETL_OPTIONAL__
+#define __ETL_OPTIONAL__
+
+#include "platform.h"
+#include "alignment.h"
+#include "type_traits.h"
+#include "exception.h"
+#include "error_handler.h"
+
+namespace etl
+{
+  //*****************************************************************************
+  /// A null option type.
+  ///\ingroup utilities
+  //*****************************************************************************
+  class nullopt_t
+  {
+  public:
+
+    // Convertible to any type of null non-member pointer.
+    template<class T>
+    operator T*() const
+    {
+      return 0;
+    }
+
+  private:
+
+    // Can't take address of nullopt.
+    void operator&() const;
+  };
+
+  //*****************************************************************************
+  /// A null option.
+  ///\ingroup utilities
+  //*****************************************************************************
+  const nullopt_t nullopt = {};
+
+  //***************************************************************************
+  /// Exception for optional.
+  ///\ingroup list
+  //***************************************************************************
+  class optional_exception : public exception
+  {
+  public:
+
+    optional_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Invalid exception for optional.
+  ///\ingroup list
+  //***************************************************************************
+  class optional_invalid : public optional_exception
+  {
+  public:
+
+    optional_invalid(string_type file_name_, numeric_type line_number_)
+      : optional_exception("optional: invalid", file_name_, line_number_)
+    {
+    }
+  };
+
+  //*****************************************************************************
+  /// An optional type.
+  /// If the optional type is not initialised then a type is not constructed.
+  ///\tparam The type to store.
+  ///\ingroup utilities
+  //*****************************************************************************
+  template <typename T>
+  class optional
+  {
+  public:
+
+    //***************************************************************************
+    /// Constructor.
+    //***************************************************************************
+    optional()
+      : valid(false)
+    {
+    }
+
+    //***************************************************************************
+    /// Constructor with nullopt.
+    //***************************************************************************
+    optional(etl::nullopt_t)
+      : valid(false)
+    {
+    }
+
+    //***************************************************************************
+    /// Copy constructor.
+    //***************************************************************************
+    optional(const optional& other)
+      : valid(bool(other))
+    {
+      if (valid)
+      {
+       ::new (storage.template get_address<T>()) T(other.value());
+      }
+    }
+
+    //***************************************************************************
+    /// Constructor from value type.
+    //***************************************************************************
+    optional(const T& value_)
+    {
+     ::new (storage.template get_address<T>()) T(value_);
+      valid = true;
+    }
+
+    //***************************************************************************
+    /// Destructor.
+    //***************************************************************************
+    ~optional()
+    {
+      if (valid)
+      {
+        storage.template get_reference<T>().~T();
+      }
+    }
+
+    //***************************************************************************
+    /// Assignment operator from nullopt.
+    //***************************************************************************
+    optional& operator =(etl::nullopt_t)
+    {
+      if (valid)
+      {
+        storage.template get_reference<T>().~T();
+        valid = false;
+      }
+
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Assignment operator from optional.
+    //***************************************************************************
+    optional& operator =(const optional& other)
+    {
+      if (this != &other)
+      {
+        if (valid && !bool(other))
+        {
+          storage.template get_reference<T>().~T();
+          valid = false;
+        }
+        else if (bool(other))
+        {
+          if (valid)
+          {
+            storage.template get_reference<T>() = other.value();
+          }
+          else
+          {
+           ::new (storage.template get_address<T>()) T(other.value());
+            valid = true;
+          }
+        }
+      }
+
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Assignment operator from value type.
+    //***************************************************************************
+    optional& operator =(const T& value_)
+    {
+      if (valid)
+      {
+        storage.template get_reference<T>() = value_;
+      }
+      else
+      {
+       ::new (storage.template get_address<T>()) T(value_);
+        valid = true;
+      }
+
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Pointer operator.
+    //***************************************************************************
+    T* operator ->()
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+      return storage.template get_address<T>();
+    }
+
+    //***************************************************************************
+    /// Pointer operator.
+    //***************************************************************************
+    const T* operator ->() const
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+      return storage.template get_address<T>();
+    }
+
+    //***************************************************************************
+    /// Dereference operator.
+    //***************************************************************************
+    T& operator *()
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+      return storage.template get_reference<T>();
+    }
+
+    //***************************************************************************
+    /// Dereference operator.
+    //***************************************************************************
+    const T& operator *() const
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+      return storage.template get_reference<T>();
+    }
+
+    //***************************************************************************
+    /// Bool conversion operator.
+    //***************************************************************************
+    explicit operator bool() const
+    {
+      return valid;
+    }
+
+    //***************************************************************************
+    /// Get a reference to the value.
+    //***************************************************************************
+    T& value()
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+      return storage.template get_reference<T>();
+    }
+
+    //***************************************************************************
+    /// Get a const reference to the value.
+    //***************************************************************************
+    const T& value() const
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+      return storage.template get_reference<T>();
+    }
+
+    //***************************************************************************
+    /// Gets the value or a default if no valid.
+    //***************************************************************************
+    T value_or(T default_value) const
+    {
+      return valid ? value() : default_value;
+    }
+
+    //***************************************************************************
+    /// Swaps this value with another.
+    //***************************************************************************
+    void swap(optional& other)
+    {
+      optional temp(*this);
+      *this = other;
+      other = temp;
+    }
+
+  private:
+
+    typename etl::aligned_storage_as<sizeof(T), T>::type storage;
+    bool valid;
+  };
+}
+
+//*************************************************************************
+/// Swaps the values.
+//*************************************************************************
+template <typename T>
+void swap(etl::optional<T>& lhs, etl::optional<T>& rhs)
+{
+  lhs.swap(rhs);
+}
+
+//***************************************************************************
+/// Equality operator.
+//***************************************************************************
+template <typename T>
+bool operator ==(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
+{
+  if (bool(lhs) != bool(rhs))
+  {
+    return false;
+  }
+  else if (!bool(lhs) && !bool(rhs))
+  {
+    return true;
+  }
+  else
+  {
+    return lhs.value() == rhs.value();
+  }
+}
+
+//***************************************************************************
+/// Less than operator.
+//***************************************************************************
+template <typename T>
+bool operator <(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
+{
+  if (!bool(rhs))
+  {
+    return false;
+  }
+  else if (!bool(lhs))
+  {
+    return true;
+  }
+  else
+  {
+    return lhs.value() < rhs.value();
+  }
+}
+
+//***************************************************************************
+/// Equality operator.
+//***************************************************************************
+template <typename T>
+bool operator ==(const etl::optional<T>& lhs, etl::nullopt_t)
+{
+  return !bool(lhs);
+}
+
+//***************************************************************************
+/// Equality operator.
+//***************************************************************************
+template <typename T>
+bool operator ==(etl::nullopt_t, const etl::optional<T>& rhs)
+{
+  return false;
+}
+
+//***************************************************************************
+/// Less than operator.
+//***************************************************************************
+template <typename T>
+bool operator <(const etl::optional<T>& lhs, etl::nullopt_t)
+{
+  return !bool(lhs);
+}
+
+//***************************************************************************
+/// Less than operator.
+//***************************************************************************
+template <typename T>
+bool operator <(etl::nullopt_t, const etl::optional<T>& rhs)
+{
+  return bool(rhs);
+}
+
+//***************************************************************************
+/// Equality operator.
+//**************************************************************************
+template <typename T>
+bool operator ==(const etl::optional<T>& lhs, const T& rhs)
+{
+  return bool(lhs) ? lhs.value() == rhs : false;
+}
+
+//***************************************************************************
+/// Equality operator.
+//**************************************************************************
+template <typename T>
+bool operator ==(const T& value, const etl::optional<T>& rhs)
+{
+  return bool(rhs) ? rhs.value() == value : false;
+}
+
+//***************************************************************************
+/// Less than operator.
+//***************************************************************************
+template <typename T>
+bool operator <(const etl::optional<T>& lhs, const T& rhs)
+{
+  return bool(lhs) ? lhs.value() < rhs : true;
+}
+
+//***************************************************************************
+/// Make an optional.
+//***************************************************************************
+template <typename T>
+etl::optional<typename etl::decay<T>::type> make_optional(T& value)
+{
+  return etl::optional<typename etl::decay<T>::type>(value);
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/packet.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,129 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_PACKET__
+#define __ETL_PACKET__
+
+#include "platform.h"
+#include "static_assert.h"
+#include "alignment.h"
+
+#undef ETL_FILE
+#define ETL_FILE "38"
+
+//*****************************************************************************
+///\defgroup packet packet
+/// A class that can contain one a several related types.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// A template class that can store any types derived from TBase that conform
+  /// to the size and alignment requirements.
+  ///\ingroup packet
+  //***************************************************************************
+  template <typename TBase, size_t SIZE, size_t ALIGNMENT>            
+  class packet
+  {
+  public:
+
+    //***************************************************************************
+    /// Constructor that static asserts any types that do not conform to the max size and alignment.
+    //***************************************************************************
+    template <typename T>
+    explicit packet(const T& value)
+    {
+      STATIC_ASSERT((etl::is_base_of<TBase, T>::value), "Unsupported type");
+      STATIC_ASSERT(sizeof(T) <= SIZE, "Unsupported size");
+      STATIC_ASSERT(etl::alignment_of<T>::value <= ALIGNMENT, "Unsupported alignment");
+
+      ::new (static_cast<T*>(data)) T(value);
+    }
+
+    //***************************************************************************
+    /// Destructor
+    //***************************************************************************
+    ~packet()
+    {
+      static_cast<TBase*>(data)->~TBase();
+    }
+
+    //***************************************************************************
+    /// Assignment operator for type.
+    ///\param value The value to assign.
+    //***************************************************************************
+    template <typename T>
+    packet& operator =(const T& value)
+    {
+      STATIC_ASSERT((etl::is_base_of<TBase, T>::value), "Unsupported type");
+      STATIC_ASSERT(sizeof(T) <= SIZE, "Unsupported size");
+      STATIC_ASSERT(etl::alignment_of<T>::value <= ALIGNMENT, "Unsupported alignment");
+
+      static_cast<TBase*>(data)->~TBase();
+      ::new (static_cast<T*>(data)) T(value);
+
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Get access to the contained object.
+    //***************************************************************************
+    TBase& get()
+    {
+      return *static_cast<TBase*>(data);
+    }
+
+    //***************************************************************************
+    /// Get access to the contained object.
+    //***************************************************************************
+    const TBase& get() const
+    {
+      return *static_cast<const TBase*>(data);
+    }
+
+  private:
+    
+    packet(const packet& other);
+    packet& operator =(const packet& other);
+
+    //***************************************************************************
+    /// The internal storage.
+    /// Aligned on a suitable boundary, which should be good for all types.
+    //***************************************************************************
+    typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parameter_type.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,53 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_PARAMETER__
+#define __ETL_PARAMETER__
+
+#include "platform.h"
+#include "type_traits.h"
+
+namespace etl
+{
+  //*************************************************************************
+  /// Determine how to pass parameters.
+  //*************************************************************************
+  template <typename T>
+  struct parameter_type
+  {
+    /// By default fundamental and pointer types are passed by value.
+    typedef typename etl::conditional<is_fundamental<T>::value || is_pointer<T>::value,
+                                      T,
+                                      const T&>::type type;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pearson.cpp	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,64 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+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.
+******************************************************************************/
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "static_assert.h"
+
+STATIC_ASSERT(ETL_8BIT_SUPPORT, "This file does not currently support targets with no 8bit type");
+
+namespace etl
+{
+  //***************************************************************************
+  /// Pearson lookup table
+  /// \ingroup pearson
+  //***************************************************************************
+  extern const uint8_t PEARSON_LOOKUP[] =
+  {
+    228,  39,  61,  95, 227, 187,   0, 197,  31, 189, 161, 222,  34,  15, 221, 246,
+     19, 234,   6,  50, 113,   3,  91,  63,  77, 245, 144,   2, 183, 196,  25, 226,
+     97, 126,  48,  59, 217,   4, 100, 145,  12,  88, 203, 149,  80, 154,  38,  27,
+    224, 218, 158, 115, 202,  79,  53,  83, 242,  36, 139, 131, 136, 191,  42, 170,
+     23,  99, 156,  51, 143,  60, 233, 206,  62, 108,  17,  67,  81,  71,  93, 195,
+     26, 231, 247,  96,  24, 200, 176, 209, 152, 212, 138, 165,  75, 185, 130, 248,
+    125, 110,  10, 116, 201,  90,  69, 204,  85, 251,  78, 157,  47, 184, 169, 141,
+    134, 230,  89,  21, 146,  46,  55, 128, 148, 207, 216,  11, 114, 199, 103, 102,
+    166, 244,   5, 104, 225, 160, 132,  28, 172,  65, 121, 140, 153, 119, 198, 210,
+     58,  87, 117, 177,  33,  22,  13,  37,  49, 174, 109,  40,  73, 211,  18, 167,
+    164, 252, 168,  74,  30, 173,  35,  98,  66, 193,  94, 175,  86,  54, 179, 122,
+    220, 151, 192,  29, 133, 254, 155, 127, 240, 232, 190, 180,   8,  68, 236,  20,
+    137,  92, 219, 208,  52, 250, 147, 142, 111, 112, 120,  45, 135, 255, 123, 229,
+     57, 182, 243, 124, 186, 253,   7, 237,   9,  16,  70, 171, 235, 107, 223, 118,
+    215, 178, 194, 181,  43, 188, 106, 105,  64, 241,  84, 238, 159,  44,  32,  76,
+    213, 163, 150, 101, 129,  14, 249, 205, 214,   1,  41,  56, 162,  72, 239,  82
+  } ;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pearson.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,167 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_PEARSON__
+#define __ETL_PEARSON__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "static_assert.h"
+#include "type_traits.h"
+#include "ihash.h"
+#include "array.h"
+#include "container.h"
+
+STATIC_ASSERT(ETL_8BIT_SUPPORT, "This file does not currently support targets with no 8bit type");
+
+#if defined(ETL_COMPILER_KEIL)
+#pragma diag_suppress 1300
+#endif
+
+///\defgroup pearson Pearson hash calculation
+///\ingroup pearson
+
+namespace etl
+{
+  //***************************************************************************
+  /// Pearson lookup table
+  /// \ingroup pearson
+  //***************************************************************************
+  extern const uint8_t PEARSON_LOOKUP[];
+
+  //***************************************************************************
+  /// Calculates a Pearson hash
+  ///\tparam HASH_LENGTH The number of elements in the hash.
+  /// \ingroup pearson
+  //***************************************************************************
+  template <const size_t HASH_LENGTH>
+  class pearson
+  {
+  public:
+
+    typedef etl::array<uint8_t, HASH_LENGTH> value_type;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    pearson()
+      : first(true)
+    {
+      reset();
+    }
+
+    //*************************************************************************
+    /// Constructor from range.
+    /// \param begin Start of the range.
+    /// \param end   End of the range.
+    //*************************************************************************
+    template<typename TIterator>
+    pearson(TIterator begin, const TIterator end)
+      : first(true)
+    {
+      STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+      reset();
+      add(begin, end);
+    }
+
+    //*************************************************************************
+    /// Resets the hash to the initial state.
+    //*************************************************************************
+    void reset()
+    {
+      hash.fill(0);
+    }
+
+    //*************************************************************************
+    /// Adds a range.
+    /// \param begin
+    /// \param end
+    //*************************************************************************
+    template<typename TIterator>
+    void add(TIterator begin, const TIterator end)
+    {
+      STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported");
+
+      while (begin != end)
+      {
+        add(*begin++);
+      }
+    }
+
+    //*************************************************************************
+    /// \param value The char to add to the hash.
+    //*************************************************************************
+    void add(uint8_t value_)
+    {
+      if (first)
+      {
+        for (size_t i = 0; i < HASH_LENGTH; ++i)
+        {
+          hash[i] = PEARSON_LOOKUP[(uint32_t(value_) + i) % 256];
+        }
+
+        first = false;
+      }
+      else
+      {
+        for (size_t i = 0; i < HASH_LENGTH; ++i)
+        {
+          hash[i] = PEARSON_LOOKUP[hash[i] ^ value_];
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Gets the hash value.
+    //*************************************************************************
+    value_type value() const
+    {
+      return hash;
+    }
+
+    //*************************************************************************
+    /// Conversion operator to value_type.
+    //*************************************************************************
+    operator value_type () const
+    {
+      return value();
+    }
+
+  private:
+
+    bool first;
+    value_type hash;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/platform.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,57 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_PLATFORM__
+#define __ETL_PLATFORM__
+
+// Some targets do not support 8bit types.
+#define ETL_8BIT_SUPPORT (CHAR_BIT == 8)
+
+#if defined(_DEBUG) || defined(DEBUG)
+  #define ETL_DEBUG
+#endif
+
+#undef ETL_CPP11_SUPPORTED
+#undef ETL_CPP14_SUPPORTED
+#undef ETL_NO_NULLPTR_SUPPORT
+#undef ETL_NO_LARGE_CHAR_SUPPORT
+#undef ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED
+#undef ETL_ATOMIC_SUPPORTED
+
+#include "etl_profile.h"
+
+#if ETL_CPP11_SUPPORTED
+  #define ETL_CONSTEXPR constexpr
+#else
+  #define ETL_CONSTEXPR
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pool.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,439 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_POOL__
+#define __ETL_POOL__
+
+#include "platform.h"
+#include "alignment.h"
+#include "array.h"
+#include "container.h"
+#include "integral_limits.h"
+#include "nullptr.h"
+#include "alignment.h"
+#include "error_handler.h"
+#include "static_assert.h"
+
+#include <iterator>
+#include <algorithm>
+
+#undef ETL_FILE
+#define ETL_FILE "11"
+
+//*****************************************************************************
+///\defgroup pool pool
+/// A fixed capacity pool.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for pool exceptions.
+  ///\ingroup pool
+  //***************************************************************************
+  class pool_exception : public exception
+  {
+  public:
+
+    pool_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  /// The exception thrown when the pool has no more free items.
+  ///\ingroup pool
+  //***************************************************************************
+  class pool_no_allocation : public pool_exception
+  {
+  public:
+
+    explicit pool_no_allocation(string_type file_name_, numeric_type line_number_)
+      : pool_exception(ETL_ERROR_TEXT("pool:allocation", ETL_FILE"A"), file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  /// The exception thrown when an object is released which does not belong to the pool.
+  ///\ingroup pool
+  //***************************************************************************
+  class pool_object_not_in_pool : public pool_exception
+  {
+  public:
+
+    pool_object_not_in_pool(string_type file_name_, numeric_type line_number_)
+      : pool_exception(ETL_ERROR_TEXT("pool:not in pool", ETL_FILE"B"), file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  /// The exception thrown when an the type requested is larger than the element size.
+  ///\ingroup pool
+  //***************************************************************************
+  class pool_element_size : public pool_exception
+  {
+  public:
+
+    pool_element_size(string_type file_name_, numeric_type line_number_)
+      : pool_exception(ETL_ERROR_TEXT("pool:element size", ETL_FILE"C"), file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  ///\ingroup pool
+  //***************************************************************************
+  class ipool
+  {
+  public:
+
+    typedef size_t size_type;
+
+    //*************************************************************************
+    /// Allocate an object from the pool.
+    /// Uses the default constructor.
+    /// If asserts or exceptions are enabled and there are no more free items an
+    /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned.
+    //*************************************************************************
+    template <typename T>
+    T* allocate()
+    {
+      if (sizeof(T) > ITEM_SIZE)
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size));
+      }
+
+      return reinterpret_cast<T*>(allocate_item());
+    }
+
+    //*************************************************************************
+    /// Release an object in the pool.
+    /// If asserts or exceptions are enabled and the object does not belong to this
+    /// pool then an etl::pool_object_not_in_pool is thrown.
+    /// \param p_object A pointer to the object to be released.
+    //*************************************************************************
+    void release(const void* p_object)
+    {
+      release_item((char*)p_object);
+    }
+
+    //*************************************************************************
+    /// Release all objects in the pool.
+    //*************************************************************************
+    void release_all()
+    {
+      items_allocated = 0;
+      items_initialised = 0;
+      p_next = p_buffer;
+    }
+
+    //*************************************************************************
+    /// Check to see if the object belongs to the pool.
+    /// \param p_object A pointer to the object to be checked.
+    /// \return <b>true<\b> if it does, otherwise <b>false</b>
+    //*************************************************************************
+    //template <typename T>
+    bool is_in_pool(const void* p_object) const
+    {
+      return is_item_in_pool((const char*)p_object);
+    }
+
+    //*************************************************************************
+    /// Returns the maximum number of items in the pool.
+    //*************************************************************************
+    size_t max_size() const
+    {
+      return MAX_SIZE;
+    }
+
+    //*************************************************************************
+    /// Returns the number of free items in the pool.
+    //*************************************************************************
+    size_t available() const
+    {
+      return MAX_SIZE - items_allocated;
+    }
+
+    //*************************************************************************
+    /// Returns the number of allocated items in the pool.
+    //*************************************************************************
+    size_t size() const
+    {
+      return items_allocated;
+    }
+
+    //*************************************************************************
+    /// Checks to see if there are no allocated items in the pool.
+    /// \return <b>true</b> if there are none allocated.
+    //*************************************************************************
+    bool empty() const
+    {
+      return items_allocated == 0;
+    }
+
+    //*************************************************************************
+    /// Checks to see if there are no free items in the pool.
+    /// \return <b>true</b> if there are none free.
+    //*************************************************************************
+    bool full() const
+    {
+      return items_allocated == MAX_SIZE;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor
+    //*************************************************************************
+    ipool(char* p_buffer_, uint32_t item_size_, uint32_t max_size_)
+      : p_buffer(p_buffer_),
+        p_next(p_buffer_),
+        items_allocated(0),
+        items_initialised(0),
+        ITEM_SIZE(item_size_),
+        MAX_SIZE(max_size_)
+    {
+    }
+
+  private:
+
+    //*************************************************************************
+    /// Allocate an item from the pool.
+    //*************************************************************************
+    char* allocate_item()
+    {
+      char* p_value = std::nullptr;
+
+      // Any free space left?
+      if (items_allocated < MAX_SIZE)
+      {
+        // Initialise another one if necessary.
+        if (items_initialised < MAX_SIZE)
+        {
+          uintptr_t p = reinterpret_cast<uintptr_t>(p_buffer + (items_initialised * ITEM_SIZE));
+          *reinterpret_cast<uintptr_t*>(p) = p + ITEM_SIZE;
+          ++items_initialised;
+        }
+
+        // Get the address of new allocated item.
+        p_value = p_next;
+
+        ++items_allocated;
+        if (items_allocated != MAX_SIZE)
+        {
+          // Set up the pointer to the next free item
+          p_next = *reinterpret_cast<char**>(p_next);
+        }
+        else
+        {
+          // No more left!
+          p_next = std::nullptr;
+        }
+      }
+      else
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::pool_no_allocation));
+      }
+
+      return p_value;
+    }
+
+    //*************************************************************************
+    /// Release an item back to the pool.
+    //*************************************************************************
+    void release_item(char* p_value)
+    {
+      // Does it belong to us?
+      ETL_ASSERT(is_item_in_pool(p_value), ETL_ERROR(pool_object_not_in_pool));
+
+      if (p_next != std::nullptr)
+      {
+        // Point it to the current free item.
+        *(uintptr_t*)p_value = reinterpret_cast<uintptr_t>(p_next);
+      }
+      else
+      {
+        // This is the only free item.
+        *((uintptr_t*)p_value) = 0;
+      }
+
+      p_next = p_value;
+
+      --items_allocated;
+    }
+
+    //*************************************************************************
+    /// Check if the item belongs to this pool.
+    //*************************************************************************
+    bool is_item_in_pool(const char* p) const
+    {
+      // Within the range of the buffer?
+      intptr_t distance = p - p_buffer;
+      bool is_within_range = (distance >= 0) && (distance <= intptr_t((ITEM_SIZE * MAX_SIZE) - ITEM_SIZE));
+
+      // Modulus and division can be slow on some architectures, so only do this in debug.
+#if defined(ETL_DEBUG)
+      // Is the address on a valid object boundary?
+      bool is_valid_address = ((distance % ITEM_SIZE) == 0);
+#else
+      bool is_valid_address = true;
+#endif
+
+      return is_within_range && is_valid_address;
+    }
+
+    // Disable copy construction and assignment.
+    ipool(const ipool&);
+    ipool& operator =(const ipool&);
+
+    char* p_buffer;
+    char* p_next;
+
+    uint32_t  items_allocated;   ///< The number of items allocated.
+    uint32_t  items_initialised; ///< The number of items initialised.
+
+    const uint32_t ITEM_SIZE;    ///< The size of allocated items.
+    const uint32_t MAX_SIZE;    ///< The maximum number of objects that can be allocated.
+  };
+
+  //*************************************************************************
+  /// A templated pool implementation that uses a fixed size pool.
+  ///\ingroup pool
+  //*************************************************************************
+  template <typename T, const size_t SIZE_>
+  class pool : public etl::ipool
+  {
+  public:
+
+    static const size_t SIZE = SIZE_;
+
+    //*************************************************************************
+    /// Constructor
+    //*************************************************************************
+    pool()
+      : etl::ipool(reinterpret_cast<char*>(&buffer[0]), ELEMENT_SIZE, SIZE)
+    {
+    }
+
+    //*************************************************************************
+    /// Allocate an object from the pool.
+    /// Uses the default constructor.
+    /// If asserts or exceptions are enabled and there are no more free items an
+    /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned.
+    /// Static asserts if the specified type is too large for the pool.
+    //*************************************************************************
+    template <typename U>
+    U* allocate()
+    {
+      STATIC_ASSERT(sizeof(U) <= ELEMENT_SIZE, "Type too large for pool");
+      return ipool::allocate<U>();
+    }
+
+  private:
+
+    // The pool element.
+    union Element
+    {
+      uintptr_t next;             ///< Pointer to the next free element.
+      char      value[sizeof(T)]; ///< Storage for value type.
+      typename  etl::type_with_alignment<etl::alignment_of<T>::value>::type dummy; ///< Dummy item to get correct alignment.
+    };
+
+    ///< The memory for the pool of objects.
+    typename etl::aligned_storage<sizeof(Element), etl::alignment_of<Element>::value>::type buffer[SIZE];
+
+    static const uint32_t ELEMENT_SIZE = sizeof(Element);
+
+    // Should not be copied.
+    pool(const pool&);
+    pool& operator =(const pool&);
+  };
+
+  //*************************************************************************
+  /// A templated abstract pool implementation that uses a fixed size pool.
+  ///\ingroup pool
+  //*************************************************************************
+  template <const size_t TYPE_SIZE_, const size_t ALIGNMENT_, const size_t SIZE_>
+  class generic_pool : public etl::ipool
+  {
+  public:
+
+    static const size_t SIZE      = SIZE_;
+    static const size_t ALIGNMENT = ALIGNMENT_;
+    static const size_t TYPE_SIZE = TYPE_SIZE_;
+
+    //*************************************************************************
+    /// Constructor
+    //*************************************************************************
+    generic_pool()
+      : etl::ipool(reinterpret_cast<char*>(&buffer[0]), ELEMENT_SIZE, SIZE)
+    {
+    }
+
+    //*************************************************************************
+    /// Allocate an object from the pool.
+    /// If asserts or exceptions are enabled and there are no more free items an
+    /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned.
+    /// Static asserts if the specified type is too large for the pool.
+    //*************************************************************************
+    template <typename U>
+    U* allocate()
+    {
+      STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
+      STATIC_ASSERT(sizeof(U)  <= ELEMENT_SIZE, "Type too large for pool");
+      return ipool::allocate<U>();
+    }
+
+  private:
+
+    // The pool element.
+    union Element
+    {
+      uintptr_t next;              ///< Pointer to the next free element.
+      char      value[TYPE_SIZE_]; ///< Storage for value type.
+      typename  etl::type_with_alignment<ALIGNMENT_>::type dummy; ///< Dummy item to get correct alignment.
+    };
+
+    ///< The memory for the pool of objects.
+    typename etl::aligned_storage<sizeof(Element), etl::alignment_of<Element>::value>::type buffer[SIZE];
+
+    static const uint32_t ELEMENT_SIZE = sizeof(Element);
+
+    // Should not be copied.
+    generic_pool(const generic_pool&);
+    generic_pool& operator =(const generic_pool&);
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/power.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,184 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_POW__
+#define __ETL_POW__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "platform.h"
+#include "log.h"
+
+///\defgroup power power
+/// power<N, POWER> : Calculates N to the power POWER.
+///\ingroup maths
+
+namespace etl 
+{
+  //***************************************************************************
+  ///\ingroup power
+  /// Calculates powers.
+  ///\note Only supports positive N.
+  //***************************************************************************
+  template <const size_t NV, const size_t POWER>
+  struct power
+  {
+    static const uint64_t value = NV * power<NV, POWER - 1>::value;
+  };
+
+  //***************************************************************************
+  /// Calculates powers.
+  ///\note Only supports positive N.
+  /// Specialisation for POWER == 0.
+  //***************************************************************************
+  template <const size_t NV>
+  struct power<NV, 0>
+  {
+    static const uint64_t value = 1;
+  };
+
+  //***************************************************************************
+  ///\ingroup power
+  /// Calculates the rounded up power of 2.
+  //***************************************************************************
+  template <const size_t NV>
+  struct power_of_2_round_up
+  {
+    enum value_type
+    {
+      value = 1 << (etl::log2<NV - 1>::value + 1)
+    };
+  };
+
+  //***************************************************************************
+  ///\ingroup power
+  /// Calculates the rounded up power of 2.
+  /// Specialisation for 0.
+  //***************************************************************************
+  template <>
+  struct power_of_2_round_up<0>
+  {
+    enum value_type
+    {
+      value = 2
+    };
+  };
+
+  //***************************************************************************
+  ///\ingroup power
+  /// Calculates the rounded down power of 2.
+  //***************************************************************************
+  template <const size_t NV>
+  struct power_of_2_round_down
+  {
+    enum value_type
+    {
+      value = 1 << (etl::log2<NV - 1>::value)
+    };
+  };
+
+  //***************************************************************************
+  ///\ingroup power
+  /// Calculates the rounded down power of 2.
+  /// Specialisation for 0.
+  //***************************************************************************
+  template <>
+  struct power_of_2_round_down<0>
+  {
+    enum value_type
+    {
+      value = 2
+    };
+  };
+
+  //***************************************************************************
+  ///\ingroup power
+  /// Calculates the rounded down power of 2.
+  /// Specialisation for 1.
+  //***************************************************************************
+  template <>
+  struct power_of_2_round_down<1>
+  {
+    enum value_type
+    {
+      value = 2
+    };
+  };
+
+  //***************************************************************************
+  ///\ingroup power
+  /// Calculates the rounded down power of 2.
+  /// Specialisation for 2.
+  //***************************************************************************
+  template <>
+  struct power_of_2_round_down<2>
+  {
+    enum value_type
+    {
+      value = 2
+    };
+  };
+
+  //***************************************************************************
+  ///\ingroup power
+  /// Checks if N is a power of 2.
+  //***************************************************************************
+  template <const size_t NV>
+  struct is_power_of_2
+  {
+    static const bool value = (NV & (NV - 1)) == 0;
+  };
+
+  //***************************************************************************
+  ///\ingroup power
+  /// Checks if N is a power of 2.
+  /// Specialisation for 0.
+  //***************************************************************************
+  template <>
+  struct is_power_of_2<0>
+  {
+    static const bool value = false;
+  };
+
+  //***************************************************************************
+  ///\ingroup power
+  /// Checks if N is a power of 2.
+  /// Specialisation for 1.
+  //***************************************************************************
+  template <>
+  struct is_power_of_2<1>
+  {
+    static const bool value = false;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/priority_queue.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,429 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove, rlindeman
+
+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 __ETL_PRIORITY_QUEUE__
+#define __ETL_PRIORITY_QUEUE__
+
+#include <stddef.h>
+#include <functional>
+#include <algorithm>
+
+#include "platform.h"
+#include "container.h"
+#include "vector.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "error_handler.h"
+#include "exception.h"
+
+#undef ETL_FILE
+#define ETL_FILE "12"
+
+//*****************************************************************************
+///\defgroup queue queue
+/// A priority queue with the capacity defined at compile time,
+/// written in the STL style.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for priority_queue exceptions.
+  ///\ingroup queue
+  //***************************************************************************
+  class priority_queue_exception : public exception
+  {
+  public:
+
+    priority_queue_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The exception thrown when the queue is full.
+  ///\ingroup queue
+  //***************************************************************************
+  class priority_queue_full : public etl::priority_queue_exception
+  {
+  public:
+
+    priority_queue_full(string_type file_name_, numeric_type line_number_)
+      : priority_queue_exception(ETL_ERROR_TEXT("priority_queue:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The priority queue iterator exception on reversed iterators
+  ///\ingroup queue
+  //***************************************************************************
+  class priority_queue_iterator : public etl::priority_queue_exception
+  {
+  public:
+
+    priority_queue_iterator(string_type file_name_, numeric_type line_number_)
+      : priority_queue_exception(ETL_ERROR_TEXT("priority_queue:iterator", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup queue
+  ///\brief This is the base for all priority queues that contain a particular type.
+  ///\details Normally a reference to this type will be taken from a derived queue.
+  /// The TContainer specified must provide the front, push_back, pop_back, and
+  /// assign methods to work correctly with priority_queue.
+  ///\code
+  /// etl::priority_queue<int, 10> myPriorityQueue;
+  /// etl::ipriority_queue<int>& iQueue = myPriorityQueue;
+  ///\endcode
+  /// \warning This priority queue cannot be used for concurrent access from
+  /// multiple threads.
+  /// \tparam T The type of value that the queue holds.
+  /// \tparam TContainer to hold the T queue values
+  /// \tparam TCompare to use in comparing T values
+  //***************************************************************************
+  template <typename T, typename TContainer, typename TCompare>
+  class ipriority_queue
+  {
+  public:
+
+    typedef T                     value_type;         ///< The type stored in the queue.
+    typedef TContainer            container_type;     ///< The container type used for priority queue.
+    typedef TCompare              compare_type;       ///< The comparison type.
+    typedef T&                    reference;          ///< A reference to the type used in the queue.
+    typedef const T&              const_reference;    ///< A const reference to the type used in the queue.
+    typedef typename TContainer::size_type size_type; ///< The type used for determining the size of the queue.
+    typedef typename std::iterator_traits<typename TContainer::iterator>::difference_type difference_type;
+
+  private:
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+
+  public:
+
+    //*************************************************************************
+    /// Gets a reference to the highest priority value in the priority queue.<br>
+    /// \return A reference to the highest priority value in the priority queue.
+    //*************************************************************************
+    reference top()
+    {
+      return container.front();
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the highest priority value in the priority queue.<br>
+    /// \return A const reference to the highest priority value in the priority queue.
+    //*************************************************************************
+    const_reference top() const
+    {
+      return container.front();
+    }
+
+    //*************************************************************************
+    /// Adds a value to the queue.
+    /// If asserts or exceptions are enabled, throws an etl::priority_queue_full
+    /// is the priority queue is already full.
+    ///\param value The value to push to the queue.
+    //*************************************************************************
+    void push(parameter_t value)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(etl::priority_queue_full));
+
+      // Put element at end
+      container.push_back(value);
+      // Make elements in container into heap
+      std::push_heap(container.begin(), container.end(), TCompare());
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the queue.
+    /// If asserts or exceptions are enabled, throws an etl::priority_queue_full
+    /// is the priority queue is already full.
+    ///\param value The value to push to the queue.
+    //*************************************************************************
+    template <typename T1>
+    void emplace(const T1& value1)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(etl::priority_queue_full));
+
+      // Put element at end
+      container.emplace_back(value1);
+      // Make elements in container into heap
+      std::push_heap(container.begin(), container.end(), TCompare());
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the queue.
+    /// If asserts or exceptions are enabled, throws an etl::priority_queue_full
+    /// is the priority queue is already full.
+    ///\param value The value to push to the queue.
+    //*************************************************************************
+    template <typename T1, typename T2>
+    void emplace(const T1& value1, const T2& value2)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(etl::priority_queue_full));
+
+      // Put element at end
+      container.emplace_back(value1, value2);
+      // Make elements in container into heap
+      std::push_heap(container.begin(), container.end(), TCompare());
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the queue.
+    /// If asserts or exceptions are enabled, throws an etl::priority_queue_full
+    /// is the priority queue is already full.
+    ///\param value The value to push to the queue.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3>
+    void emplace(const T1& value1, const T2& value2, const T3& value3)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(etl::priority_queue_full));
+
+      // Put element at end
+      container.emplace_back(value1, value2, value3);
+      // Make elements in container into heap
+      std::push_heap(container.begin(), container.end(), TCompare());
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the queue.
+    /// If asserts or exceptions are enabled, throws an etl::priority_queue_full
+    /// is the priority queue is already full.
+    ///\param value The value to push to the queue.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    void emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(etl::priority_queue_full));
+
+      // Put element at end
+      container.emplace_back(value1, value2, value3, value4);
+      // Make elements in container into heap
+      std::push_heap(container.begin(), container.end(), TCompare());
+    }
+
+    //*************************************************************************
+    /// Assigns values to the priority queue.
+    /// If asserts or exceptions are enabled, emits priority_queue_full if
+    /// priority queue does not have enough free space.
+    /// If asserts or exceptions are enabled, emits priority_iterator if the
+    /// iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(d >= 0, ETL_ERROR(etl::priority_queue_iterator));
+      ETL_ASSERT(static_cast<size_t>(d) <= max_size(), ETL_ERROR(etl::priority_queue_full));
+#endif
+
+      clear();
+      container.assign(first, last);
+      std::make_heap(container.begin(), container.end(), TCompare());
+    }
+
+    //*************************************************************************
+    /// Removes the oldest value from the back of the priority queue.
+    /// Does nothing if the priority queue is already empty.
+    //*************************************************************************
+    void pop()
+    {
+      // Move largest element to end
+      std::pop_heap(container.begin(), container.end(), TCompare());
+      // Actually remove largest element at end
+      container.pop_back();
+    }
+
+    //*************************************************************************
+    /// Gets the highest priority value in the priority queue
+    /// and assigns it to destination and removes it from the queue.
+    //*************************************************************************
+    void pop_into(reference destination)
+    {
+      destination = top();
+      pop();
+    }
+
+    //*************************************************************************
+    /// Returns the current number of items in the priority queue.
+    //*************************************************************************
+    size_type size() const
+    {
+      return container.size();
+    }
+
+    //*************************************************************************
+    /// Returns the maximum number of items that can be queued.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return container.max_size();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the priority queue is empty.
+    /// \return <b>true</b> if the queue is empty, otherwise <b>false</b>
+    //*************************************************************************
+    bool empty() const
+    {
+      return container.empty();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the priority queue is full.
+    /// \return <b>true</b> if the priority queue is full, otherwise <b>false</b>
+    //*************************************************************************
+    bool full() const
+    {
+      return container.size() == container.max_size();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return container.max_size() - container.size();
+    }
+
+    //*************************************************************************
+    /// Clears the queue to the empty state.
+    //*************************************************************************
+    void clear()
+    {
+      container.clear();
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Make this a clone of the supplied priority queue
+    //*************************************************************************
+    void clone(const ipriority_queue& other)
+    {
+      assign(other.container.cbegin(), other.container.cend());
+    }
+
+    //*************************************************************************
+    /// The constructor that is called from derived classes.
+    //*************************************************************************
+    ipriority_queue()
+    {
+    }
+
+  private:
+
+    // Disable copy construction.
+    ipriority_queue(const ipriority_queue&);
+
+    /// The container specified at instantiation of the priority_queue
+    TContainer container;
+  };
+
+  //***************************************************************************
+  ///\ingroup priority_queue
+  /// A fixed capacity priority queue.
+  /// This queue does not support concurrent access by different threads.
+  /// \tparam T    The type this queue should support.
+  /// \tparam SIZE The maximum capacity of the queue.
+  //***************************************************************************
+  template <typename T, const size_t SIZE, typename TContainer = etl::vector<T, SIZE>, typename TCompare = std::less<typename TContainer::value_type> >
+  class priority_queue : public etl::ipriority_queue<T, TContainer, TCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = SIZE;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    priority_queue()
+      : etl::ipriority_queue<T, TContainer, TCompare>()
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor
+    //*************************************************************************
+    priority_queue(const priority_queue& rhs)
+      : etl::ipriority_queue<T, TContainer, TCompare>()
+    {
+      etl::ipriority_queue<T, TContainer, TCompare>::clone(rhs);
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    priority_queue(TIterator first, TIterator last)
+      : etl::ipriority_queue<T, TContainer, TCompare>()
+    {
+      etl::ipriority_queue<T, TContainer, TCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~priority_queue()
+    {
+      etl::ipriority_queue<T, TContainer, TCompare>::clear();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    priority_queue& operator = (const priority_queue& rhs)
+    {
+      if (&rhs != this)
+      {
+        etl::ipriority_queue<T, TContainer, TCompare>::clone(rhs);
+      }
+
+      return *this;
+    }
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/private/ivectorpointer.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,562 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_IVECTOR_POINTER__
+#define __ETL_IVECTOR_POINTER__
+
+#ifndef __ETL_IN_VECTOR_H__
+#error  This header is a private element of etl::ivector
+#endif
+
+#include "pvoidvector.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for specifically sized vectors.
+  /// Can be used as a reference type for all vectors containing a specific pointer type.
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  class ivector<T*> : public pvoidvector
+  {
+  public:
+
+    typedef T*                                    value_type;
+    typedef T*&                                   reference;
+    typedef const T* const &                      const_reference;
+    typedef T**                                   pointer;
+    typedef const T* const *                      const_pointer;
+    typedef T**                                   iterator;
+    typedef const T* const *                      const_iterator;
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef size_t                                size_type;
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+  protected:
+
+    typedef value_type parameter_t;
+
+  private:
+
+    typedef pvoidvector base_t;
+
+  public:
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the vector.
+    ///\return An iterator to the beginning of the vector.
+    //*********************************************************************
+    iterator begin()
+    {
+      return iterator(base_t::begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the vector.
+    ///\return A const iterator to the beginning of the vector.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(base_t::begin());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the vector.
+    ///\return An iterator to the end of the vector.
+    //*********************************************************************
+    iterator end()
+    {
+      return iterator(base_t::end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the vector.
+    ///\return A const iterator to the end of the vector.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(base_t::end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the vector.
+    ///\return A const iterator to the beginning of the vector.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(base_t::cbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the vector.
+    ///\return A const iterator to the end of the vector.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(base_t::cend());
+    }
+
+    //*********************************************************************
+    /// Returns an reverse iterator to the reverse beginning of the vector.
+    ///\return Iterator to the reverse beginning of the vector.
+    //*********************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(iterator(base_t::end()));
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the vector.
+    ///\return Const iterator to the reverse beginning of the vector.
+    //*********************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(const_iterator(base_t::end()));
+    }
+
+    //*********************************************************************
+    /// Returns a reverse iterator to the end + 1 of the vector.
+    ///\return Reverse iterator to the end + 1 of the vector.
+    //*********************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(iterator(base_t::begin()));
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the vector.
+    ///\return Const reverse iterator to the end + 1 of the vector.
+    //*********************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(const_iterator(base_t::begin()));
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the vector.
+    ///\return Const reverse iterator to the reverse beginning of the vector.
+    //*********************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(const_iterator(base_t::cend()));
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the vector.
+    ///\return Const reverse iterator to the end + 1 of the vector.
+    //*********************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(const_iterator(base_t::cbegin()));
+    }
+
+    //*********************************************************************
+    /// Resizes the vector.
+    /// If asserts or exceptions are enabled and the new size is larger than the
+    /// maximum then a vector_full is thrown.
+    ///\param new_size The new size.
+    //*********************************************************************
+    void resize(size_t new_size)
+    {
+      base_t::resize(new_size);
+    }
+
+    //*********************************************************************
+    /// Resizes the vector.
+    /// If asserts or exceptions are enabled and the new size is larger than the
+    /// maximum then a vector_full is thrown.
+    ///\param new_size The new size.
+    ///\param value   The value to fill new elements with. Default = default constructed value.
+    //*********************************************************************
+    void resize(size_t new_size, value_type value)
+    {
+      base_t::resize(new_size, value);
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'i'
+    ///\param i The index.
+    ///\return A reference to the value at index 'i'
+    //*********************************************************************
+    reference operator [](size_t i)
+    {
+      return reference(base_t::operator[](i));
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'i'
+    ///\param i The index.
+    ///\return A const reference to the value at index 'i'
+    //*********************************************************************
+    const_reference operator [](size_t i) const
+    {
+      return const_reference(base_t::operator[](i));
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'i'
+    /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range.
+    ///\param i The index.
+    ///\return A reference to the value at index 'i'
+    //*********************************************************************
+    reference at(size_t i)
+    {
+      return reference(base_t::at(i));
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'i'
+    /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range.
+    ///\param i The index.
+    ///\return A const reference to the value at index 'i'
+    //*********************************************************************
+    const_reference at(size_t i) const
+    {
+      return const_reference(base_t::at(i));
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the first element.
+    ///\return A reference to the first element.
+    //*********************************************************************
+    reference front()
+    {
+      return reference(base_t::front());
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the first element.
+    ///\return A const reference to the first element.
+    //*********************************************************************
+    const_reference front() const
+    {
+      return const_reference(base_t::front());
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the last element.
+    ///\return A reference to the last element.
+    //*********************************************************************
+    reference back()
+    {
+      return reference(base_t::back());
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the last element.
+    ///\return A const reference to the last element.
+    //*********************************************************************
+    const_reference back() const
+    {
+      return const_reference(base_t::back());
+    }
+
+    //*********************************************************************
+    /// Returns a pointer to the beginning of the vector data.
+    ///\return A pointer to the beginning of the vector data.
+    //*********************************************************************
+    pointer data()
+    {
+      return pointer(base_t::data());
+    }
+
+    //*********************************************************************
+    /// Returns a const pointer to the beginning of the vector data.
+    ///\return A const pointer to the beginning of the vector data.
+    //*********************************************************************
+    const_pointer data() const
+    {
+      return const_pointer(base_t::data());
+    }
+
+    //*********************************************************************
+    /// Assigns values to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+    /// If asserts or exceptions are enabled, emits vector_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+      base_t::initialise();
+
+      while (first != last)
+      {
+        *p_end++ = (void*)*first++;
+      }
+    }
+
+    //*********************************************************************
+    /// Assigns values to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+    ///\param n     The number of elements to add.
+    ///\param value The value to insert for each element.
+    //*********************************************************************
+    void assign(size_t n, parameter_t value)
+    {
+      base_t::assign(n, value);
+    }
+
+    //*************************************************************************
+    /// Clears the vector.
+    //*************************************************************************
+    void clear()
+    {
+      base_t::clear();
+    }
+
+    //*************************************************************************
+    /// Increases the size of the vector by one, but does not initialise the new element.
+    /// If asserts or exceptions are enabled, throws a vector_full if the vector is already full.
+    //*************************************************************************
+    void push_back()
+    {
+      base_t::push_back();
+    }
+
+    //*********************************************************************
+    /// Inserts a value at the end of the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+    ///\param value The value to add.
+    //*********************************************************************
+    void push_back(parameter_t value)
+    {
+      base_t::push_back(value);
+    }
+
+    //*************************************************************************
+    /// Removes an element from the end of the vector.
+    /// Does nothing if the vector is empty.
+    //*************************************************************************
+    void pop_back()
+    {
+      base_t::pop_back();
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+    ///\param position The position to insert before.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator position, parameter_t value)
+    {
+      return iterator(base_t::insert(base_t::iterator(position), value));
+    }
+
+    //*********************************************************************
+    /// Inserts 'n' values to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+    ///\param position The position to insert before.
+    ///\param n        The number of elements to add.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    void insert(iterator position, size_t n, parameter_t value)
+    {
+      base_t::insert(base_t::iterator(position), n, value);
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+    ///\param position The position to insert before.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(iterator position, TIterator first, TIterator last)
+    {
+      base_t::insert(base_t::iterator(position), first, last);
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param i_element Iterator to the element.
+    ///\return An iterator pointing to the element that followed the erased element.
+    //*********************************************************************
+    iterator erase(iterator i_element)
+    {
+      return iterator(base_t::erase(base_t::iterator(i_element)));
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    ///\return An iterator pointing to the element that followed the erased element.
+    //*********************************************************************
+    iterator erase(iterator first, iterator last)
+    {
+      return iterator(base_t::erase(base_t::iterator(first), base_t::iterator(last)));
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    ivector& operator = (const ivector& rhs)
+    {
+      if (&rhs != this)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    ivector(T** p_buffer_, size_t MAX_SIZE_)
+      : pvoidvector(reinterpret_cast<void**>(p_buffer_), MAX_SIZE_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  bool operator ==(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs)
+  {
+    return pvoidvector_equal(lhs, rhs);
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  bool operator !=(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs)
+  {
+    return pvoidvector_not_equal(lhs, rhs);
+  }
+
+  //***************************************************************************
+  /// Less than operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the first vector is lexicographically less than the second, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  bool operator <(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs)
+  {
+    return pvoidvector_less_than(lhs, rhs);
+  }
+
+  //***************************************************************************
+  /// Greater than operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the first vector is lexicographically greater than the second, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  bool operator >(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs)
+  {
+    return pvoidvector_greater_than(lhs, rhs);
+  }
+
+  //***************************************************************************
+  /// Less than or equal operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the first vector is lexigraphically less than or equal to the second, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  bool operator <=(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs)
+  {
+    return pvoidvector_less_than_equal(lhs, rhs);
+  }
+
+  //***************************************************************************
+  /// Greater than or equal operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the first vector is lexigraphically greater than or equal to the second, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  bool operator >=(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs)
+  {
+    return pvoidvector_greater_than_equal(lhs, rhs);
+  }
+
+  //***************************************************************************
+  // Helper functions
+  //***************************************************************************
+  inline bool pvoidvector_equal(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs)
+  {
+    return operator ==(lhs, rhs);
+  }
+
+  inline bool pvoidvector_not_equal(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs)
+  {
+    return operator !=(lhs, rhs);
+  }
+
+  inline bool pvoidvector_less_than(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs)
+  {
+    return operator <(lhs, rhs);
+  }
+
+  inline bool pvoidvector_greater_than(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs)
+  {
+    return operator >(lhs, rhs);
+  }
+
+  inline bool pvoidvector_less_than_equal(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs)
+  {
+    return operator <=(lhs, rhs);
+  }
+
+  inline bool pvoidvector_greater_than_equal(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs)
+  {
+    return operator >=(lhs, rhs);
+  }
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/private/pvoidvector.cpp	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,109 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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.
+******************************************************************************/
+
+#include "../platform.h"
+#include "pvoidvector.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  bool operator ==(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  bool operator !=(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //***************************************************************************
+  /// Less than operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the first vector is lexicographically less than the second, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  inline bool operator <(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs)
+  {
+    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+  }
+
+  //***************************************************************************
+  /// Greater than operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the first vector is lexicographically greater than the second, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  bool operator >(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs)
+  {
+    return (rhs < lhs);
+  }
+
+  //***************************************************************************
+  /// Less than or equal operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the first vector is lexicographically less than or equal to the second, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  bool operator <=(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs)
+  {
+    return !(lhs > rhs);
+  }
+
+  //***************************************************************************
+  /// Greater than or equal operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the first vector is lexicographically greater than or equal to the second, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  bool operator >=(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs)
+  {
+    return !(lhs < rhs);
+  }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/private/pvoidvector.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,604 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_PVOIDVECTOR__
+#define __ETL_PVOIDVECTOR__
+
+#define __ETL_IN_PVOIDVECTOR__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "../platform.h"
+#include "../algorithm.h"
+#include "vector_base.h"
+#include "../type_traits.h"
+#include "../error_handler.h"
+
+#ifdef ETL_COMPILER_GCC
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#endif
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for void* vectors.
+  ///\ingroup vector
+  //***************************************************************************
+  class pvoidvector : public vector_base
+  {
+  public:
+
+    typedef void*                                 value_type;
+    typedef void*&                                reference;
+    typedef const void*&                          const_reference;
+    typedef void**                                pointer;
+    typedef const void**                          const_pointer;
+    typedef void**                                iterator;
+    typedef const void**                          const_iterator;
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef size_t                                size_type;
+    typedef std::iterator_traits<iterator>::difference_type difference_type;
+
+  public:
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the vector.
+    ///\return An iterator to the beginning of the vector.
+    //*********************************************************************
+    iterator begin()
+    {
+      return p_buffer;
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the vector.
+    ///\return A const iterator to the beginning of the vector.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(p_buffer);
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the vector.
+    ///\return An iterator to the end of the vector.
+    //*********************************************************************
+    iterator end()
+    {
+      return p_end;
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the vector.
+    ///\return A const iterator to the end of the vector.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(p_end);
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the vector.
+    ///\return A const iterator to the beginning of the vector.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(p_buffer);
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the vector.
+    ///\return A const iterator to the end of the vector.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(p_end);
+    }
+
+    //*********************************************************************
+    /// Returns an reverse iterator to the reverse beginning of the vector.
+    ///\return Iterator to the reverse beginning of the vector.
+    //*********************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(end());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the vector.
+    ///\return Const iterator to the reverse beginning of the vector.
+    //*********************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(end());
+    }
+
+    //*********************************************************************
+    /// Returns a reverse iterator to the end + 1 of the vector.
+    ///\return Reverse iterator to the end + 1 of the vector.
+    //*********************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the vector.
+    ///\return Const reverse iterator to the end + 1 of the vector.
+    //*********************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the vector.
+    ///\return Const reverse iterator to the reverse beginning of the vector.
+    //*********************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(cend());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the vector.
+    ///\return Const reverse iterator to the end + 1 of the vector.
+    //*********************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(cbegin());
+    }
+
+    //*********************************************************************
+    /// Resizes the vector.
+    /// If asserts or exceptions are enabled and the new size is larger than the
+    /// maximum then a vector_full is thrown.
+    ///\param new_size The new size.
+    //*********************************************************************
+    void resize(size_t new_size)
+    {
+      ETL_ASSERT(new_size <= CAPACITY, ETL_ERROR(vector_full));
+
+      p_end = p_buffer + new_size;
+    }
+
+    //*********************************************************************
+    /// Resizes the vector.
+    /// If asserts or exceptions are enabled and the new size is larger than the
+    /// maximum then a vector_full is thrown.
+    ///\param new_size The new size.
+    ///\param value   The value to fill new elements with. Default = default constructed value.
+    //*********************************************************************
+    void resize(size_t new_size, value_type value)
+    {
+      ETL_ASSERT(new_size <= CAPACITY, ETL_ERROR(vector_full));
+
+      pointer p_new_end = p_buffer + new_size;
+
+      // Size up if necessary.
+      if (p_end < p_new_end)
+      {
+        std::fill(p_end, p_new_end, value);
+      }
+
+      p_end = p_new_end;
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'i'
+    ///\param i The index.
+    ///\return A reference to the value at index 'i'
+    //*********************************************************************
+    reference operator [](size_t i)
+    {
+      return p_buffer[i];
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'i'
+    ///\param i The index.
+    ///\return A const reference to the value at index 'i'
+    //*********************************************************************
+    const_reference operator [](size_t i) const
+    {
+      return const_reference(p_buffer[i]);
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'i'
+    /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range.
+    ///\param i The index.
+    ///\return A reference to the value at index 'i'
+    //*********************************************************************
+    reference at(size_t i)
+    {
+      ETL_ASSERT(i < size(), ETL_ERROR(vector_out_of_bounds));
+      return p_buffer[i];
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'i'
+    /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range.
+    ///\param i The index.
+    ///\return A const reference to the value at index 'i'
+    //*********************************************************************
+    const_reference at(size_t i) const
+    {
+      ETL_ASSERT(i < size(), ETL_ERROR(vector_out_of_bounds));
+      return const_reference(p_buffer[i]);
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the first element.
+    ///\return A reference to the first element.
+    //*********************************************************************
+    reference front()
+    {
+      return p_buffer[0];
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the first element.
+    ///\return A const reference to the first element.
+    //*********************************************************************
+    const_reference front() const
+    {
+      return const_reference(p_buffer[0]);
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the last element.
+    ///\return A reference to the last element.
+    //*********************************************************************
+    reference back()
+    {
+      return *(p_end  -1);
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the last element.
+    ///\return A const reference to the last element.
+    //*********************************************************************
+    const_reference back() const
+    {
+      return const_reference(*(p_end - 1));
+    }
+
+    //*********************************************************************
+    /// Returns a pointer to the beginning of the vector data.
+    ///\return A pointer to the beginning of the vector data.
+    //*********************************************************************
+    pointer data()
+    {
+      return p_buffer;
+    }
+
+    //*********************************************************************
+    /// Returns a const pointer to the beginning of the vector data.
+    ///\return A const pointer to the beginning of the vector data.
+    //*********************************************************************
+    const_pointer data() const
+    {
+      return const_pointer(p_buffer);
+    }
+
+    //*********************************************************************
+    /// Assigns values to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+    /// If asserts or exceptions are enabled, emits vector_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(static_cast<size_t>(d) <= CAPACITY, ETL_ERROR(vector_full));
+#endif
+
+      initialise();
+
+      while (first != last)
+      {
+        *p_end++ = const_cast<void*>(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Assigns values to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+    ///\param n     The number of elements to add.
+    ///\param value The value to insert for each element.
+    //*********************************************************************
+    void assign(size_t n, value_type value)
+    {
+      initialise();
+
+      ETL_ASSERT(n <= CAPACITY, ETL_ERROR(vector_full));
+
+      for (size_t current_size = 0; current_size < n; ++current_size)
+      {
+        *p_end++ = value;
+      }
+    }
+
+    //*************************************************************************
+    /// Clears the vector.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*************************************************************************
+    /// Increases the size of the vector by one, but does not initialise the new element.
+    /// If asserts or exceptions are enabled, throws a vector_full if the vector is already full.
+    //*************************************************************************
+    void push_back()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full));
+#endif
+
+      ++p_end;
+    }
+
+    //*********************************************************************
+    /// Inserts a value at the end of the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+    ///\param value The value to add.
+    //*********************************************************************
+    void push_back(value_type value)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full));
+#endif
+      *p_end++ = value;
+    }
+
+    //*************************************************************************
+    /// Removes an element from the end of the vector.
+    /// Does nothing if the vector is empty.
+    //*************************************************************************
+    void pop_back()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(size() > 0, ETL_ERROR(vector_empty));
+#endif
+      --p_end;
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+    ///\param position The position to insert before.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator position, value_type value)
+    {
+      ETL_ASSERT(size() + 1 <= CAPACITY, ETL_ERROR(vector_full));
+
+      if (position != end())
+      {
+        ++p_end;
+        std::copy_backward(position, end() - 1, end());
+        *position = value;
+      }
+      else
+      {
+        *p_end++ = value;
+      }
+
+      return position;
+    }
+
+    //*********************************************************************
+    /// Inserts 'n' values to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+    ///\param position The position to insert before.
+    ///\param n        The number of elements to add.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    void insert(iterator position, size_t n, value_type value)
+    {
+      ETL_ASSERT((size() + 1) <= CAPACITY, ETL_ERROR(vector_full));
+
+      std::copy_backward(position, p_end, p_end + n);
+      std::fill_n(position, n, value);
+
+      p_end += n;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+    /// For fundamental and pointer types.
+    ///\param position The position to insert before.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <typename TIterator>
+    void insert(iterator position, TIterator first, TIterator last)
+    {
+      size_t count = std::distance(first, last);
+
+      ETL_ASSERT((size() + count) <= CAPACITY, ETL_ERROR(vector_full));
+
+      std::copy_backward(position, p_end, p_end + count);
+      std::copy(first, last, position);
+      p_end += count;
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param i_element Iterator to the element.
+    ///\return An iterator pointing to the element that followed the erased element.
+    //*********************************************************************
+    iterator erase(iterator i_element)
+    {
+      std::copy(i_element + 1, end(), i_element);
+      --p_end;
+
+      return i_element;
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    ///\return An iterator pointing to the element that followed the erased element.
+    //*********************************************************************
+    iterator erase(iterator first, iterator last)
+    {
+      std::copy(last, end(), first);
+      size_t n_delete = std::distance(first, last);
+
+      // Just adjust the count.
+      p_end -= n_delete;
+
+      return first;
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    pvoidvector& operator = (const pvoidvector& rhs)
+    {
+      if (&rhs != this)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Gets the current size of the vector.
+    ///\return The current size of the vector.
+    //*************************************************************************
+    size_type size() const
+    {
+      return size_t(p_end - p_buffer);
+    }
+
+    //*************************************************************************
+    /// Checks the 'empty' state of the vector.
+    ///\return <b>true</b> if empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return (p_end == p_buffer);
+    }
+
+    //*************************************************************************
+    /// Checks the 'full' state of the vector.
+    ///\return <b>true</b> if full.
+    //*************************************************************************
+    bool full() const
+    {
+      return size() == CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return max_size() - size();
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    pvoidvector(void** p_buffer_, size_t MAX_SIZE)
+      : vector_base(MAX_SIZE),
+        p_buffer(p_buffer_),
+        p_end(p_buffer_)
+    {
+    }
+
+    //*********************************************************************
+    /// Initialise the vector.
+    //*********************************************************************
+    void initialise()
+    {
+      p_end = p_buffer;
+    }
+
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    void repair(void** p_buffer_)
+    {
+      uintptr_t length = p_end - p_buffer;
+
+      p_buffer = p_buffer_;
+      p_end    = p_buffer_ + length;
+    }
+
+    void** p_buffer;
+    void** p_end;
+
+  private:
+
+    // Disable copy construction.
+    pvoidvector(const pvoidvector&);
+  };
+
+  bool operator ==(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs);
+  bool operator !=(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs);
+  bool operator  <(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs);
+  bool operator  >(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs);
+  bool operator <=(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs);
+  bool operator >=(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef __ETL_IN_PVOIDVECTOR__
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/private/vector_base.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,165 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+#if !defined(__ETL_IN_VECTOR_H__) && !defined(__ETL_IN_PVOIDVECTOR__)
+#error This header is a private element of etl::vector & etl::pvoidvector
+#endif
+
+#ifndef __ETL_VECTOR_BASE__
+#define __ETL_VECTOR_BASE__
+
+#include <stddef.h>
+
+#include "../platform.h"
+#include "../exception.h"
+#include "../error_handler.h"
+#include "../debug_count.h"
+
+#define ETL_FILE "17"
+
+namespace etl
+{
+  //***************************************************************************
+  ///\ingroup vector
+  /// Exception base for vectors
+  //***************************************************************************
+  class vector_exception : public exception
+  {
+  public:
+
+    vector_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup vector
+  /// Vector full exception.
+  //***************************************************************************
+  class vector_full : public vector_exception
+  {
+  public:
+
+    vector_full(string_type file_name_, numeric_type line_number_)
+      : vector_exception(ETL_ERROR_TEXT("vector:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup vector
+  /// Vector empty exception.
+  //***************************************************************************
+  class vector_empty : public vector_exception
+  {
+  public:
+
+    vector_empty(string_type file_name_, numeric_type line_number_)
+      : vector_exception(ETL_ERROR_TEXT("vector:empty", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup vector
+  /// Vector out of bounds exception.
+  //***************************************************************************
+  class vector_out_of_bounds : public vector_exception
+  {
+  public:
+
+    vector_out_of_bounds(string_type file_name_, numeric_type line_number_)
+      : vector_exception(ETL_ERROR_TEXT("vector:bounds", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup vector
+  /// Vector incompatible type exception.
+  //***************************************************************************
+  class vector_incompatible_type : public vector_exception
+  {
+  public:
+
+    vector_incompatible_type(string_type file_name_, numeric_type line_number_)
+      : vector_exception(ETL_ERROR_TEXT("vector:type", ETL_FILE"D"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup vector
+  /// The base class for all templated vector types.
+  //***************************************************************************
+  class vector_base
+  {
+  public:
+
+    typedef size_t size_type;
+
+    //*************************************************************************
+    /// Returns the capacity of the vector.
+    ///\return The capacity of the vector.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the vector.
+    ///\return The maximum size of the vector.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return CAPACITY;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    vector_base(size_type max_size_)
+      : CAPACITY(max_size_)
+    {
+    }
+
+    const size_type CAPACITY;         ///<The maximum number of elements in the vector.
+    etl::debug_count construct_count; ///< Internal debugging.
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/arduino_arm.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,51 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_ARDUINO__
+#define __ETL_ARDUINO__
+
+//*****************************************************************************
+// Arduino
+//*****************************************************************************
+
+#include <limits.h>
+
+#define ETL_TARGET_DEVICE_ARM
+#define ETL_TARGET_OS_NONE
+#define ETL_COMPILER_GCC
+#define ETL_CPP11_SUPPORTED 0
+#define ETL_CPP14_SUPPORTED 0
+#define ETL_NO_NULLPTR_SUPPORT    1
+#define ETL_NO_LARGE_CHAR_SUPPORT 1
+#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0
+#define ETL_ATOMIC_SUPPORTED 0
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/armv5.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,51 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_ARMV5__
+#define __ETL_ARMV5__
+
+//*****************************************************************************
+// ARM Compiler Version 5
+//*****************************************************************************
+
+#include <limits.h>
+
+#define ETL_TARGET_DEVICE_ARM
+#define ETL_TARGET_OS_NONE
+#define ETL_COMPILER_ARM
+#define ETL_CPP11_SUPPORTED 0
+#define ETL_CPP14_SUPPORTED 0
+#define ETL_NO_NULLPTR_SUPPORT 0
+#define ETL_NO_LARGE_CHAR_SUPPORT 1
+#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0
+#define ETL_ATOMIC_SUPPORTED 0
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/armv6.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,51 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_ARMV6__
+#define __ETL_ARMV6__
+
+//*****************************************************************************
+// ARM Compiler Version 6
+//*****************************************************************************
+
+#include <limits.h>
+
+#define ETL_TARGET_DEVICE_ARM
+#define ETL_TARGET_OS_NONE
+#define ETL_COMPILER_LLVM
+#undef ETL_CPP11_SUPPORTED 
+#undef ETL_CPP14_SUPPORTED 
+#define ETL_NO_NULLPTR_SUPPORT 1
+#define ETL_NO_LARGE_CHAR_SUPPORT 0
+#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0
+#define ETL_ATOMIC_SUPPORTED 1
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/cpp03.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,51 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_CPP03__
+#define __ETL_CPP03__
+
+//*****************************************************************************
+// Generic C++03
+//*****************************************************************************
+
+#include <limits.h>
+
+#define ETL_TARGET_DEVICE_GENERIC
+#define ETL_TARGET_OS_NONE
+#define ETL_COMPILER_GENERIC
+#define ETL_CPP11_SUPPORTED 0
+#define ETL_CPP14_SUPPORTED 0
+#define ETL_NO_NULLPTR_SUPPORT    1
+#define ETL_NO_LARGE_CHAR_SUPPORT 1
+#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0
+#define ETL_ATOMIC_SUPPORTED 0
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/cpp11.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,51 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_CPP11__
+#define __ETL_CPP11__
+
+//*****************************************************************************
+// Generic C++11
+//*****************************************************************************
+
+#include <limits.h>
+
+#define ETL_TARGET_DEVICE_GENERIC
+#define ETL_TARGET_OS_NONE
+#define ETL_COMPILER_GENERIC
+#define ETL_CPP11_SUPPORTED 1
+#define ETL_CPP14_SUPPORTED 0
+#define ETL_NO_NULLPTR_SUPPORT 0
+#define ETL_NO_LARGE_CHAR_SUPPORT 0
+#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1
+#define ETL_ATOMIC_SUPPORTED 1
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/cpp14.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,51 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_CPP14__
+#define __ETL_CPP14__
+
+//*****************************************************************************
+// Generic C++14
+//*****************************************************************************
+
+#include <limits.h>
+
+#define ETL_TARGET_DEVICE_GENERIC
+#define ETL_TARGET_OS_NONE
+#define ETL_COMPILER_GENERIC
+#define ETL_CPP11_SUPPORTED 1
+#define ETL_CPP14_SUPPORTED 1
+#define ETL_NO_NULLPTR_SUPPORT 0
+#define ETL_NO_LARGE_CHAR_SUPPORT 0
+#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1
+#define ETL_ATOMIC_SUPPORTED 1
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/gcc_generic.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,53 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_GCC__
+#define __ETL_GCC__
+
+//*****************************************************************************
+// GCC
+//*****************************************************************************
+
+#include <limits.h>
+
+#define ETL_TARGET_DEVICE_GENERIC
+#define ETL_TARGET_OS_NONE
+#define ETL_COMPILER_GCC
+
+  #define ETL_CPP11_SUPPORTED                      0
+  #define ETL_CPP14_SUPPORTED                      0
+
+#define ETL_NO_NULLPTR_SUPPORT                     !ETL_CPP11_SUPPORTED
+#define ETL_NO_LARGE_CHAR_SUPPORT                  !ETL_CPP11_SUPPORTED
+#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED
+#define ETL_ATOMIC_SUPPORTED                       ETL_CPP11_SUPPORTED
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/gcc_linux_x86.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,56 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_GCC__
+#define __ETL_GCC__
+
+//*****************************************************************************
+// GCC
+//*****************************************************************************
+
+#include <limits.h>
+
+#define ETL_TARGET_DEVICE_X86
+#define ETL_TARGET_OS_LINUX
+#define ETL_COMPILER_GCC
+#ifdef __cplusplus
+  #define ETL_CPP11_SUPPORTED                      (__cplusplus >= 201103L)
+  #define ETL_CPP14_SUPPORTED                      (__cplusplus >= 201402L)
+#else
+  #define ETL_CPP11_SUPPORTED                      0
+  #define ETL_CPP14_SUPPORTED                      0
+#endif
+#define ETL_NO_NULLPTR_SUPPORT                     !ETL_CPP11_SUPPORTED
+#define ETL_NO_LARGE_CHAR_SUPPORT                  !ETL_CPP11_SUPPORTED
+#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED
+#define ETL_ATOMIC_SUPPORTED                       ETL_CPP11_SUPPORTED
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/gcc_windows_x86.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,56 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_GCC__
+#define __ETL_GCC__
+
+//*****************************************************************************
+// GCC
+//*****************************************************************************
+
+#include <limits.h>
+
+#define ETL_TARGET_DEVICE_X86
+#define ETL_TARGET_OS_WINDOWS
+#define ETL_COMPILER_GCC
+#ifdef __cplusplus
+  #define ETL_CPP11_SUPPORTED                      (__cplusplus >= 201103L)
+  #define ETL_CPP14_SUPPORTED                      (__cplusplus >= 201402L)
+#else
+  #define ETL_CPP11_SUPPORTED                      0
+  #define ETL_CPP14_SUPPORTED                      0
+#endif
+#define ETL_NO_NULLPTR_SUPPORT                     !ETL_CPP11_SUPPORTED
+#define ETL_NO_LARGE_CHAR_SUPPORT                  !ETL_CPP11_SUPPORTED
+#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED
+#define ETL_ATOMIC_SUPPORTED                       ETL_CPP11_SUPPORTED
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/msvc_x86.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,51 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_MSVC__
+#define __ETL_MSVC__
+
+//*****************************************************************************
+// Microsoft Visual Studio
+//*****************************************************************************
+
+#include <limits.h>
+
+#define ETL_TARGET_DEVICE_X86
+#define ETL_TARGET_OS_WINDOWS
+#define ETL_COMPILER_MICROSOFT
+#define ETL_CPP11_SUPPORTED                        (_MSC_VER >= 1600)
+#define ETL_CPP14_SUPPORTED                        (_MSC_VER >= 1900)
+#define ETL_NO_NULLPTR_SUPPORT                     !ETL_CPP11_SUPPORTED
+#define ETL_NO_LARGE_CHAR_SUPPORT                  !ETL_CPP11_SUPPORTED
+#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED
+#define ETL_ATOMIC_SUPPORTED                       ETL_CPP11_SUPPORTED
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/ticc.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,51 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_TICC__
+#define __ETL_TICC__
+
+//*****************************************************************************
+// Texas Instruments Code Composer
+//*****************************************************************************
+
+#include <limits.h>
+
+#define ETL_TARGET_DEVICE_GENERIC
+#define ETL_TARGET_OS_NONE
+#define ETL_COMPILER_TI
+#define ETL_CPP11_SUPPORTED 0
+#define ETL_CPP14_SUPPORTED 0
+#define ETL_NO_NULLPTR_SUPPORT    1
+#define ETL_NO_LARGE_CHAR_SUPPORT 1
+#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0
+#define ETL_ATOMIC_SUPPORTED 0
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/queue.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,523 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, Mark Kitson
+
+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 __ETL_QUEUE__
+#define __ETL_QUEUE__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "platform.h"
+#include "container.h"
+#include "alignment.h"
+#include "array.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "debug_count.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+
+#undef ETL_FILE
+#define ETL_FILE "13"
+
+//*****************************************************************************
+///\defgroup queue queue
+/// A First-in / first-out queue with the capacity defined at compile time,
+/// written in the STL style.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for queue exceptions.
+  ///\ingroup queue
+  //***************************************************************************
+  class queue_exception : public exception
+  {
+  public:
+
+    queue_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The exception thrown when the queue is full.
+  ///\ingroup queue
+  //***************************************************************************
+  class queue_full : public queue_exception
+  {
+  public:
+
+    queue_full(string_type file_name_, numeric_type line_number_)
+      : queue_exception(ETL_ERROR_TEXT("queue:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The exception thrown when the queue is empty.
+  ///\ingroup queue
+  //***************************************************************************
+  class queue_empty : public queue_exception
+  {
+  public:
+
+    queue_empty(string_type file_name_, numeric_type line_number_)
+      : queue_exception(ETL_ERROR_TEXT("queue:empty", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for all queues.
+  ///\ingroup queue
+  //***************************************************************************
+  class queue_base
+  {
+  public:
+
+    typedef size_t size_type; ///< The type used for determining the size of queue.
+
+    //*************************************************************************
+    /// Returns the current number of items in the queue.
+    //*************************************************************************
+    size_type size() const
+    {
+      return current_size;
+    }
+
+    //*************************************************************************
+    /// Returns the maximum number of items that can be queued.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Checks to see if the queue is empty.
+    /// \return <b>true</b> if the queue is empty, otherwise <b>false</b>
+    //*************************************************************************
+    bool empty() const
+    {
+      return current_size == 0;
+    }
+
+    //*************************************************************************
+    /// Checks to see if the queue is full.
+    /// \return <b>true</b> if the queue is full, otherwise <b>false</b>
+    //*************************************************************************
+    bool full() const
+    {
+      return current_size == CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return max_size() - size();
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// The constructor that is called from derived classes.
+    //*************************************************************************
+    queue_base(size_type max_size_)
+      : in(0),
+        out(0),
+        current_size(0),
+        CAPACITY(max_size_)
+    {
+    }
+
+    //*************************************************************************
+    /// Increments (and wraps) the 'in' index value to record a queue addition.
+    //*************************************************************************
+    void add_in()
+    {
+      if (++in == CAPACITY)
+      {
+        in = 0;
+      }
+
+      ++current_size;
+      ++construct_count;
+    }
+
+    //*************************************************************************
+    /// Decrements (and wraps) the 'out' index value to record a queue deletion.
+    //*************************************************************************
+    void del_out()
+    {
+      if (++out == CAPACITY)
+      {
+        out = 0;
+      }
+      --current_size;
+      --construct_count;
+    }
+
+    size_type in;                     ///< Where to input new data.
+    size_type out;                    ///< Where to get the oldest data.
+    size_type current_size;           ///< The number of items in the queue.
+    const size_type CAPACITY;         ///< The maximum number of items in the queue.
+    etl::debug_count construct_count; ///< For internal debugging purposes.
+  };
+
+  //***************************************************************************
+  ///\ingroup queue
+  ///\brief This is the base for all queues that contain a particular type.
+  ///\details Normally a reference to this type will be taken from a derived queue.
+  ///\code
+  /// etl::queue<int, 10> myQueue;
+  /// etl::iqueue<int>& iQueue = myQueue;
+  ///\endcode
+  /// \warning This queue cannot be used for concurrent access from multiple threads.
+  /// \tparam T The type of value that the queue holds.
+  //***************************************************************************
+  template <typename T>
+  class iqueue : public etl::queue_base
+  {
+  public:
+
+    typedef T                     value_type;      ///< The type stored in the queue.
+    typedef T&                    reference;       ///< A reference to the type used in the queue.
+    typedef const T&              const_reference; ///< A const reference to the type used in the queue.
+    typedef T*                    pointer;         ///< A pointer to the type used in the queue.
+    typedef const T*              const_pointer;   ///< A const pointer to the type used in the queue.
+    typedef queue_base::size_type size_type;       ///< The type used for determining the size of the queue.
+
+  private:
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+    typedef typename etl::queue_base              base_t;
+
+  public:
+
+    //*************************************************************************
+    /// Gets a reference to the value at the front of the queue.<br>
+    /// \return A reference to the value at the front of the queue.
+    //*************************************************************************
+    reference front()
+    {
+      return p_buffer[out];
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the value at the front of the queue.<br>
+    /// \return A const reference to the value at the front of the queue.
+    //*************************************************************************
+    const_reference front() const
+    {
+      return p_buffer[out];
+    }
+
+    //*************************************************************************
+    /// Gets a reference to the value at the back of the queue.<br>
+    /// \return A reference to the value at the back of the queue.
+    //*************************************************************************
+    reference back()
+    {
+      return p_buffer[in == 0 ? CAPACITY - 1 : in - 1];
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the value at the back of the queue.<br>
+    /// \return A const reference to the value at the back of the queue.
+    //*************************************************************************
+    const_reference back() const
+    {
+      return p_buffer[in == 0 ? CAPACITY - 1 : in - 1];
+    }
+
+    //*************************************************************************
+    /// Adds a value to the queue.
+    /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
+    ///\param value The value to push to the queue.
+    //*************************************************************************
+    void push(parameter_t value)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(queue_full));
+#endif
+      ::new (&p_buffer[in]) T(value);
+      base_t::add_in();
+    }
+
+    //*************************************************************************
+    /// Allows a possibly more efficient 'push' by moving to the next input value
+    /// and returning a reference to it.
+    /// This may eliminate a copy by allowing direct construction in-place.<br>
+    /// If asserts or exceptions are enabled, throws an etl::queue_full is the queue is already full.
+    /// \return A reference to the position to 'push' to.
+    //*************************************************************************
+    reference push()
+    {
+      const size_type next = in;
+
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(queue_full));
+#endif
+      base_t::add_in();
+
+      return p_buffer[next];
+    }
+
+    //*************************************************************************
+    /// Constructs a value in the queue 'in place'.
+    /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
+    ///\param value The value to use to construct the item to push to the queue.
+    //*************************************************************************
+    template <typename T1>
+    void emplace(const T1& value1)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(queue_full));
+#endif
+      ::new (&p_buffer[in]) T(value1);
+      base_t::add_in();
+    }
+
+    //*************************************************************************
+    /// Constructs a value in the queue 'in place'.
+    /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
+    ///\param value The value to use to construct the item to push to the queue.
+    //*************************************************************************
+    template <typename T1, typename T2>
+    void emplace(const T1& value1, const T2& value2)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(queue_full));
+#endif
+      ::new (&p_buffer[in]) T(value1, value2);
+      base_t::add_in();
+    }
+
+    //*************************************************************************
+    /// Constructs a value in the queue 'in place'.
+    /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
+    ///\param value The value to use to construct the item to push to the queue.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3>
+    void emplace(const T1& value1, const T2& value2, const T3& value3)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(queue_full));
+#endif
+      ::new (&p_buffer[in]) T(value1, value2, value3);
+      base_t::add_in();
+    }
+
+    //*************************************************************************
+    /// Constructs a value in the queue 'in place'.
+    /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
+    ///\param value The value to use to construct the item to push to the queue.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    void emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(queue_full));
+#endif
+      ::new (&p_buffer[in]) T(value1, value2, value3, value4);
+      base_t::add_in();
+    }
+
+    //*************************************************************************
+    /// Clears the queue to the empty state.
+    //*************************************************************************
+    void clear()
+    {
+      while (current_size > 0)
+      {
+        p_buffer[out].~T();
+        base_t::del_out();
+      }
+
+      in = 0;
+      out = 0;
+    }
+
+    //*************************************************************************
+    /// Removes the oldest value from the back of the queue.
+    /// Does nothing if the queue is already empty.
+    /// If asserts or exceptions are enabled, throws an etl::queue_empty if the queue is empty.
+    //*************************************************************************
+    void pop()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(queue_empty));
+#endif
+      p_buffer[out].~T();
+      base_t::del_out();
+    }
+
+    //*************************************************************************
+    /// Gets the oldest value and removes it from the front of the queue.
+    /// If asserts or exceptions are enabled, throws an etl::queue_empty if the queue is empty.
+    //*************************************************************************
+    void pop_into(reference destination)
+    {
+      destination = front();
+      pop();
+    }
+
+    //*************************************************************************
+    /// Gets the oldest value and removes it from the front of the queue and
+    /// pushes it to the destination container.
+    /// If asserts or exceptions are enabled, throws an etl::queue_empty if the queue is empty.
+    /// NOTE: The destination must support a push(T) member function.
+    //*************************************************************************
+    template <typename TContainer>
+    void pop_into(TContainer& destination)
+    {
+      destination.push(front());
+      pop();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    iqueue& operator = (const iqueue& rhs)
+    {
+      if (&rhs != this)
+      {
+        clear();
+        clone(rhs);
+      }
+
+      return *this;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Make this a clone of the supplied queue
+    //*************************************************************************
+    void clone(const iqueue& other)
+    {
+      clear();
+
+      size_t index = other.out;
+
+      for (size_t i = 0; i < other.size(); ++i)
+      {
+        push(other.p_buffer[index]);
+        index = (index == (CAPACITY - 1)) ? 0 : index + 1;
+      }
+    }
+
+    //*************************************************************************
+    /// The constructor that is called from derived classes.
+    //*************************************************************************
+    iqueue(T* p_buffer_, size_type max_size_)
+      : queue_base(max_size_),
+        p_buffer(p_buffer_)
+    {
+    }
+
+  private:
+
+    // Disable copy construction.
+    iqueue(const iqueue&);
+
+    T* p_buffer; ///< The internal buffer.
+  };
+
+  //***************************************************************************
+  ///\ingroup queue
+  /// A fixed capacity queue.
+  /// This queue does not support concurrent access by different threads.
+  /// \tparam T    The type this queue should support.
+  /// \tparam SIZE The maximum capacity of the queue.
+  //***************************************************************************
+  template <typename T, const size_t SIZE>
+  class queue : public etl::iqueue<T>
+  {
+  public:
+
+    static const size_t MAX_SIZE = SIZE;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    queue()
+      : etl::iqueue<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor
+    //*************************************************************************
+    queue(const queue& rhs)
+      : etl::iqueue<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
+    {
+      etl::iqueue<T>::clone(rhs);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~queue()
+    {
+      etl::iqueue<T>::clear();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    queue& operator = (const queue& rhs)
+    {
+      if (&rhs != this)
+      {
+        etl::iqueue<T>::clone(rhs);
+      }
+
+      return *this;
+    }
+
+  private:
+
+    /// The uninitialised buffer of T used in the stack.
+    typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[SIZE];
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/radix.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,68 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_RADIX__
+#define __ETL_RADIX__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "enum_type.h"
+
+///\defgroup radix radix
+/// Radix constants for binary, octal, decimal and hex.
+///\ingroup etl
+
+namespace etl
+{
+  /// \ingroup radix
+  struct radix
+  {
+    enum enum_type
+    {
+      undefined = 0,
+      binary    = 2,
+      octal     = 8,
+      decimal   = 10,
+      hex       = 16
+    };
+
+    ETL_DECLARE_ENUM_TYPE(radix, uint_least8_t)
+    ETL_ENUM_TYPE(undefined, "undefined")
+    ETL_ENUM_TYPE(binary,    "binary")
+    ETL_ENUM_TYPE(octal,     "octal")
+    ETL_ENUM_TYPE(decimal,   "decimal")
+    ETL_ENUM_TYPE(hex,       "hex")
+    ETL_END_ENUM_TYPE
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/random.cpp	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,353 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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.
+******************************************************************************/
+
+#include "platform.h"
+#include "random.h"
+
+namespace etl
+{
+  //***************************************************************************
+  // XOR Shift
+  //***************************************************************************
+
+  //***************************************************************************
+  /// Default constructor.
+  /// Attempts to come up with a unique non-zero seed.
+  //***************************************************************************
+  random_xorshift::random_xorshift()
+  {
+    // An attempt to come up with a unique non-zero seed,
+    // based on the address of the instance.
+    uintptr_t n    = reinterpret_cast<uintptr_t>(this);
+    uint32_t  seed = static_cast<uint32_t>(n);
+    initialise(seed);
+  }
+
+  //***************************************************************************
+  /// Constructor with seed value.
+  ///\param seed The new seed value.
+  //***************************************************************************
+  random_xorshift::random_xorshift(uint32_t seed)
+  {
+    initialise(seed);
+  }
+
+  //***************************************************************************
+  /// Initialises the sequence with a new seed value.
+  ///\param seed The new seed value.
+  //***************************************************************************
+  void random_xorshift::initialise(uint32_t seed)
+  {
+    // Add the first four primes to ensure that the seed isn't zero.
+    state[0] = seed + 3;
+    state[1] = seed + 5;
+    state[2] = seed + 7;
+    state[3] = seed + 11;
+  }
+
+  //***************************************************************************
+  /// Get the next random_xorshift number.
+  //***************************************************************************
+  uint32_t random_xorshift::operator()()
+  {
+    uint32_t n = state[3];
+    n ^= n << 11;
+    n ^= n >> 8;
+    state[3] = state[2];
+    state[2] = state[1];
+    state[1] = state[0];
+    n ^= state[0];
+    n ^= state[0] >> 19;
+    state[0] = n;
+
+    return n;
+  }
+
+  //***************************************************************************
+  /// Get the next random_xorshift number in a specified inclusive range.
+  //***************************************************************************
+  uint32_t random_xorshift::range(uint32_t low, uint32_t high)
+  {
+    uint32_t r = high - low + 1;
+    uint32_t n = operator()();
+    n %= r;
+    n += low;
+
+    return n;
+  }
+
+  //***************************************************************************
+  // Linear Congruential Generator
+  //***************************************************************************
+
+  //***************************************************************************
+  /// Default constructor.
+  /// Attempts to come up with a unique non-zero seed.
+  //***************************************************************************
+  random_lcg::random_lcg()
+  {
+    // An attempt to come up with a unique non-zero seed,
+    // based on the address of the instance.
+    uintptr_t n    = reinterpret_cast<uintptr_t>(this);
+    uint32_t  seed = static_cast<uint32_t>(n);
+    initialise(seed);
+  }
+
+  //***************************************************************************
+  /// Constructor with seed value.
+  ///\param seed The new seed value.
+  //***************************************************************************
+  random_lcg::random_lcg(uint32_t seed)
+  {
+    initialise(seed);
+  }
+
+  //***************************************************************************
+  /// Initialises the sequence with a new seed value.
+  ///\param seed The new seed value.
+  //***************************************************************************
+  void random_lcg::initialise(uint32_t seed)
+  {
+    seed = (seed == 0) ? 1 : seed;
+    value = (seed > m) ? m : seed;
+  }
+
+  //***************************************************************************
+  /// Get the next random_clcg number.
+  //***************************************************************************
+  uint32_t random_lcg::operator()()
+  {
+    value = (a * value) % m;
+
+    return value;
+  }
+
+  //***************************************************************************
+  /// Get the next random_clcg number in a specified inclusive range.
+  //***************************************************************************
+  uint32_t random_lcg::range(uint32_t low, uint32_t high)
+  {
+    uint32_t r = high - low + 1;
+    uint32_t n = operator()();
+    n %= r;
+    n += low;
+
+    return n;
+  }
+
+  //***************************************************************************
+  // Combined Linear Congruential Generator
+  //***************************************************************************
+
+  //***************************************************************************
+  /// Default constructor.
+  /// Attempts to come up with a unique non-zero seed.
+  //***************************************************************************
+  random_clcg::random_clcg()
+  {
+    // An attempt to come up with a unique non-zero seed,
+    // based on the address of the instance.
+    uintptr_t n = reinterpret_cast<uintptr_t>(this);
+    uint32_t  seed = static_cast<uint32_t>(n);
+    initialise(seed);
+  }
+
+  //***************************************************************************
+  /// Constructor with seed value.
+  ///\param seed The new seed value.
+  //***************************************************************************
+  random_clcg::random_clcg(uint32_t seed)
+  {
+    initialise(seed);
+  }
+
+  //***************************************************************************
+  /// Initialises the sequence with a new seed value.
+  ///\param seed The new seed value.
+  //***************************************************************************
+  void random_clcg::initialise(uint32_t seed)
+  {
+    seed = (seed == 0) ? 1 : seed;
+    value1 = (seed > m1) ? m1 : seed;
+    value2 = (seed > m1) ? m1 : seed;
+  }
+
+  //***************************************************************************
+  /// Get the next random_clcg number.
+  //***************************************************************************
+  uint32_t random_clcg::operator()()
+  {
+    static const uint32_t m = ((m1 > m2) ? m1 : m2);
+
+    value1 = (a1 * value1) % m1;
+    value2 = (a2 * value2) % m2;
+
+    return (value1 + value2) % m;
+  }
+
+  //***************************************************************************
+  /// Get the next random_clcg number in a specified inclusive range.
+  //***************************************************************************
+  uint32_t random_clcg::range(uint32_t low, uint32_t high)
+  {
+    uint32_t r = high - low + 1;
+    uint32_t n = operator()();
+    n %= r;
+    n += low;
+
+    return n;
+  }
+
+  //***************************************************************************
+  // Linear Shift Feedback Register
+  //***************************************************************************
+
+  //***************************************************************************
+  /// Default constructor.
+  /// Attempts to come up with a unique non-zero seed.
+  //***************************************************************************
+  random_lsfr::random_lsfr()
+  {
+    // An attempt to come up with a unique non-zero seed,
+    // based on the address of the instance.
+    uintptr_t n    = reinterpret_cast<uintptr_t>(this);
+    uint32_t  seed = static_cast<uint32_t>(n);
+    initialise(seed);
+  }
+
+  //***************************************************************************
+  /// Constructor with seed value.
+  ///\param seed The new seed value.
+  //***************************************************************************
+  random_lsfr::random_lsfr(uint32_t seed)
+  {
+    initialise(seed);
+  }
+
+  //***************************************************************************
+  /// Initialises the sequence with a new seed value.
+  ///\param seed The new seed value.
+  //***************************************************************************
+  void random_lsfr::initialise(uint32_t seed)
+  {
+    value = seed;
+  }
+
+  //***************************************************************************
+  /// Get the next random_lsfr number.
+  //***************************************************************************
+  uint32_t random_lsfr::operator()()
+  {
+    static const uint32_t polynomial = 0x80200003;
+
+    value >>= 1;
+
+    if ((value & 1) == 1)
+    {
+      value ^= polynomial;
+    }
+
+    return value;
+  }
+
+  //***************************************************************************
+  /// Get the next random_lsfr number in a specified inclusive range.
+  //***************************************************************************
+  uint32_t random_lsfr::range(uint32_t low, uint32_t high)
+  {
+    uint32_t r = high - low + 1;
+    uint32_t n = operator()();
+    n %= r;
+    n += low;
+
+    return n;
+  }
+
+  //***************************************************************************
+  // Multiply with carry random number generator.
+  //***************************************************************************
+
+  //***************************************************************************
+  /// Default constructor.
+  /// Attempts to come up with a unique non-zero seed.
+  //***************************************************************************
+  random_mwc::random_mwc()
+  {
+    // An attempt to come up with a unique non-zero seed,
+    // based on the address of the instance.
+    uintptr_t n = reinterpret_cast<uintptr_t>(this);
+    uint32_t  seed = static_cast<uint32_t>(n);
+    initialise(seed);
+  }
+
+  //***************************************************************************
+  /// Constructor with seed value.
+  ///\param seed The new seed value.
+  //***************************************************************************
+  random_mwc::random_mwc(uint32_t seed)
+  {
+    initialise(seed);
+  }
+
+  //***************************************************************************
+  /// Initialises the sequence with a new seed value.
+  ///\param seed The new seed value.
+  //***************************************************************************
+  void random_mwc::initialise(uint32_t seed)
+  {
+    value1 = seed;
+    value2 = seed;
+  }
+
+  //***************************************************************************
+  /// Get the next random_lsfr number.
+  //***************************************************************************
+  uint32_t random_mwc::operator()()
+  {
+    value1 = 36969 * (value1 & 0xFFFF) + (value1 >> 16);
+    value2 = 18000 * (value2 & 0xFFFF) + (value2 >> 16);
+
+    return (value1 << 16) + value2;
+  }
+
+  //***************************************************************************
+  /// Get the next random_lsfr number in a specified inclusive range.
+  //***************************************************************************
+  uint32_t random_mwc::range(uint32_t low, uint32_t high)
+  {
+    uint32_t r = high - low + 1;
+    uint32_t n = operator()();
+    n %= r;
+    n += low;
+
+    return n;
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/random.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,168 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_RANDOM__
+#define __ETL_RANDOM__
+
+#include <stdint.h>
+
+#include "platform.h"
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base for all 32 bit random number generators.
+  //***************************************************************************
+  class random
+  {
+  public:
+
+    virtual ~random()
+    {
+    }
+
+    virtual void initialise(uint32_t seed) = 0;
+    virtual uint32_t operator()() = 0;
+    virtual uint32_t range(uint32_t low, uint32_t high) = 0;
+  };
+
+  //***************************************************************************
+  /// A 32 bit random number generator.
+  /// Uses a 128 bit XOR shift algorithm.
+  /// https://en.wikipedia.org/wiki/Xorshift
+  //***************************************************************************
+  class random_xorshift : public random
+  {
+    public:
+
+      random_xorshift();
+      explicit random_xorshift(uint32_t seed);
+      void initialise(uint32_t seed);
+      uint32_t operator()();
+      uint32_t range(uint32_t low, uint32_t high);
+
+    private:
+
+      uint32_t state[4];
+  };
+
+  //***************************************************************************
+  /// A 32 bit random number generator.
+  /// Uses a linear congruential generator.
+  /// https://cs.adelaide.edu.au/~paulc/teaching/montecarlo/node107.html
+  //***************************************************************************
+  class random_lcg : public random
+  {
+  public:
+
+    random_lcg();
+    explicit random_lcg(uint32_t seed);
+    void initialise(uint32_t seed);
+    uint32_t operator()();
+    uint32_t range(uint32_t low, uint32_t high);
+
+  private:
+
+    static const uint32_t a = 40014;
+    static const uint32_t m = 2147483563;
+
+    uint32_t value;
+  };
+
+  //***************************************************************************
+  /// A 32 bit random number generator.
+  /// Uses a combined linear congruential generator.
+  /// https://cs.adelaide.edu.au/~paulc/teaching/montecarlo/node107.html
+  //***************************************************************************
+  class random_clcg : public random
+  {
+    public:
+
+      random_clcg();
+      explicit random_clcg(uint32_t seed);
+      void initialise(uint32_t seed);
+      uint32_t operator()();
+      uint32_t range(uint32_t low, uint32_t high);
+
+    private:
+
+      static const uint32_t a1 = 40014;
+      static const uint32_t m1 = 2147483563;
+
+      static const uint32_t a2 = 40692;
+      static const uint32_t m2 = 2147483399;
+
+      uint32_t value1;
+      uint32_t value2;
+  };
+
+  //***************************************************************************
+  /// A 32 bit random number generator.
+  /// Uses a linear shift feedback register.
+  /// https://en.wikipedia.org/wiki/Linear-feedback_shift_register
+  //***************************************************************************
+  class random_lsfr : public random
+  {
+    public:
+
+      random_lsfr();
+      explicit random_lsfr(uint32_t seed);
+      void initialise(uint32_t seed);
+      uint32_t operator()();
+      uint32_t range(uint32_t low, uint32_t high);
+
+    private:
+
+      uint32_t value;
+  };
+
+  //***************************************************************************
+  /// A 32 bit random number generator.
+  /// Uses a multiply with carry calculation.
+  //***************************************************************************
+  class random_mwc : public random
+  {
+  public:
+
+    random_mwc();
+    explicit random_mwc(uint32_t seed);
+    void initialise(uint32_t seed);
+    uint32_t operator()();
+    uint32_t range(uint32_t low, uint32_t high);
+
+  private:
+
+    uint32_t value1;
+    uint32_t value2;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ratio.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,95 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_RATIO__
+#define __ETL_RATIO__
+
+#include <stdint.h>
+
+///\defgroup ratio ratio
+///\ingroup utilities
+
+namespace etl
+{
+  template <const size_t NUM, const size_t DEN = 1>
+  struct ratio
+  {
+    static const std::intmax_t num = NUM;
+    static const std::intmax_t den = DEN;
+  };
+
+  #if INT_MAX > INT32_MAX
+    typedef ratio<1, 1000000000000000000000000> yocto;
+    typedef ratio<1, 1000000000000000000000>    zepto;
+    typedef ratio<1, 1000000000000000000>       atto
+    typedef ratio<1, 1000000000000000>          femto
+    typedef ratio<1, 1000000000000>             pico;
+  #endif
+
+  #if (INT_MAX >= INT32_MAX)
+    typedef ratio<1, 1000000000>                nano;
+    typedef ratio<1, 1000000>                   micro;
+  #endif
+
+  #if (INT_MAX >= INT16_MAX)
+    typedef ratio<1, 1000>                      milli;
+    typedef ratio<1, 100>                       centi;
+    typedef ratio<1, 10>                        deci;
+    typedef ratio<10, 1>                        deca;
+    typedef ratio<100, 1>                       hecto
+    typedef ratio<1000, 1>                      kilo
+  #endif
+
+  #if (INT_MAX >= INT32_MAX)
+    typedef ratio<1000000, 1>                   mega;
+    typedef ratio<1000000000, 1>                giga;
+  #endif
+
+  #if INT_MAX > INT32_MAX
+    typedef ratio<1000000000000, 1>             tera;
+    typedef ratio<1000000000000000, 1>          peta;
+    typedef ratio<1000000000000000000, 1>       exa;
+    typedef ratio<1000000000000000000000, 1>    zetta;
+    typedef ratio<1000000000000000000000000, 1> yotta;
+  #endif
+
+  /// An approximation of PI to 6 digits.
+  typedef ratio<355, 113> ratio_pi;
+
+  /// An approximation of root 2.
+  typedef ratio<239, 169> ratio_root2;
+
+  /// An approximation of e.
+  typedef ratio<326, 120> ratio_e;
+}
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reference_flat_map.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,957 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_REFERENCE_FLAT_MAP__
+#define __ETL_REFERENCE_FLAT_MAP__
+
+#include <stddef.h>
+
+#include "platform.h"
+#include "vector.h"
+#include "error_handler.h"
+#include "debug_count.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "exception.h"
+#include "static_assert.h"
+
+#undef ETL_FILE
+#define ETL_FILE "30"
+
+//*****************************************************************************
+///\defgroup reference_flat_map reference_flat_map
+/// An reference_flat_map with the capacity defined at compile time.
+/// Has insertion of O(N) and search of O(logN)
+/// Duplicate entries are not allowed.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  ///\ingroup reference_flat_map
+  /// Exception base for reference_flat_maps
+  //***************************************************************************
+  class flat_map_exception : public etl::exception
+  {
+  public:
+
+    flat_map_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup reference_flat_map
+  /// Vector full exception.
+  //***************************************************************************
+  class flat_map_full : public etl::flat_map_exception
+  {
+  public:
+
+    flat_map_full(string_type file_name_, numeric_type line_number_)
+      : flat_map_exception(ETL_ERROR_TEXT("flat_map: full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup reference_flat_map
+  /// Vector out of bounds exception.
+  //***************************************************************************
+  class flat_map_out_of_bounds : public etl::flat_map_exception
+  {
+  public:
+
+    flat_map_out_of_bounds(string_type file_name_, numeric_type line_number_)
+      : flat_map_exception(ETL_ERROR_TEXT("flat_map:bounds", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for specifically sized reference_flat_maps.
+  /// Can be used as a reference type for all reference_flat_maps containing a specific type.
+  ///\ingroup reference_flat_map
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare = std::less<TKey> >
+  class ireference_flat_map
+  {
+  public:
+
+    typedef std::pair<const TKey, TMapped> value_type;
+
+  protected:
+
+    typedef etl::ivector<value_type*> lookup_t;
+
+  public:
+
+    typedef TKey              key_type;
+    typedef TMapped           mapped_type;
+    typedef TKeyCompare       key_compare;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef size_t            size_type;
+
+    //*************************************************************************
+    class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+    {
+    public:
+
+      friend class ireference_flat_map;
+
+      iterator()
+      {
+      }
+
+      iterator(typename lookup_t::iterator ilookup_)
+        : ilookup(ilookup_)
+      {
+      }
+
+      iterator(const iterator& other)
+        : ilookup(other.ilookup)
+      {
+      }
+
+      iterator& operator =(const iterator& other)
+      {
+        ilookup = other.ilookup;
+        return *this;
+      }
+
+      iterator& operator ++()
+      {
+        ++ilookup;
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        ++ilookup;
+        return temp;
+      }
+
+      iterator& operator --()
+      {
+        --ilookup;
+        return *this;
+      }
+
+      iterator operator --(int)
+      {
+        iterator temp(*this);
+        --ilookup;
+        return temp;
+      }
+
+      reference operator *()
+      {
+        return *(*ilookup);
+      }
+
+      const_reference operator *() const
+      {
+        return *(*ilookup);
+      }
+
+      pointer operator &()
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      const_pointer operator &() const
+      {
+        return &(*(*ilookup));
+      }
+
+      pointer operator ->()
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      const_pointer operator ->() const
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.ilookup == rhs.ilookup;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      typename lookup_t::iterator ilookup;
+    };
+
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+    {
+    public:
+
+      friend class ireference_flat_map;
+
+      const_iterator()
+      {
+      }
+
+      const_iterator(typename lookup_t::const_iterator ilookup_)
+        : ilookup(ilookup_)
+      {
+      }
+
+      const_iterator(const iterator& other)
+        : ilookup(other.ilookup)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : ilookup(other.ilookup)
+      {
+      }
+
+      const_iterator& operator =(const iterator& other)
+      {
+        ilookup = other.ilookup;
+        return *this;
+      }
+
+      const_iterator& operator =(const const_iterator& other)
+      {
+        ilookup = other.ilookup;
+        return *this;
+      }
+
+      const_iterator& operator ++()
+      {
+        ++ilookup;
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        ++ilookup;
+        return temp;
+      }
+
+      const_iterator& operator --()
+      {
+        --ilookup;
+        return *this;
+      }
+
+      const_iterator operator --(int)
+      {
+        const_iterator temp(*this);
+        --ilookup;
+        return temp;
+      }
+
+      const_reference operator *() const
+      {
+        return *(*ilookup);
+      }
+
+      const_pointer operator &() const
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      const_pointer operator ->() const
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.ilookup == rhs.ilookup;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      typename lookup_t::const_iterator ilookup;
+    };
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+  protected:
+
+    typedef typename etl::parameter_type<TKey>::type key_parameter_t;
+
+  private:
+
+    //*********************************************************************
+    /// How to compare elements and keys.
+    //*********************************************************************
+    class compare
+    {
+    public:
+
+      bool operator ()(const value_type& element, key_type key) const
+      {
+        return key_compare()(element.first, key);
+      }
+
+      bool operator ()(key_type key, const value_type& element) const
+      {
+        return key_compare()(key, element.first);
+      }
+    };
+
+  public:
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the reference_flat_map.
+    ///\return An iterator to the beginning of the reference_flat_map.
+    //*********************************************************************
+    iterator begin()
+    {
+      return iterator(lookup.begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the reference_flat_map.
+    ///\return A const iterator to the beginning of the reference_flat_map.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(lookup.begin());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the reference_flat_map.
+    ///\return An iterator to the end of the reference_flat_map.
+    //*********************************************************************
+    iterator end()
+    {
+      return iterator(lookup.end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the reference_flat_map.
+    ///\return A const iterator to the end of the reference_flat_map.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(lookup.end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the reference_flat_map.
+    ///\return A const iterator to the beginning of the reference_flat_map.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(lookup.cbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the reference_flat_map.
+    ///\return A const iterator to the end of the reference_flat_map.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(lookup.cend());
+    }
+
+    //*********************************************************************
+    /// Returns an reverse iterator to the reverse beginning of the reference_flat_map.
+    ///\return Iterator to the reverse beginning of the reference_flat_map.
+    //*********************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(lookup.rbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the reference_flat_map.
+    ///\return Const iterator to the reverse beginning of the reference_flat_map.
+    //*********************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return reverse_iterator(lookup.rbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a reverse iterator to the end + 1 of the reference_flat_map.
+    ///\return Reverse iterator to the end + 1 of the reference_flat_map.
+    //*********************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(lookup.rend());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the reference_flat_map.
+    ///\return Const reverse iterator to the end + 1 of the reference_flat_map.
+    //*********************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(lookup.rend());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the reference_flat_map.
+    ///\return Const reverse iterator to the reverse beginning of the reference_flat_map.
+    //*********************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(lookup.crbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the reference_flat_map.
+    ///\return Const reverse iterator to the end + 1 of the reference_flat_map.
+    //*********************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(lookup.crend());
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'key'
+    ///\param i The index.
+    ///\return A reference to the value at index 'key'
+    //*********************************************************************
+    mapped_type& operator [](key_parameter_t key)
+    {
+      iterator i_element = lower_bound(key);
+
+      ETL_ASSERT(i_element != end(), ETL_ERROR(flat_map_out_of_bounds));
+
+      return i_element->second;
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'key'
+    ///\param i The index.
+    ///\return A const reference to the value at index 'key'
+    //*********************************************************************
+    const mapped_type& operator [](key_parameter_t key) const
+    {
+      iterator i_element = lower_bound(key);
+
+      ETL_ASSERT(i_element != end(), ETL_ERROR(flat_map_out_of_bounds));
+
+      return i_element->second;
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'key'
+    /// If asserts or exceptions are enabled, emits an etl::flat_map_out_of_bounds if the key is not in the range.
+    ///\param i The index.
+    ///\return A reference to the value at index 'key'
+    //*********************************************************************
+    mapped_type& at(key_parameter_t key)
+    {
+      iterator i_element = lower_bound(key);
+
+      ETL_ASSERT(i_element != end(), ETL_ERROR(flat_map_out_of_bounds));
+
+      return i_element->second;
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'key'
+    /// If asserts or exceptions are enabled, emits an etl::flat_map_out_of_bounds if the key is not in the range.
+    ///\param i The index.
+    ///\return A const reference to the value at index 'key'
+    //*********************************************************************
+    const mapped_type& at(key_parameter_t key) const
+    {
+      const_iterator i_element = lower_bound(key);
+
+      ETL_ASSERT(i_element != end(), ETL_ERROR(flat_map_out_of_bounds));
+
+      return i_element->second;
+    }
+
+    //*********************************************************************
+    /// Assigns values to the reference_flat_map.
+    /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined, emits flat_map_full if the reference_flat_map does not have enough free space.
+    /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined, emits flat_map_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+      STATIC_ASSERT((etl::is_same<value_type, typename std::iterator_traits<TIterator>::value_type>::value), "Incompatible data for assign");
+
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_map_full));
+#endif
+
+      clear();
+
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the reference_flat_map.
+    /// If asserts or exceptions are enabled, emits flat_map_full if the reference_flat_map is already full.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(reference value)
+    {
+      iterator i_element = lower_bound(value.first);
+
+      return insert_at(i_element, value);
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the reference_flat_map.
+    /// If asserts or exceptions are enabled, emits flat_map_full if the reference_flat_map is already full.
+    ///\param position The position to insert at.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator position, reference value)
+    {
+      return insert(value).first;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the reference_flat_map.
+    /// If asserts or exceptions are enabled, emits flat_map_full if the reference_flat_map does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param key The key to erase.
+    ///\return The number of elements erased. 0 or 1.
+    //*********************************************************************
+    size_t erase(key_parameter_t key)
+    {
+      iterator i_element = find(key);
+
+      if (i_element == end())
+      {
+        return 0;
+      }
+      else
+      {
+        lookup.erase(i_element.ilookup);
+        return 1;
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param i_element Iterator to the element.
+    //*********************************************************************
+    void erase(iterator i_element)
+    {
+      lookup.erase(i_element.ilookup);
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    //*********************************************************************
+    void erase(iterator first, iterator last)
+    {
+      lookup.erase(first.ilookup, last.ilookup);
+    }
+
+    //*************************************************************************
+    /// Clears the reference_flat_map.
+    //*************************************************************************
+    void clear()
+    {
+      erase(begin(), end());
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    iterator find(key_parameter_t key)
+    {
+      iterator itr = lower_bound(key);
+
+      if (itr != end())
+      {
+        if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first))
+        {
+          return itr;
+        }
+        else
+        {
+          return end();
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    const_iterator find(key_parameter_t key) const
+    {
+      const_iterator itr = lower_bound(key);
+
+      if (itr != end())
+      {
+        if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first))
+        {
+          return itr;
+        }
+        else
+        {
+          return end();
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Counts an element.
+    ///\param key The key to search for.
+    ///\return 1 if the key exists, otherwise 0.
+    //*********************************************************************
+    size_t count(key_parameter_t key) const
+    {
+      return (find(key) == end()) ? 0 : 1;
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator lower_bound(key_parameter_t key)
+    {
+      return std::lower_bound(begin(), end(), key, compare());
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator lower_bound(key_parameter_t key) const
+    {
+      return std::lower_bound(cbegin(), cend(), key, compare());
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator upper_bound(key_parameter_t key)
+    {
+      return std::upper_bound(begin(), end(), key, compare());
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator upper_bound(key_parameter_t key) const
+    {
+      return std::upper_bound(begin(), end(), key, compare());
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<iterator, iterator> equal_range(key_parameter_t key)
+    {
+      iterator i_lower = std::lower_bound(begin(), end(), key, compare());
+
+      return std::make_pair(i_lower, std::upper_bound(i_lower, end(), key, compare()));
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
+    {
+      const_iterator i_lower = std::lower_bound(cbegin(), cend(), key, compare());
+
+      return std::make_pair(i_lower, std::upper_bound(i_lower, cend(), key, compare()));
+    }
+
+    //*************************************************************************
+    /// Gets the current size of the reference_flat_map.
+    ///\return The current size of the reference_flat_map.
+    //*************************************************************************
+    size_type size() const
+    {
+      return lookup.size();
+    }
+
+    //*************************************************************************
+    /// Checks the 'empty' state of the reference_flat_map.
+    ///\return <b>true</b> if empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return lookup.empty();
+    }
+
+    //*************************************************************************
+    /// Checks the 'full' state of the reference_flat_map.
+    ///\return <b>true</b> if full.
+    //*************************************************************************
+    bool full() const
+    {
+      return lookup.full();
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the reference_flat_map.
+    ///\return The capacity of the reference_flat_map.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return lookup.capacity();
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the reference_flat_map.
+    ///\return The maximum size of the reference_flat_map.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return lookup.max_size();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return lookup.available();
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    ireference_flat_map(lookup_t& lookup_)
+      : lookup(lookup_)
+    {
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the reference_flat_map.
+    ///\param i_element The place to insert.
+    ///\param value     The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert_at(iterator i_element, value_type& value)
+    {
+      std::pair<iterator, bool> result(end(), false);
+
+      if (i_element == end())
+      {
+        // At the end.
+        ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_map_full));
+
+        lookup.push_back(&value);
+        result.first = --end();
+        result.second = true;
+      }
+      else
+      {
+        // Not at the end.
+        result.first = i_element;
+
+        // Existing element?
+        if (value.first != i_element->first)
+        {
+          // A new one.
+          ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_map_full));
+          lookup.insert(i_element.ilookup, &value);
+          result.second = true;
+        }
+      }
+
+      return result;
+    }
+
+  private:
+
+    // Disable copy construction and assignment.
+    ireference_flat_map(const ireference_flat_map&);
+    ireference_flat_map& operator = (const ireference_flat_map&);
+
+    lookup_t& lookup;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first reference_flat_map.
+  ///\param rhs Reference to the second reference_flat_map.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup reference_flat_map
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator ==(const etl::ireference_flat_map<TKey, TMapped, TKeyCompare>& lhs, const etl::ireference_flat_map<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first reference_flat_map.
+  ///\param rhs Reference to the second reference_flat_map.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup reference_flat_map
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator !=(const etl::ireference_flat_map<TKey, TMapped, TKeyCompare>& lhs, const etl::ireference_flat_map<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //***************************************************************************
+  /// A reference_flat_map implementation that uses a fixed size buffer.
+  ///\tparam TKey     The key type.
+  ///\tparam TValue   The value type.
+  ///\tparam TCompare The type to compare keys. Default = std::less<TKey>
+  ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+  ///\ingroup reference_flat_map
+  //***************************************************************************
+  template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> >
+  class reference_flat_map : public ireference_flat_map<TKey, TValue, TCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    reference_flat_map()
+      : ireference_flat_map<TKey, TValue, TCompare>(lookup)
+    {
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    reference_flat_map(TIterator first, TIterator last)
+      : ireference_flat_map<TKey, TValue, TCompare>(lookup)
+    {
+      ireference_flat_map<TKey, TValue, TCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~reference_flat_map()
+    {
+      ireference_flat_map<TKey, TValue, TCompare>::clear();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    reference_flat_map& operator = (const reference_flat_map& rhs)
+    {
+      if (&rhs != this)
+      {
+        ireference_flat_map<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    reference_flat_map(const reference_flat_map&);
+
+    typedef typename ireference_flat_map<TKey, TValue, TCompare>::value_type node_t;
+
+    // The vector that stores pointers to the nodes.
+    etl::vector<node_t*, MAX_SIZE> lookup;
+  };
+
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reference_flat_multimap.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,863 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_REFERENCE_FLAT_MULTIMAP_BASE__
+#define __ETL_REFERENCE_FLAT_MULTIMAP_BASE__
+
+#include <stddef.h>
+
+#include "platform.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "debug_count.h"
+#include "vector.h"
+
+#undef ETL_FILE
+#define ETL_FILE "31"
+
+namespace etl
+{
+  //***************************************************************************
+  ///\ingroup reference_flat_multimap
+  /// Exception base for reference_flat_multimaps
+  //***************************************************************************
+  class flat_multimap_exception : public exception
+  {
+  public:
+
+    flat_multimap_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup reference_flat_multimap
+  /// Vector full exception.
+  //***************************************************************************
+  class flat_multimap_full : public flat_multimap_exception
+  {
+  public:
+
+    flat_multimap_full(string_type file_name_, numeric_type line_number_)
+      : flat_multimap_exception(ETL_ERROR_TEXT("flat_multimap:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for specifically sized reference_flat_multimaps.
+  /// Can be used as a reference type for all reference_flat_multimaps containing a specific type.
+  ///\ingroup reference_flat_multimap
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare = std::less<TKey> >
+  class ireference_flat_multimap
+  {
+  public:
+
+    typedef std::pair<const TKey, TMapped> value_type;
+
+  protected:
+
+    typedef etl::ivector<value_type*> lookup_t;
+
+  public:
+
+    typedef TKey              key_type;
+    typedef TMapped           mapped_type;
+    typedef TKeyCompare       key_compare;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef size_t            size_type;
+
+    //*************************************************************************
+    class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+    {
+    public:
+
+      friend class ireference_flat_multimap;
+
+      iterator()
+      {
+      }
+
+      iterator(typename lookup_t::iterator ilookup_)
+        : ilookup(ilookup_)
+      {
+      }
+
+      iterator(const iterator& other)
+        : ilookup(other.ilookup)
+      {
+      }
+
+      iterator& operator =(const iterator& other)
+      {
+        ilookup = other.ilookup;
+        return *this;
+      }
+
+      iterator& operator ++()
+      {
+        ++ilookup;
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        ++ilookup;
+        return temp;
+      }
+
+      iterator& operator --()
+      {
+        --ilookup;
+        return *this;
+      }
+
+      iterator operator --(int)
+      {
+        iterator temp(*this);
+        --ilookup;
+        return temp;
+      }
+
+      reference operator *()
+      {
+        return *(*ilookup);
+      }
+
+      const_reference operator *() const
+      {
+        return *(*ilookup);
+      }
+
+      pointer operator &()
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      const_pointer operator &() const
+      {
+        return &(*(*ilookup));
+      }
+
+      pointer operator ->()
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      const_pointer operator ->() const
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.ilookup == rhs.ilookup;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      typename lookup_t::iterator ilookup;
+    };
+
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+    {
+    public:
+
+      friend class ireference_flat_multimap;
+
+      const_iterator()
+      {
+      }
+
+      const_iterator(typename lookup_t::const_iterator ilookup_)
+        : ilookup(ilookup_)
+      {
+      }
+
+      const_iterator(const iterator& other)
+        : ilookup(other.ilookup)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : ilookup(other.ilookup)
+      {
+      }
+
+      const_iterator& operator =(const iterator& other)
+      {
+        ilookup = other.ilookup;
+        return *this;
+      }
+
+      const_iterator& operator =(const const_iterator& other)
+      {
+        ilookup = other.ilookup;
+        return *this;
+      }
+
+      const_iterator& operator ++()
+      {
+        ++ilookup;
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        ++ilookup;
+        return temp;
+      }
+
+      const_iterator& operator --()
+      {
+        --ilookup;
+        return *this;
+      }
+
+      const_iterator operator --(int)
+      {
+        const_iterator temp(*this);
+        --ilookup;
+        return temp;
+      }
+
+      const_reference operator *() const
+      {
+        return *(*ilookup);
+      }
+
+      const_pointer operator &() const
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      const_pointer operator ->() const
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.ilookup == rhs.ilookup;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      typename lookup_t::const_iterator ilookup;
+    };
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+  protected:
+
+    typedef typename etl::parameter_type<TKey>::type key_parameter_t;
+
+  private:
+
+    //*********************************************************************
+    /// How to compare elements and keys.
+    //*********************************************************************
+    class compare
+    {
+    public:
+
+      bool operator ()(const value_type& element, key_type key) const
+      {
+        return key_compare()(element.first, key);
+      }
+
+      bool operator ()(key_type key, const value_type& element) const
+      {
+        return key_compare()(key, element.first);
+      }
+    };
+
+  public:
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the reference_flat_multimap.
+    ///\return An iterator to the beginning of the reference_flat_multimap.
+    //*********************************************************************
+    iterator begin()
+    {
+      return iterator(lookup.begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the reference_flat_multimap.
+    ///\return A const iterator to the beginning of the reference_flat_multimap.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(lookup.begin());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the reference_flat_multimap.
+    ///\return An iterator to the end of the reference_flat_multimap.
+    //*********************************************************************
+    iterator end()
+    {
+      return iterator(lookup.end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the reference_flat_multimap.
+    ///\return A const iterator to the end of the reference_flat_multimap.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(lookup.end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the reference_flat_multimap.
+    ///\return A const iterator to the beginning of the reference_flat_multimap.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(lookup.cbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the reference_flat_multimap.
+    ///\return A const iterator to the end of the reference_flat_multimap.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(lookup.cend());
+    }
+
+    //*********************************************************************
+    /// Returns an reverse iterator to the reverse beginning of the reference_flat_multimap.
+    ///\return Iterator to the reverse beginning of the reference_flat_multimap.
+    //*********************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(lookup.rbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the reference_flat_multimap.
+    ///\return Const iterator to the reverse beginning of the reference_flat_multimap.
+    //*********************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(lookup.rbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a reverse iterator to the end + 1 of the reference_flat_multimap.
+    ///\return Reverse iterator to the end + 1 of the reference_flat_multimap.
+    //*********************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(lookup.rend());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the reference_flat_multimap.
+    ///\return Const reverse iterator to the end + 1 of the reference_flat_multimap.
+    //*********************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(lookup.rend());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the reference_flat_multimap.
+    ///\return Const reverse iterator to the reverse beginning of the reference_flat_multimap.
+    //*********************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(lookup.crbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the reference_flat_multimap.
+    ///\return Const reverse iterator to the end + 1 of the reference_flat_multimap.
+    //*********************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(lookup.crend());
+    }
+
+    //*********************************************************************
+    /// Assigns values to the reference_flat_multimap.
+    /// If asserts or exceptions are enabled, emits reference_flat_multimap_full if the reference_flat_multimap does not have enough free space.
+    /// If asserts or exceptions are enabled, emits reference_flat_multimap_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_multimap_full));
+#endif
+
+      clear();
+
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the reference_flat_multimap.
+    /// If asserts or exceptions are enabled, emits reference_flat_multimap_full if the reference_flat_multimap is already full.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(value_type& value)
+    {
+      ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_multimap_full));
+
+      std::pair<iterator, bool> result(end(), false);
+
+      iterator i_element = lower_bound(value.first);
+
+      return insert_at(i_element, value);
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the flast_multi.
+    /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map is already full.
+    ///\param position The position to insert at.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator position, const value_type& value)
+    {
+      return insert(value).first;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the reference_flat_multimap.
+    /// If asserts or exceptions are enabled, emits reference_flat_multimap_full if the reference_flat_multimap does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param key The key to erase.
+    ///\return The number of elements erased. 0 or 1.
+    //*********************************************************************
+    size_t erase(key_parameter_t key)
+    {
+      std::pair<iterator, iterator> range = equal_range(key);
+
+      if (range.first == end())
+      {
+        return 0;
+      }
+      else
+      {
+        size_t d = std::distance(range.first, range.second);
+        erase(range.first, range.second);
+        return d;
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param i_element Iterator to the element.
+    //*********************************************************************
+    void erase(iterator i_element)
+    {
+      lookup.erase(i_element.ilookup);
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    //*********************************************************************
+    void erase(iterator first, iterator last)
+    {
+      lookup.erase(first.ilookup, last.ilookup);
+    }
+
+    //*************************************************************************
+    /// Clears the reference_flat_multimap.
+    //*************************************************************************
+    void clear()
+    {
+      erase(begin(), end());
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    iterator find(key_parameter_t key)
+    {
+      iterator itr = lower_bound(key);
+
+      if (itr != end())
+      {
+        if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first))
+        {
+          return itr;
+        }
+        else
+        {
+          return end();
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    const_iterator find(key_parameter_t key) const
+    {
+      const_iterator itr = lower_bound(key);
+
+      if (itr != end())
+      {
+        if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first))
+        {
+          return itr;
+        }
+        else
+        {
+          return end();
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Counts an element.
+    ///\param key The key to search for.
+    ///\return 1 if the key exists, otherwise 0.
+    //*********************************************************************
+    size_t count(key_parameter_t key) const
+    {
+      std::pair<const_iterator, const_iterator> range = equal_range(key);
+
+      return std::distance(range.first, range.second);
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator lower_bound(key_parameter_t key)
+    {
+      return std::lower_bound(begin(), end(), key, compare());
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator lower_bound(key_parameter_t key) const
+    {
+      return std::lower_bound(cbegin(), cend(), key, compare());
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator upper_bound(key_parameter_t key)
+    {
+      return std::upper_bound(begin(), end(), key, compare());
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator upper_bound(key_parameter_t key) const
+    {
+      return std::upper_bound(begin(), end(), key, compare());
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<iterator, iterator> equal_range(key_parameter_t key)
+    {
+      iterator i_lower = std::lower_bound(begin(), end(), key, compare());
+
+      return std::make_pair(i_lower, std::upper_bound(i_lower, end(), key, compare()));
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
+    {
+      const_iterator i_lower = std::lower_bound(cbegin(), cend(), key, compare());
+
+      return std::make_pair(i_lower, std::upper_bound(i_lower, cend(), key, compare()));
+    }
+
+    //*************************************************************************
+    /// Gets the current size of the flat_multiset.
+    ///\return The current size of the flat_multiset.
+    //*************************************************************************
+    size_type size() const
+    {
+      return lookup.size();
+    }
+
+    //*************************************************************************
+    /// Checks the 'empty' state of the flat_multiset.
+    ///\return <b>true</b> if empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return lookup.empty();
+    }
+
+    //*************************************************************************
+    /// Checks the 'full' state of the flat_multiset.
+    ///\return <b>true</b> if full.
+    //*************************************************************************
+    bool full() const
+    {
+      return lookup.full();
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the flat_multiset.
+    ///\return The capacity of the flat_multiset.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return lookup.capacity();
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the flat_multiset.
+    ///\return The maximum size of the flat_multiset.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return lookup.max_size();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return lookup.available();
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    ireference_flat_multimap(lookup_t& lookup_)
+      : lookup(lookup_)
+    {
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the reference_flat_multimap.
+    ///\param i_element The place to insert.
+    ///\param value     The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert_at(iterator i_element, value_type& value)
+    {
+      std::pair<iterator, bool> result(end(), false);
+
+      if (i_element == end())
+      {
+        // At the end.
+        lookup.push_back(&value);
+        result.first = --end();
+        result.second = true;
+      }
+      else
+      {
+        // Not at the end.
+        lookup.insert(i_element.ilookup, &value);
+        result.first = i_element;
+        result.second = true;
+      }
+
+      return result;
+    }
+
+  private:
+
+    // Disable copy construction and assignment.
+    ireference_flat_multimap(const ireference_flat_multimap&);
+    ireference_flat_multimap& operator = (const ireference_flat_multimap&);
+
+    lookup_t&  lookup;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first reference_flat_multimap.
+  ///\param rhs Reference to the second reference_flat_multimap.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup reference_flat_multimap
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator ==(const etl::ireference_flat_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::ireference_flat_multimap<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first reference_flat_multimap.
+  ///\param rhs Reference to the second reference_flat_multimap.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup reference_flat_multimap
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator !=(const etl::ireference_flat_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::ireference_flat_multimap<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> >
+  //***************************************************************************
+  /// A reference_flat_multimap implementation that uses a fixed size buffer.
+  ///\tparam TKey     The key type.
+  ///\tparam TValue   The value type.
+  ///\tparam TCompare The type to compare keys. Default = std::less<TKey>
+  ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+  ///\ingroup reference_flat_multimap
+  //***************************************************************************
+  class reference_flat_multimap : public ireference_flat_multimap<TKey, TValue, TCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    reference_flat_multimap()
+      : ireference_flat_multimap<TKey, TValue, TCompare>(lookup)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    reference_flat_multimap(const reference_flat_multimap& other)
+      : ireference_flat_multimap<TKey, TValue, TCompare>(lookup)
+    {
+      ireference_flat_multimap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    reference_flat_multimap(TIterator first, TIterator last)
+      : ireference_flat_multimap<TKey, TValue, TCompare>(lookup)
+    {
+      ireference_flat_multimap<TKey, TValue, TCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~reference_flat_multimap()
+    {
+      ireference_flat_multimap<TKey, TValue, TCompare>::clear();
+    }
+
+  private:
+
+    typedef typename ireference_flat_multimap<TKey, TValue, TCompare>::value_type node_t;
+
+    // The vector that stores pointers to the nodes.
+    etl::vector<node_t*, MAX_SIZE> lookup;
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reference_flat_multiset.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,871 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_REFERENCE_FLAT_MULTISET__
+#define __ETL_REFERENCE_FLAT_MULTISET__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <stddef.h>
+
+#include "platform.h"
+#include "type_traits.h"
+#include "vector.h"
+#include "pool.h"
+#include "error_handler.h"
+#include "exception.h"
+
+#undef ETL_FILE
+#define ETL_FILE "33"
+
+namespace etl
+{
+  //***************************************************************************
+  ///\ingroup reference_flat_multiset
+  /// Exception base for reference_flat_multisets
+  //***************************************************************************
+  class flat_multiset_exception : public exception
+  {
+  public:
+
+    flat_multiset_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup reference_flat_multiset
+  /// Vector full exception.
+  //***************************************************************************
+  class flat_multiset_full : public flat_multiset_exception
+  {
+  public:
+
+    flat_multiset_full(string_type file_name_, numeric_type line_number_)
+      : flat_multiset_exception(ETL_ERROR_TEXT("flat_multiset:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup reference_flat_multiset
+  /// Vector iterator exception.
+  //***************************************************************************
+  class flat_multiset_iterator : public flat_multiset_exception
+  {
+  public:
+
+    flat_multiset_iterator(string_type file_name_, numeric_type line_number_)
+      : flat_multiset_exception(ETL_ERROR_TEXT("flat_multiset:iterator", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for specifically sized reference_flat_multisets.
+  /// Can be used as a reference type for all reference_flat_multisets containing a specific type.
+  ///\ingroup reference_flat_multiset
+  //***************************************************************************
+  template <typename T, typename TKeyCompare = std::less<T> >
+  class ireference_flat_multiset
+  {
+  public:
+
+    typedef T                 key_type;
+    typedef T                 value_type;
+    typedef TKeyCompare       key_compare;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef size_t            size_type;
+
+  protected:
+
+    typedef etl::ivector<value_type*> lookup_t;
+
+  public:
+
+    //*************************************************************************
+    class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+    {
+    public:
+
+      friend class ireference_flat_multiset;
+
+      iterator()
+      {
+      }
+
+      iterator(typename lookup_t::iterator ilookup_)
+        : ilookup(ilookup_)
+      {
+      }
+
+      iterator(const iterator& other)
+        : ilookup(other.ilookup)
+      {
+      }
+
+      iterator& operator =(const iterator& other)
+      {
+        ilookup = other.ilookup;
+        return *this;
+      }
+
+      iterator& operator ++()
+      {
+        ++ilookup;
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        ++ilookup;
+        return temp;
+      }
+
+      iterator& operator --()
+      {
+        --ilookup;
+        return *this;
+      }
+
+      iterator operator --(int)
+      {
+        iterator temp(*this);
+        --ilookup;
+        return temp;
+      }
+
+      reference operator *()
+      {
+        return *(*ilookup);
+      }
+
+      const_reference operator *() const
+      {
+        return *(*ilookup);
+      }
+
+      pointer operator &()
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      const_pointer operator &() const
+      {
+        return &(*(*ilookup));
+      }
+
+      pointer operator ->()
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      const_pointer operator ->() const
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.ilookup == rhs.ilookup;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      typename lookup_t::iterator ilookup;
+    };
+
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+    {
+    public:
+
+      friend class ireference_flat_multiset;
+
+      const_iterator()
+      {
+      }
+
+      const_iterator(typename lookup_t::const_iterator ilookup_)
+        : ilookup(ilookup_)
+      {
+      }
+
+      const_iterator(const iterator& other)
+        : ilookup(other.ilookup)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : ilookup(other.ilookup)
+      {
+      }
+
+      const_iterator& operator =(const iterator& other)
+      {
+        ilookup = other.ilookup;
+        return *this;
+      }
+
+      const_iterator& operator =(const const_iterator& other)
+      {
+        ilookup = other.ilookup;
+        return *this;
+      }
+
+      const_iterator& operator ++()
+      {
+        ++ilookup;
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        ++ilookup;
+        return temp;
+      }
+
+      const_iterator& operator --()
+      {
+        --ilookup;
+        return *this;
+      }
+
+      const_iterator operator --(int)
+      {
+        const_iterator temp(*this);
+        --ilookup;
+        return temp;
+      }
+
+      const_reference operator *() const
+      {
+        return *(*ilookup);
+      }
+
+      const_pointer operator &() const
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      const_pointer operator ->() const
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.ilookup == rhs.ilookup;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      typename lookup_t::const_iterator ilookup;
+    };
+
+  protected:
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+
+  public:
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the reference_flat_multiset.
+    ///\return An iterator to the beginning of the reference_flat_multiset.
+    //*********************************************************************
+    iterator begin()
+    {
+      return iterator(lookup.begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the reference_flat_multiset.
+    ///\return A const iterator to the beginning of the reference_flat_multiset.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(lookup.begin());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the reference_flat_multiset.
+    ///\return An iterator to the end of the reference_flat_multiset.
+    //*********************************************************************
+    iterator end()
+    {
+      return iterator(lookup.end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the reference_flat_multiset.
+    ///\return A const iterator to the end of the reference_flat_multiset.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(lookup.end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the reference_flat_multiset.
+    ///\return A const iterator to the beginning of the reference_flat_multiset.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(lookup.cbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the reference_flat_multiset.
+    ///\return A const iterator to the end of the reference_flat_multiset.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(lookup.cend());
+    }
+
+    //*********************************************************************
+    /// Returns an reverse iterator to the reverse beginning of the reference_flat_multiset.
+    ///\return Iterator to the reverse beginning of the reference_flat_multiset.
+    //*********************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(lookup.rbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the reference_flat_multiset.
+    ///\return Const iterator to the reverse beginning of the reference_flat_multiset.
+    //*********************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(lookup.rbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a reverse iterator to the end + 1 of the reference_flat_multiset.
+    ///\return Reverse iterator to the end + 1 of the reference_flat_multiset.
+    //*********************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(lookup.rend());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the reference_flat_multiset.
+    ///\return Const reverse iterator to the end + 1 of the reference_flat_multiset.
+    //*********************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(lookup.rend());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the reference_flat_multiset.
+    ///\return Const reverse iterator to the reverse beginning of the reference_flat_multiset.
+    //*********************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(lookup.crbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the reference_flat_multiset.
+    ///\return Const reverse iterator to the end + 1 of the reference_flat_multiset.
+    //*********************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(lookup.crend());
+    }
+
+    //*********************************************************************
+    /// Assigns values to the reference_flat_multiset.
+    /// If asserts or exceptions are enabled, emits reference_flat_multiset_full if the reference_flat_multiset does not have enough free space.
+    /// If asserts or exceptions are enabled, emits reference_flat_multiset_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_multiset_full));
+#endif
+
+      clear();
+
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the reference_flat_multiset.
+    /// If asserts or exceptions are enabled, emits reference_flat_multiset_full if the reference_flat_multiset is already full.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(value_type& value)
+    {
+      std::pair<iterator, bool> result(end(), false);
+
+      ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_multiset_full));
+
+      iterator i_element = std::lower_bound(begin(), end(), value, TKeyCompare());
+
+      if (i_element == end())
+      {
+        // At the end. Doesn't exist.
+        lookup.push_back(&value);
+        result.first = --end();
+        result.second = true;
+      }
+      else
+      {
+        // Not at the end.
+        lookup.insert(i_element.ilookup, &value);
+        result.first = i_element;
+        result.second = true;
+      }
+
+      return result;
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the reference_flat_multiset.
+    /// If asserts or exceptions are enabled, emits reference_flat_multiset_full if the reference_flat_multiset is already full.
+    ///\param position The position to insert at.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator position, value_type& value)
+    {
+      return insert(value).first;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the reference_flat_multiset.
+    /// If asserts or exceptions are enabled, emits reference_flat_multiset_full if the reference_flat_multiset does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param key The key to erase.
+    ///\return The number of elements erased. 0 or 1.
+    //*********************************************************************
+    size_t erase(parameter_t key)
+    {
+      std::pair<iterator, iterator> range = equal_range(key);
+
+      if (range.first == end())
+      {
+        return 0;
+      }
+      else
+      {
+        size_t d = std::distance(range.first, range.second);
+        erase(range.first, range.second);
+        return d;
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param i_element Iterator to the element.
+    //*********************************************************************
+    void erase(iterator i_element)
+    {
+      lookup.erase(i_element.ilookup);
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    //*********************************************************************
+    void erase(iterator first, iterator last)
+    {
+      lookup.erase(first.ilookup, last.ilookup);;
+    }
+
+    //*************************************************************************
+    /// Clears the reference_flat_multiset.
+    //*************************************************************************
+    void clear()
+    {
+      erase(begin(), end());
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    iterator find(parameter_t key)
+    {
+      iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare());
+
+      if (itr != end())
+      {
+        if (!key_compare()(*itr, key) && !key_compare()(key, *itr))
+        {
+          return itr;
+        }
+        else
+        {
+          return end();
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    const_iterator find(parameter_t key) const
+    {
+      const_iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare());
+
+      if (itr != end())
+      {
+        if (!key_compare()(*itr, key) && !key_compare()(key, *itr))
+        {
+          return itr;
+        }
+        else
+        {
+          return end();
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Counts an element.
+    ///\param key The key to search for.
+    ///\return 1 if the key exists, otherwise 0.
+    //*********************************************************************
+    size_t count(parameter_t key) const
+    {
+      std::pair<const_iterator, const_iterator> range = equal_range(key);
+
+      return std::distance(range.first, range.second);
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator lower_bound(parameter_t key)
+    {
+      return std::lower_bound(begin(), end(), key, TKeyCompare());
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator lower_bound(parameter_t key) const
+    {
+      return std::lower_bound(cbegin(), cend(), key, TKeyCompare());
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator upper_bound(parameter_t key)
+    {
+      return std::upper_bound(begin(), end(), key, TKeyCompare());
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator upper_bound(parameter_t key) const
+    {
+      return std::upper_bound(cbegin(), cend(), key, TKeyCompare());
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<iterator, iterator> equal_range(parameter_t key)
+    {
+      return std::equal_range(begin(), end(), key, TKeyCompare());
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(parameter_t key) const
+    {
+      return std::equal_range(begin(), end(), key, TKeyCompare());
+    }
+
+    //*************************************************************************
+    /// Gets the current size of the reference_flat_multiset.
+    ///\return The current size of the reference_flat_multiset.
+    //*************************************************************************
+    size_type size() const
+    {
+      return lookup.size();
+    }
+
+    //*************************************************************************
+    /// Checks the 'empty' state of the reference_flat_multiset.
+    ///\return <b>true</b> if empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return lookup.empty();
+    }
+
+    //*************************************************************************
+    /// Checks the 'full' state of the reference_flat_multiset.
+    ///\return <b>true</b> if full.
+    //*************************************************************************
+    bool full() const
+    {
+      return lookup.full();
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the reference_flat_multiset.
+    ///\return The capacity of the reference_flat_multiset.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return lookup.capacity();
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the reference_flat_multiset.
+    ///\return The maximum size of the reference_flat_multiset.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return lookup.max_size();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return lookup.available();
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    ireference_flat_multiset(lookup_t& lookup_)
+      : lookup(lookup_)
+    {
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the reference_flat_set.
+    ///\param i_element The place to insert.
+    ///\param value     The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert_at(iterator i_element, reference value)
+    {
+      std::pair<iterator, bool> result(end(), false);
+
+      if (i_element == end())
+      {
+        // At the end.
+        ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_multiset_full));
+
+        lookup.push_back(&value);
+        result.first = --end();
+        result.second = true;
+      }
+      else
+      {
+        // Not at the end.
+        result.first = i_element;
+
+        // A new one.
+        ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_multiset_full));
+        lookup.insert(i_element.ilookup, &value);
+        result.second = true;
+      }
+
+      return result;
+    }
+
+  private:
+
+    // Disable copy construction.
+    ireference_flat_multiset(const ireference_flat_multiset&);
+    ireference_flat_multiset& operator =(const ireference_flat_multiset&);
+
+    lookup_t& lookup;
+  };
+
+  //***************************************************************************
+  /// An reference flat set
+  ///\ingroup reference_flat_multiset
+  //***************************************************************************
+  template <typename TKey, const size_t MAX_SIZE_, typename TKeyCompare = std::less<TKey> >
+  class reference_flat_multiset : public ireference_flat_multiset<TKey, TKeyCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    reference_flat_multiset()
+      : ireference_flat_multiset<TKey, TKeyCompare>(lookup)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    reference_flat_multiset(const reference_flat_multiset& other)
+      : ireference_flat_multiset<TKey, TKeyCompare>(lookup)
+    {
+      ireference_flat_multiset<TKey, TKeyCompare>::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    reference_flat_multiset(TIterator first, TIterator last)
+      : ireference_flat_multiset<TKey, TKeyCompare>(lookup)
+    {
+      ireference_flat_multiset<TKey, TKeyCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~reference_flat_multiset()
+    {
+      ireference_flat_multiset<TKey, TKeyCompare>::clear();
+    }
+
+  private:
+
+    typedef TKey value_type;
+
+    // The vector that stores pointers to the nodes.
+    etl::vector<value_type*, MAX_SIZE> lookup;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first reference_flat_multiset.
+  ///\param rhs Reference to the second reference_flat_multiset.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup reference_flat_multiset
+  //***************************************************************************
+  template <typename T, typename TKeyCompare>
+  bool operator ==(const etl::ireference_flat_multiset<T, TKeyCompare>& lhs, const etl::ireference_flat_multiset<T, TKeyCompare>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first reference_flat_multiset.
+  ///\param rhs Reference to the second reference_flat_multiset.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup reference_flat_multiset
+  //***************************************************************************
+  template <typename T, typename TKeyCompare>
+  bool operator !=(const etl::ireference_flat_multiset<T, TKeyCompare>& lhs, const etl::ireference_flat_multiset<T, TKeyCompare>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+}
+
+#undef ETL_FILE
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reference_flat_set.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,853 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_REFERENCE_FLAT_SET__
+#define __ETL_REFERENCE_FLAT_SET__
+
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <stddef.h>
+
+#include "platform.h"
+#include "type_traits.h"
+#include "pool.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "vector.h"
+
+#undef ETL_FILE
+#define ETL_FILE "32"
+
+namespace etl
+{
+  //***************************************************************************
+  ///\ingroup reference_flat_set
+  /// Exception base for flat_sets
+  //***************************************************************************
+  class flat_set_exception : public exception
+  {
+  public:
+
+    flat_set_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup reference_flat_set
+  /// Vector full exception.
+  //***************************************************************************
+  class flat_set_full : public flat_set_exception
+  {
+  public:
+
+    flat_set_full(string_type file_name_, numeric_type line_number_)
+      : flat_set_exception(ETL_ERROR_TEXT("flat_set:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup reference_flat_set
+  /// Vector iterator exception.
+  //***************************************************************************
+  class flat_set_iterator : public flat_set_exception
+  {
+  public:
+
+    flat_set_iterator(string_type file_name_, numeric_type line_number_)
+      : flat_set_exception(ETL_ERROR_TEXT("flat_set:iterator", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for specifically sized reference_flat_sets.
+  /// Can be used as a reference type for all reference_flat_sets containing a specific type.
+  ///\ingroup reference_flat_set
+  //***************************************************************************
+  template <typename T, typename TKeyCompare = std::less<T> >
+  class ireference_flat_set
+  {
+  public:
+
+    typedef T                 key_type;
+    typedef T                 value_type;
+    typedef TKeyCompare       key_compare;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef size_t            size_type;
+
+  protected:
+
+    typedef etl::ivector<value_type*> lookup_t;
+
+  public:
+
+    //*************************************************************************
+    class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+    {
+    public:
+
+      friend class ireference_flat_set;
+
+      iterator()
+      {
+      }
+
+      iterator(typename lookup_t::iterator ilookup_)
+        : ilookup(ilookup_)
+      {
+      }
+
+      iterator(const iterator& other)
+        : ilookup(other.ilookup)
+      {
+      }
+
+      iterator& operator =(const iterator& other)
+      {
+        ilookup = other.ilookup;
+        return *this;
+      }
+
+      iterator& operator ++()
+      {
+        ++ilookup;
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        ++ilookup;
+        return temp;
+      }
+
+      iterator& operator --()
+      {
+        --ilookup;
+        return *this;
+      }
+
+      iterator operator --(int)
+      {
+        iterator temp(*this);
+        --ilookup;
+        return temp;
+      }
+
+      reference operator *()
+      {
+        return *(*ilookup);
+      }
+
+      const_reference operator *() const
+      {
+        return *(*ilookup);
+      }
+
+      pointer operator &()
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      const_pointer operator &() const
+      {
+        return &(*(*ilookup));
+      }
+
+      pointer operator ->()
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      const_pointer operator ->() const
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.ilookup == rhs.ilookup;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      typename lookup_t::iterator ilookup;
+    };
+
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+    {
+    public:
+
+      friend class ireference_flat_set;
+
+      const_iterator()
+      {
+      }
+
+      const_iterator(typename lookup_t::const_iterator ilookup_)
+        : ilookup(ilookup_)
+      {
+      }
+
+      const_iterator(const iterator& other)
+        : ilookup(other.ilookup)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : ilookup(other.ilookup)
+      {
+      }
+
+      const_iterator& operator =(const iterator& other)
+      {
+        ilookup = other.ilookup;
+        return *this;
+      }
+
+      const_iterator& operator =(const const_iterator& other)
+      {
+        ilookup = other.ilookup;
+        return *this;
+      }
+
+      const_iterator& operator ++()
+      {
+        ++ilookup;
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        ++ilookup;
+        return temp;
+      }
+
+      const_iterator& operator --()
+      {
+        --ilookup;
+        return *this;
+      }
+
+      const_iterator operator --(int)
+      {
+        const_iterator temp(*this);
+        --ilookup;
+        return temp;
+      }
+
+      const_reference operator *() const
+      {
+        return *(*ilookup);
+      }
+
+      const_pointer operator &() const
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      const_pointer operator ->() const
+      {
+        return etl::addressof(*(*ilookup));
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.ilookup == rhs.ilookup;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      typename lookup_t::const_iterator ilookup;
+    };
+
+  protected:
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+
+  public:
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the reference_flat_set.
+    ///\return An iterator to the beginning of the reference_flat_set.
+    //*********************************************************************
+    iterator begin()
+    {
+      return iterator(lookup.begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the reference_flat_set.
+    ///\return A const iterator to the beginning of the reference_flat_set.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(lookup.begin());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the reference_flat_set.
+    ///\return An iterator to the end of the reference_flat_set.
+    //*********************************************************************
+    iterator end()
+    {
+      return iterator(lookup.end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the reference_flat_set.
+    ///\return A const iterator to the end of the reference_flat_set.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(lookup.end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the reference_flat_set.
+    ///\return A const iterator to the beginning of the reference_flat_set.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(lookup.cbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the reference_flat_set.
+    ///\return A const iterator to the end of the reference_flat_set.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(lookup.cend());
+    }
+
+    //*********************************************************************
+    /// Returns an reverse iterator to the reverse beginning of the reference_flat_set.
+    ///\return Iterator to the reverse beginning of the reference_flat_set.
+    //*********************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(lookup.rbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the reference_flat_set.
+    ///\return Const iterator to the reverse beginning of the reference_flat_set.
+    //*********************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(lookup.rbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a reverse iterator to the end + 1 of the reference_flat_set.
+    ///\return Reverse iterator to the end + 1 of the reference_flat_set.
+    //*********************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(lookup.rend());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the reference_flat_set.
+    ///\return Const reverse iterator to the end + 1 of the reference_flat_set.
+    //*********************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(lookup.rend());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the reference_flat_set.
+    ///\return Const reverse iterator to the reverse beginning of the reference_flat_set.
+    //*********************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(lookup.crbegin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the reference_flat_set.
+    ///\return Const reverse iterator to the end + 1 of the reference_flat_set.
+    //*********************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(lookup.crend());
+    }
+
+    //*********************************************************************
+    /// Assigns values to the reference_flat_set.
+    /// If asserts or exceptions are enabled, emits reference_flat_set_full if the reference_flat_set does not have enough free space.
+    /// If asserts or exceptions are enabled, emits reference_flat_set_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_set_full));
+#endif
+
+      clear();
+
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the reference_flat_set.
+    /// If asserts or exceptions are enabled, emits reference_flat_set_full if the reference_flat_set is already full.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(reference value)
+    {
+      iterator i_element = lower_bound(value);
+
+      return insert_at(i_element, value);
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the reference_flat_set.
+    /// If asserts or exceptions are enabled, emits reference_flat_set_full if the reference_flat_set is already full.
+    ///\param position The position to insert at.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator position, reference value)
+    {
+      return insert(value).first;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the reference_flat_set.
+    /// If asserts or exceptions are enabled, emits reference_flat_set_full if the reference_flat_set does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param key The key to erase.
+    ///\return The number of elements erased. 0 or 1.
+    //*********************************************************************
+    size_t erase(parameter_t key)
+    {
+      iterator i_element = find(key);
+
+      if (i_element == end())
+      {
+        return 0;
+      }
+      else
+      {
+        lookup.erase(i_element.ilookup);
+        return 1;
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param i_element Iterator to the element.
+    //*********************************************************************
+    void erase(iterator i_element)
+    {
+      lookup.erase(i_element.ilookup);
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    //*********************************************************************
+    void erase(iterator first, iterator last)
+    {
+      lookup.erase(first.ilookup, last.ilookup);;
+    }
+
+    //*************************************************************************
+    /// Clears the reference_flat_set.
+    //*************************************************************************
+    void clear()
+    {
+      erase(begin(), end());
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    iterator find(parameter_t key)
+    {
+      iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare());
+
+      if (itr != end())
+      {
+        if (!key_compare()(*itr, key) && !key_compare()(key, *itr))
+        {
+          return itr;
+        }
+        else
+        {
+          return end();
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    const_iterator find(parameter_t key) const
+    {
+      const_iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare());
+
+      if (itr != end())
+      {
+        if (!key_compare()(*itr, key) && !key_compare()(key, *itr))
+        {
+          return itr;
+        }
+        else
+        {
+          return end();
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Counts an element.
+    ///\param key The key to search for.
+    ///\return 1 if the key exists, otherwise 0.
+    //*********************************************************************
+    size_t count(parameter_t key) const
+    {
+      return (find(key) == end()) ? 0 : 1;
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator lower_bound(parameter_t key)
+    {
+      return std::lower_bound(begin(), end(), key, TKeyCompare());
+    }
+
+    //*********************************************************************
+    /// Finds the lower bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator lower_bound(parameter_t key) const
+    {
+      return std::lower_bound(cbegin(), cend(), key, TKeyCompare());
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    iterator upper_bound(parameter_t key)
+    {
+      return std::upper_bound(begin(), end(), key, TKeyCompare());
+    }
+
+    //*********************************************************************
+    /// Finds the upper bound of a key
+    ///\param key The key to search for.
+    ///\return An iterator.
+    //*********************************************************************
+    const_iterator upper_bound(parameter_t key) const
+    {
+      return std::upper_bound(cbegin(), cend(), key, TKeyCompare());
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<iterator, iterator> equal_range(parameter_t key)
+    {
+      return std::equal_range(begin(), end(), key, TKeyCompare());
+    }
+
+    //*********************************************************************
+    /// Finds the range of equal elements of a key
+    ///\param key The key to search for.
+    ///\return An iterator pair.
+    //*********************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(parameter_t key) const
+    {
+      return std::upper_bound(cbegin(), cend(), key, TKeyCompare());
+    }
+
+    //*************************************************************************
+    /// Gets the current size of the reference_flat_set.
+    ///\return The current size of the reference_flat_set.
+    //*************************************************************************
+    size_type size() const
+    {
+      return lookup.size();
+    }
+
+    //*************************************************************************
+    /// Checks the 'empty' state of the reference_flat_set.
+    ///\return <b>true</b> if empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return lookup.empty();
+    }
+
+    //*************************************************************************
+    /// Checks the 'full' state of the reference_flat_set.
+    ///\return <b>true</b> if full.
+    //*************************************************************************
+    bool full() const
+    {
+      return lookup.full();
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the reference_flat_set.
+    ///\return The capacity of the reference_flat_set.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return lookup.capacity();
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the reference_flat_set.
+    ///\return The maximum size of the reference_flat_set.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return lookup.max_size();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return lookup.available();
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    ireference_flat_set(lookup_t& lookup_)
+      : lookup(lookup_)
+    {
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the reference_flat_set.
+    ///\param i_element The place to insert.
+    ///\param value     The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert_at(iterator i_element, reference value)
+    {
+      std::pair<iterator, bool> result(end(), false);
+
+      if (i_element == end())
+      {
+        // At the end.
+        ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_set_full));
+
+        lookup.push_back(&value);
+        result.first = --end();
+        result.second = true;
+      }
+      else
+      {
+        // Not at the end.
+        result.first = i_element;
+
+        // Existing element?
+        if (value != *i_element)
+        {
+          // A new one.
+          ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_set_full));
+          lookup.insert(i_element.ilookup, &value);
+          result.second = true;
+        }
+      }
+
+      return result;
+    }
+
+  private:
+
+    // Disable copy construction.
+    ireference_flat_set(const ireference_flat_set&);
+    ireference_flat_set& operator =(const ireference_flat_set&);
+
+    lookup_t& lookup;
+  };
+
+  //***************************************************************************
+  /// An reference flat set
+  ///\ingroup reference_flat_set
+  //***************************************************************************
+  template <typename TKey, const size_t MAX_SIZE_, typename TKeyCompare = std::less<TKey> >
+  class reference_flat_set : public ireference_flat_set<TKey, TKeyCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    reference_flat_set()
+      : ireference_flat_set<TKey, TKeyCompare>(lookup)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    reference_flat_set(const reference_flat_set& other)
+      : ireference_flat_set<TKey, TKeyCompare>(lookup)
+    {
+      ireference_flat_set<TKey, TKeyCompare>::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    reference_flat_set(TIterator first, TIterator last)
+      : ireference_flat_set<TKey, TKeyCompare>(lookup)
+    {
+      ireference_flat_set<TKey, TKeyCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~reference_flat_set()
+    {
+      ireference_flat_set<TKey, TKeyCompare>::clear();
+    }
+
+  private:
+
+    typedef TKey value_type;
+
+    // The vector that stores pointers to the nodes.
+    etl::vector<value_type*, MAX_SIZE> lookup;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first reference_flat_set.
+  ///\param rhs Reference to the second reference_flat_set.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup reference_flat_set
+  //***************************************************************************
+  template <typename T, typename TKeyCompare>
+  bool operator ==(const etl::ireference_flat_set<T, TKeyCompare>& lhs, const etl::ireference_flat_set<T, TKeyCompare>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first reference_flat_set.
+  ///\param rhs Reference to the second reference_flat_set.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup reference_flat_set
+  //***************************************************************************
+  template <typename T, typename TKeyCompare>
+  bool operator !=(const etl::ireference_flat_set<T, TKeyCompare>& lhs, const etl::ireference_flat_set<T, TKeyCompare>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+}
+
+#undef ETL_FILE
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scheduler.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,412 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_SCHEDULER__
+#define __ETL_SCHEDULER__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "vector.h"
+#include "nullptr.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "task.h"
+#include "type_traits.h"
+#include "function.h"
+
+#undef ETL_FILE
+#define ETL_FILE "36"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Base exception class for scheduler.
+  //***************************************************************************
+  class scheduler_exception : public etl::exception
+  {
+  public:
+
+    scheduler_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// 'No tasks' exception.
+  //***************************************************************************
+  class scheduler_no_tasks_exception : public etl::scheduler_exception
+  {
+  public:
+
+    scheduler_no_tasks_exception(string_type file_name_, numeric_type line_number_)
+      : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:no tasks", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// 'Null tasks' exception.
+  //***************************************************************************
+  class scheduler_null_task_exception : public etl::scheduler_exception
+  {
+  public:
+
+    scheduler_null_task_exception(string_type file_name_, numeric_type line_number_)
+      : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:null task", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// 'Too many tasks' exception.
+  //***************************************************************************
+  class scheduler_too_many_tasks_exception : public etl::scheduler_exception
+  {
+  public:
+
+    scheduler_too_many_tasks_exception(string_type file_name_, numeric_type line_number_)
+      : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:too many tasks", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Sequencial Single.
+  /// A policy the scheduler can use to decide what to do next.
+  /// Only calls the task to process work once, if it has work to do.
+  //***************************************************************************
+  struct scheduler_policy_sequencial_single
+  {
+    bool schedule_tasks(etl::ivector<etl::task*>& task_list)
+    {
+      bool idle = true;
+
+      for (size_t index = 0; index < task_list.size(); ++index)
+      {
+        etl::task& task = *(task_list[index]);
+
+        if (task.task_request_work() > 0)
+        {
+          task.task_process_work();
+          idle = false;
+        }
+      }
+
+      return idle;
+    }
+  };
+
+  //***************************************************************************
+  /// Sequencial Multiple.
+  /// A policy the scheduler can use to decide what to do next.
+  /// Calls the task to process work until it reports that it has no more.
+  //***************************************************************************
+  struct scheduler_policy_sequencial_multiple
+  {
+    bool schedule_tasks(etl::ivector<etl::task*>& task_list)
+    {
+      bool idle = true;
+
+      for (size_t index = 0; index < task_list.size(); ++index)
+      {
+        etl::task& task = *(task_list[index]);
+
+        while (task.task_request_work() > 0)
+        {
+          task.task_process_work();
+          idle = false;
+        }
+      }
+
+      return idle;
+    }
+  };
+
+  //***************************************************************************
+  /// Highest Priority.
+  /// A policy the scheduler can use to decide what to do next.
+  /// Calls the highest priority task that has work.
+  //***************************************************************************
+  struct scheduler_policy_highest_priority
+  {
+    bool schedule_tasks(etl::ivector<etl::task*>& task_list)
+    {
+      bool idle = true;
+
+      size_t index = 0;
+      while (index < task_list.size())
+      {
+        etl::task& task = *(task_list[index]);
+
+        if (task.task_request_work() > 0)
+        {
+          task.task_process_work();
+          idle = false;
+          break;
+        }
+        else
+        {
+          ++index;
+        }
+      }
+
+      return idle;
+    }
+  };
+
+  //***************************************************************************
+  /// Most Work.
+  /// A policy the scheduler can use to decide what to do next.
+  /// Calls the task that has the most work.
+  /// Starts looking from the task with the highest priority.
+  //***************************************************************************
+  struct scheduler_policy_most_work
+  {
+    bool schedule_tasks(etl::ivector<etl::task*>& task_list)
+    {
+      bool idle = true;
+
+      size_t most_index = 0;
+      uint_least8_t most_work = 0;
+
+      for (size_t index = 0; index < task_list.size(); ++index)
+      {
+        etl::task& task = *(task_list[index]);
+
+        uint_least8_t n_work = task.task_request_work();
+
+        if (n_work > most_work)
+        {
+          most_index = index;
+          most_work = n_work;
+          idle = false;
+        }
+      }
+
+      if (!idle)
+      {
+        task_list[most_index]->task_process_work();
+      }
+
+      return idle;
+    }
+  };
+
+  //***************************************************************************
+  /// Scheduler base.
+  //***************************************************************************
+  class ischeduler
+  {
+  public:
+
+    //*******************************************
+    // Virtuals.
+    //*******************************************
+    virtual void start() = 0;
+
+    virtual ~ischeduler()
+    {
+    }
+
+    //*******************************************
+    /// Set the idle callback.
+    //*******************************************
+    void set_idle_callback(etl::ifunction<void>& callback)
+    {
+      p_idle_callback = &callback;
+    }
+
+    //*******************************************
+    /// Set the watchdog callback.
+    //*******************************************
+    void set_watchdog_callback(etl::ifunction<void>& callback)
+    {
+      p_watchdog_callback = &callback;
+    }
+
+    //*******************************************
+    /// Set the running state for the scheduler.
+    //*******************************************
+    void set_scheduler_running(bool scheduler_running_)
+    {
+      scheduler_running = scheduler_running_;
+    }
+
+    //*******************************************
+    /// Get the running state for the scheduler.
+    //*******************************************
+    bool scheduler_is_running() const
+    {
+      return scheduler_running;
+    }
+
+    //*******************************************
+    /// Force the scheduler to exit.
+    //*******************************************
+    void exit_scheduler()
+    {
+      scheduler_exit = true;
+    }
+
+    //*******************************************
+    /// Add a task.
+    /// Add to the task list in priority order.
+    //*******************************************
+    void add_task(etl::task& task)
+    {
+      ETL_ASSERT(!task_list.full(), ETL_ERROR(etl::scheduler_too_many_tasks_exception))
+
+      if (!task_list.full())
+      {
+        typename task_list_t::iterator itask = std::upper_bound(task_list.begin(),
+                                                                task_list.end(),
+                                                                task.get_task_priority(),
+                                                                compare_priority());
+
+        task_list.insert(itask, &task);
+      }
+    }
+
+    //*******************************************
+    /// Add a task list.
+    /// Adds to the tasks to the internal task list in priority order.
+    /// Input order is ignored.
+    //*******************************************
+    template <typename TSize>
+    void add_task_list(etl::task** p_tasks, TSize size)
+    {
+      for (TSize i = 0; i < size; ++i)
+      {
+        ETL_ASSERT((p_tasks[i] != std::nullptr), ETL_ERROR(etl::scheduler_null_task_exception));
+        add_task(*(p_tasks[i]));
+      }
+    }
+
+  protected:
+
+    //*******************************************
+    /// Constructor.
+    //*******************************************
+    ischeduler(etl::ivector<etl::task*>& task_list_)
+      : scheduler_running(false),
+        scheduler_exit(false),
+        p_idle_callback(std::nullptr),
+        p_watchdog_callback(std::nullptr),
+        task_list(task_list_)
+    {
+    }
+
+    bool scheduler_running;
+    bool scheduler_exit;
+    etl::ifunction<void>* p_idle_callback;
+    etl::ifunction<void>* p_watchdog_callback;
+
+  private:
+
+    //*******************************************
+    // Used to order tasks in descending priority.
+    //*******************************************
+    struct compare_priority
+    {
+      bool operator()(etl::task* ptask, etl::task_priority_t priority) const
+      {
+        return ptask->get_task_priority() > priority;
+      }
+
+      bool operator()(etl::task_priority_t priority, etl::task* ptask) const
+      {
+        return priority > ptask->get_task_priority();
+      }
+    };
+
+    typedef etl::ivector<etl::task*> task_list_t;
+    task_list_t& task_list;
+  };
+
+  //***************************************************************************
+  /// Scheduler.
+  //***************************************************************************
+  template <typename TSchedulerPolicy, size_t MAX_TASKS_>
+  class scheduler : public etl::ischeduler, protected TSchedulerPolicy
+  {
+  public:
+
+    enum
+    {
+      MAX_TASKS = MAX_TASKS_,
+    };
+
+    scheduler()
+      : ischeduler(task_list)
+    {
+    }
+
+    //*******************************************
+    /// Start the scheduler. SEQUENCIAL_SINGLE
+    /// Only calls the task to process work once, if it has work to do.
+    //*******************************************
+    void start()
+    {
+      ETL_ASSERT(task_list.size() > 0, ETL_ERROR(etl::scheduler_no_tasks_exception));
+
+      const size_t task_list_size = task_list.size();
+
+      scheduler_running = true;
+
+      while (!scheduler_exit)
+      {
+        if (scheduler_running)
+        {
+          bool idle = TSchedulerPolicy::schedule_tasks(task_list);
+
+          if (p_watchdog_callback)
+          {
+            (*p_watchdog_callback)();
+          }
+
+          if (idle && p_idle_callback)
+          {
+            (*p_idle_callback)();
+          }
+        }
+      }
+    }
+
+  private:
+
+    typedef etl::vector<etl::task*, MAX_TASKS> task_list_t;
+    task_list_t task_list;
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/set.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,2082 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, rlindeman
+
+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 __ETL_SET__
+#define __ETL_SET__
+
+#include <stddef.h>
+#include <iterator>
+#include <algorithm>
+#include <functional>
+
+#include "platform.h"
+#include "container.h"
+#include "pool.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "debug_count.h"
+#include "nullptr.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#endif
+
+#undef ETL_FILE
+#define ETL_FILE "14"
+
+//*****************************************************************************
+///\defgroup set set
+/// A set with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the set.
+  ///\ingroup set
+  //***************************************************************************
+  class set_exception : public etl::exception
+  {
+  public:
+
+    set_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Full exception for the set.
+  ///\ingroup set
+  //***************************************************************************
+  class set_full : public etl::set_exception
+  {
+  public:
+
+    set_full(string_type file_name_, numeric_type line_number_)
+      : etl::set_exception(ETL_ERROR_TEXT("set:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Map out of bounds exception.
+  ///\ingroup set
+  //***************************************************************************
+  class set_out_of_bounds : public etl::set_exception
+  {
+  public:
+
+    set_out_of_bounds(string_type file_name_, numeric_type line_number_)
+      : etl::set_exception(ETL_ERROR_TEXT("set:bounds", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the set.
+  ///\ingroup set
+  //***************************************************************************
+  class set_iterator : public etl::set_exception
+  {
+  public:
+
+    set_iterator(string_type file_name_, numeric_type line_number_)
+      : etl::set_exception(ETL_ERROR_TEXT("set:iterator problem", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for all sets.
+  ///\ingroup set
+  //***************************************************************************
+  class set_base
+  {
+  public:
+
+    typedef size_t size_type; ///< The type used for determining the size of set.
+
+    //*************************************************************************
+    /// Gets the size of the set.
+    //*************************************************************************
+    size_type size() const
+    {
+      return current_size;
+    }
+
+    //*************************************************************************
+    /// Gets the maximum possible size of the set.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Checks to see if the set is empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return current_size == 0;
+    }
+
+    //*************************************************************************
+    /// Checks to see if the set is full.
+    //*************************************************************************
+    bool full() const
+    {
+      return current_size == CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the capacity of the vector.
+    ///\return The capacity of the vector.
+    //*************************************************************************
+    size_type capacity() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return max_size() - size();
+    }
+
+  protected:
+
+    enum
+    {
+      kLeft = 0,
+      kRight = 1,
+      kNeither = 2
+    };
+
+    //*************************************************************************
+    /// The node element in the set.
+    //*************************************************************************
+    struct Node
+    {
+      //***********************************************************************
+      /// Constructor
+      //***********************************************************************
+      Node() :
+        weight(kNeither),
+        dir(kNeither)
+      {
+      }
+
+      //***********************************************************************
+      /// Marks the node as a leaf.
+      //***********************************************************************
+      void mark_as_leaf()
+      {
+        weight = kNeither;
+        dir = kNeither;
+        children[0] =std::nullptr;
+        children[1] =std::nullptr;
+      }
+
+      Node* children[2];
+      uint_least8_t weight;
+      uint_least8_t dir;
+    };
+
+    //*************************************************************************
+    /// The constructor that is called from derived classes.
+    //*************************************************************************
+    set_base(size_type max_size_)
+      : current_size(0)
+      , CAPACITY(max_size_)
+      , root_node(std::nullptr)
+
+    {
+    }
+
+    //*************************************************************************
+    /// Attach the provided node to the position provided
+    //*************************************************************************
+    void attach_node(Node*& position, Node& node)
+    {
+      // Mark new node as leaf on attach to tree at position provided
+      node.mark_as_leaf();
+
+      // Add the node here
+      position = &node;
+
+      // One more.
+      ++current_size;
+    }
+
+    //*************************************************************************
+    /// Detach the node at the position provided
+    //*************************************************************************
+    void detach_node(Node*& position, Node*& replacement)
+    {
+      // Make temporary copy of actual nodes involved because we might lose
+      // their references in the process (e.g. position is the same as
+      // replacement or replacement is a child of position)
+      Node* detached = position;
+      Node* swap = replacement;
+
+      // Update current position to point to swap (replacement) node first
+      position = swap;
+
+      // Update replacement node to point to child in opposite direction
+      // otherwise we might lose the other child of the swap node
+      replacement = swap->children[1 - swap->dir];
+
+      // Point swap node to detached node's children and weight
+      swap->children[kLeft] = detached->children[kLeft];
+      swap->children[kRight] = detached->children[kRight];
+      swap->weight = detached->weight;
+    }
+
+    //*************************************************************************
+    /// Balance the critical node at the position provided as needed
+    //*************************************************************************
+    void balance_node(Node*& critical_node)
+    {
+      // Step 1: Update weights for all children of the critical node up to the
+      // newly inserted node. This step is costly (in terms of traversing nodes
+      // multiple times during insertion) but doesn't require as much recursion
+      Node* weight_node = critical_node->children[critical_node->dir];
+      while (weight_node)
+      {
+        // Keep going until we reach a terminal node (dir == kNeither)
+        if (uint_least8_t(kNeither) != weight_node->dir)
+        {
+          // Does this insert balance the previous weight factor value?
+          if (weight_node->weight == 1 - weight_node->dir)
+          {
+            weight_node->weight = uint_least8_t(kNeither);
+          }
+          else
+          {
+            weight_node->weight = weight_node->dir;
+          }
+
+          // Update weight factor node to point to next node
+          weight_node = weight_node->children[weight_node->dir];
+        }
+        else
+        {
+          // Stop loop, terminal node found
+          break;
+        }
+      } // while(weight_node)
+
+        // Step 2: Update weight for critical_node or rotate tree to balance node
+      if (uint_least8_t(kNeither) == critical_node->weight)
+      {
+        critical_node->weight = critical_node->dir;
+      }
+      // If direction is different than weight, then it will now be balanced
+      else if (critical_node->dir != critical_node->weight)
+      {
+        critical_node->weight = uint_least8_t(kNeither);
+      }
+      // Rotate is required to balance the tree at the critical node
+      else
+      {
+        // If critical node matches child node direction then perform a two
+        // node rotate in the direction of the critical node
+        if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
+        {
+          rotate_2node(critical_node, critical_node->dir);
+        }
+        // Otherwise perform a three node rotation in the direction of the
+        // critical node
+        else
+        {
+          rotate_3node(critical_node, critical_node->dir,
+            critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the node whose key would go before all the other keys from the
+    /// position provided
+    //*************************************************************************
+    Node* find_limit_node(Node* position, const int8_t dir) const
+    {
+      // Something at this position and in the direction specified? keep going
+      Node* limit_node = position;
+      while (limit_node && limit_node->children[dir])
+      {
+        limit_node = limit_node->children[dir];
+      }
+
+      // Return the limit node position found
+      return limit_node;
+    }
+
+    //*************************************************************************
+    /// Find the node whose key would go before all the other keys from the
+    /// position provided
+    //*************************************************************************
+    const Node* find_limit_node(const Node* position, const int8_t dir) const
+    {
+      // Something at this position and in the direction specified? keep going
+      const Node* limit_node = position;
+      while (limit_node && limit_node->children[dir])
+      {
+        limit_node = limit_node->children[dir];
+      }
+
+      // Return the limit node position found
+      return limit_node;
+    }
+
+    //*************************************************************************
+    /// Rotate two nodes at the position provided the to balance the tree
+    //*************************************************************************
+    void rotate_2node(Node*& position, uint_least8_t dir)
+    {
+      //     A            C             A          B
+      //   B   C   ->   A   E   OR    B   C  ->  D   A
+      //      D E      B D           D E            E C
+      // C (new position) becomes the root
+      // A (position) takes ownership of D as its children[kRight] child
+      // C (new position) takes ownership of A as its left child
+      //                 OR
+      // B (new position) becomes the root
+      // A (position) takes ownership of E as its left child
+      // B (new position) takes ownership of A as its right child
+
+      // Capture new root
+      Node* new_root = position->children[dir];
+      // Replace position's previous child with new root's other child
+      position->children[dir] = new_root->children[1 - dir];
+      // New root now becomes parent of current position
+      new_root->children[1 - dir] = position;
+      // Clear weight factor from current position
+      position->weight = uint_least8_t(kNeither);
+      // Newly detached right now becomes current position
+      position = new_root;
+      // Clear weight factor from new root
+      position->weight = uint_least8_t(kNeither);
+    }
+
+    //*************************************************************************
+    /// Rotate three nodes at the position provided the to balance the tree
+    //*************************************************************************
+    void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third)
+    {
+      //        __A__             __E__            __A__             __D__
+      //      _B_    C    ->     B     A    OR    B    _C_   ->     A     C
+      //     D   E              D F   G C             D   E        B F   G E
+      //        F G                                  F G
+      // E (new position) becomes the root
+      // B (position) takes ownership of F as its left child
+      // A takes ownership of G as its right child
+      //                  OR
+      // D (new position) becomes the root
+      // A (position) takes ownership of F as its right child
+      // C takes ownership of G as its left child
+
+      // Capture new root (either E or D depending on dir)
+      Node* new_root = position->children[dir]->children[1 - dir];
+      // Set weight factor for B or C based on F or G existing and being a different than dir
+      position->children[dir]->weight = third != uint_least8_t(kNeither) && third != dir ? dir : uint_least8_t(kNeither);
+
+      // Detach new root from its tree (replace with new roots child)
+      position->children[dir]->children[1 - dir] =
+        new_root->children[dir];
+      // Attach current left tree to new root
+      new_root->children[dir] = position->children[dir];
+      // Set weight factor for A based on F or G
+      position->weight = third != uint_least8_t(kNeither) && third == dir ? 1 - dir : uint_least8_t(kNeither);
+
+      // Move new root's right tree to current roots left tree
+      position->children[dir] = new_root->children[1 - dir];
+      // Attach current root to new roots right tree
+      new_root->children[1 - dir] = position;
+      // Replace current position with new root
+      position = new_root;
+      // Clear weight factor for new current position
+      position->weight = uint_least8_t(kNeither);
+    }
+
+    size_type current_size;   ///< The number of the used nodes.
+    const size_type CAPACITY; ///< The maximum size of the set.
+    Node* root_node;          ///< The node that acts as the set root.
+    etl::debug_count construct_count;
+  };
+
+  //***************************************************************************
+  /// A templated base for all etl::set types.
+  ///\ingroup set
+  //***************************************************************************
+  template <typename T, typename TCompare>
+  class iset : public etl::set_base
+  {
+  public:
+
+    typedef const T     key_type;
+    typedef const T     value_type;
+    typedef TCompare    key_compare;
+    typedef TCompare    value_compare;
+    typedef value_type& const_reference;
+    typedef value_type* const_pointer;
+    typedef size_t      size_type;
+
+    //*************************************************************************
+    /// How to compare two key elements.
+    //*************************************************************************
+    struct key_comp
+    {
+      bool operator ()(key_type& key1, key_type& key2) const
+      {
+        return key_compare()(key1, key2);
+      }
+    };
+
+    //*************************************************************************
+    /// How to compare two value elements.
+    //*************************************************************************
+    struct value_comp
+    {
+      bool operator ()(value_type& value1, value_type& value2) const
+      {
+        return value_compare()(value1, value2);
+      }
+    };
+
+  protected:
+
+    //*************************************************************************
+    /// The data node element in the set.
+    //*************************************************************************
+    struct Data_Node : public Node
+    {
+      explicit Data_Node(value_type value_)
+        : value(value_)
+      {
+      }
+
+      value_type value;
+    };
+
+    /// Defines the key value parameter type
+    typedef typename etl::parameter_type<T>::type key_parameter_t;
+
+    //*************************************************************************
+    /// How to compare node elements.
+    //*************************************************************************
+    bool node_comp(const Data_Node& node1, const Data_Node& node2) const
+    {
+      return key_compare()(node1.value, node2.value);
+    }
+
+    bool node_comp(const Data_Node& node, key_parameter_t key) const
+    {
+      return key_compare()(node.value, key);
+    }
+    bool node_comp(key_parameter_t key, const Data_Node& node) const
+
+    {
+      return key_compare()(key, node.value);
+    }
+
+  private:
+
+    /// The pool of data nodes used in the set.
+    etl::ipool* p_node_pool;
+
+    //*************************************************************************
+    /// Downcast a Node* to a Data_Node*
+    //*************************************************************************
+    static Data_Node* data_cast(Node* p_node)
+    {
+      return static_cast<Data_Node*>(p_node);
+    }
+
+    //*************************************************************************
+    /// Downcast a Node& to a Data_Node&
+    //*************************************************************************
+    static Data_Node& data_cast(Node& node)
+    {
+      return static_cast<Data_Node&>(node);
+    }
+
+    //*************************************************************************
+    /// Downcast a const Node* to a const Data_Node*
+    //*************************************************************************
+    static const Data_Node* data_cast(const Node* p_node)
+    {
+      return static_cast<const Data_Node*>(p_node);
+    }
+
+    //*************************************************************************
+    /// Downcast a const Node& to a const Data_Node&
+    //*************************************************************************
+    static const Data_Node& data_cast(const Node& node)
+    {
+      return static_cast<const Data_Node&>(node);
+    }
+
+  public:
+    //*************************************************************************
+    /// iterator.
+    //*************************************************************************
+    class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
+    {
+    public:
+
+      friend class iset;
+
+      iterator()
+        : p_set(std::nullptr)
+        , p_node(std::nullptr)
+      {
+      }
+
+      iterator(iset& set)
+        : p_set(&set)
+        , p_node(std::nullptr)
+      {
+      }
+
+      iterator(iset& set, Node* node)
+        : p_set(&set)
+        , p_node(node)
+      {
+      }
+
+      iterator(const iterator& other)
+        : p_set(other.p_set)
+        , p_node(other.p_node)
+      {
+      }
+
+      ~iterator()
+      {
+      }
+
+      iterator& operator ++()
+      {
+        p_set->next_node(p_node);
+        return *this;
+      }
+
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        p_set->next_node(p_node);
+        return temp;
+      }
+
+      iterator& operator --()
+      {
+        p_set->prev_node(p_node);
+        return *this;
+      }
+
+      iterator operator --(int)
+      {
+        iterator temp(*this);
+        p_set->prev_node(p_node);
+        return temp;
+      }
+
+      iterator operator =(const iterator& other)
+      {
+        p_set = other.p_set;
+        p_node = other.p_node;
+        return *this;
+      }
+
+      const_reference operator *() const
+      {
+        return iset::data_cast(p_node)->value;
+      }
+
+      const_pointer operator &() const
+      {
+        return &(iset::data_cast(p_node)->value);
+      }
+
+      const_pointer operator ->() const
+      {
+        return &(iset::data_cast(p_node)->value);
+      }
+
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.p_set == rhs.p_set && lhs.p_node == rhs.p_node;
+      }
+
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      // Pointer to set associated with this iterator
+      iset* p_set;
+
+      // Pointer to the current node for this iterator
+      Node* p_node;
+    };
+    friend class iterator;
+
+    //*************************************************************************
+    /// const_iterator
+    //*************************************************************************
+    class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
+    {
+    public:
+
+      friend class iset;
+
+      const_iterator()
+        : p_set(nullptr)
+        , p_node(nullptr)
+      {
+      }
+
+      const_iterator(const iset& set)
+        : p_set(&set)
+        , p_node(nullptr)
+      {
+      }
+
+      const_iterator(const iset& set, const Node* node)
+        : p_set(&set)
+        , p_node(node)
+      {
+      }
+
+      const_iterator(const typename iset::iterator& other)
+        : p_set(other.p_set)
+        , p_node(other.p_node)
+      {
+      }
+
+      const_iterator(const const_iterator& other)
+        : p_set(other.p_set)
+        , p_node(other.p_node)
+      {
+      }
+
+      ~const_iterator()
+      {
+      }
+
+      const_iterator& operator ++()
+      {
+        p_set->next_node(p_node);
+        return *this;
+      }
+
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        p_set->next_node(p_node);
+        return temp;
+      }
+
+      const_iterator& operator --()
+      {
+        p_set->prev_node(p_node);
+        return *this;
+      }
+
+      const_iterator operator --(int)
+      {
+        const_iterator temp(*this);
+        p_set->prev_node(p_node);
+        return temp;
+      }
+
+      const_iterator operator =(const const_iterator& other)
+      {
+        p_set = other.p_set;
+        p_node = other.p_node;
+        return *this;
+      }
+
+      const_reference operator *() const
+      {
+        return iset::data_cast(p_node)->value;
+      }
+
+      const_pointer operator &() const
+      {
+        return iset::data_cast(p_node)->value;
+      }
+
+      const_pointer operator ->() const
+      {
+        return &(iset::data_cast(p_node)->value);
+      }
+
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.p_set == rhs.p_set && lhs.p_node == rhs.p_node;
+      }
+
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+      // Pointer to set associated with this iterator
+      const iset* p_set;
+
+      // Pointer to the current node for this iterator
+      const Node* p_node;
+    };
+    friend class const_iterator;
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    iset& operator = (const iset& rhs)
+    {
+      if (this != &rhs)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the set.
+    //*************************************************************************
+    iterator begin()
+    {
+      return iterator(*this, find_limit_node(root_node, kLeft));
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the set.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(*this, find_limit_node(root_node, kLeft));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the set.
+    //*************************************************************************
+    iterator end()
+    {
+      return iterator(*this);
+    }
+
+    //*************************************************************************
+    /// Gets the end of the set.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(*this);
+    }
+
+    //*************************************************************************
+    /// Gets the beginning of the set.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(*this, find_limit_node(root_node, kLeft));
+    }
+
+    //*************************************************************************
+    /// Gets the end of the set.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(*this);
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(iterator(*this));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(const_iterator(*this));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse beginning of the list.
+    //*************************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(const_iterator(*this));
+    }
+
+    //*************************************************************************
+    /// Gets the reverse end of the list.
+    //*************************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
+    }
+
+    //*********************************************************************
+    /// Assigns values to the set.
+    /// If asserts or exceptions are enabled, emits set_full if the set does not have enough free space.
+    /// If asserts or exceptions are enabled, emits set_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+      initialise();
+      insert(first, last);
+    }
+
+    //*************************************************************************
+    /// Clears the set.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*********************************************************************
+    /// Counts the number of elements that contain the key specified.
+    ///\param key The key to search for.
+    ///\return 1 if element was found, 0 otherwise.
+    //*********************************************************************
+    size_type count(key_parameter_t key) const
+    {
+      return find_node(root_node, key) ? 1 : 0;
+    }
+
+    //*************************************************************************
+    /// Returns two iterators with bounding (lower bound, upper bound) the
+    /// value provided
+    //*************************************************************************
+    std::pair<iterator, iterator> equal_range(const value_type& value)
+    {
+      return std::make_pair<iterator, iterator>(
+        iterator(*this, find_lower_node(root_node, value)),
+        iterator(*this, find_upper_node(root_node, value)));
+    }
+
+    //*************************************************************************
+    /// Returns two const iterators with bounding (lower bound, upper bound)
+    /// the value provided.
+    //*************************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(const value_type& value) const
+    {
+      return std::make_pair<const_iterator, const_iterator>(
+        const_iterator(*this, find_lower_node(root_node, value)),
+        const_iterator(*this, find_upper_node(root_node, value)));
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    void erase(iterator position)
+    {
+      // Remove the node by its key
+      erase((*position));
+    }
+
+    //*************************************************************************
+    /// Erases the value at the specified position.
+    //*************************************************************************
+    iterator erase(const_iterator position)
+    {
+      // Find the parent node to be removed
+      Node*& reference_node = find_node(root_node, position.p_node);
+      iterator next(*this, reference_node);
+      ++next;
+
+      remove_node(root_node, (*position));
+
+      return next;
+    }
+
+    //*************************************************************************
+    // Erase the key specified.
+    //*************************************************************************
+    size_type erase(key_parameter_t key_value)
+    {
+      // Return 1 if key value was found and removed
+      return remove_node(root_node, key_value) ? 1 : 0;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    //*************************************************************************
+    iterator erase(iterator first, iterator last)
+    {
+      iterator next;
+      while (first != last)
+      {
+        next = erase(const_iterator(first++));
+      }
+
+      return next;
+    }
+
+    //*************************************************************************
+    /// Erases a range of elements.
+    //*************************************************************************
+    iterator erase(const_iterator first, const_iterator last)
+    {
+      iterator next;
+      while (first != last)
+      {
+        next = erase(first++);
+      }
+
+      return next;
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    iterator find(key_parameter_t key_value)
+    {
+      return iterator(*this, find_node(root_node, key_value));
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator pointing to the element or end() if not found.
+    //*********************************************************************
+    const_iterator find(key_parameter_t key_value) const
+    {
+      return const_iterator(*this, find_node(root_node, key_value));
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the set.
+    /// If asserts or exceptions are enabled, emits set_full if the set is already full.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(value_type& value)
+    {
+      // Default to no inserted node
+      Node* inserted_node =std::nullptr;
+      bool inserted = false;
+
+      ETL_ASSERT(!full(), ETL_ERROR(set_full));
+
+      // Get next available free node
+      Data_Node& node = allocate_data_node(value);
+
+      // Obtain the inserted node (might bestd::nullptr if node was a duplicate)
+      inserted_node = insert_node(root_node, node);
+      inserted = inserted_node == &node;
+
+      // Insert node into tree and return iterator to new node location in tree
+      return std::make_pair(iterator(*this, inserted_node), inserted);
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the set starting at the position recommended.
+    /// If asserts or exceptions are enabled, emits set_full if the set is already full.
+    ///\param position The position that would precede the value to insert.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator, value_type& value)
+    {
+      // Default to no inserted node
+      Node* inserted_node =std::nullptr;
+
+      ETL_ASSERT(!full(), ETL_ERROR(set_full));
+
+      // Get next available free node
+      Data_Node& node = allocate_data_node(value);
+
+      // Obtain the inserted node (might bestd::nullptr if node was a duplicate)
+      inserted_node = insert_node(root_node, node);
+
+      // Insert node into tree and return iterator to new node location in tree
+      return iterator(*this, inserted_node);
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the set starting at the position recommended.
+    /// If asserts or exceptions are enabled, emits set_full if the set is already full.
+    ///\param position The position that would precede the value to insert.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(const_iterator, value_type& value)
+    {
+      // Default to no inserted node
+      Node* inserted_node =std::nullptr;
+
+      ETL_ASSERT(!full(), ETL_ERROR(set_full));
+
+      // Get next available free node
+      Data_Node& node = allocate_data_node(value);
+
+      // Obtain the inserted node (might bestd::nullptr if node was a duplicate)
+      inserted_node = insert_node(root_node, node);
+
+      // Insert node into tree and return iterator to new node location in tree
+      return iterator(*this, inserted_node);
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the set.
+    /// If asserts or exceptions are enabled, emits set_full if the set does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first, TIterator last)
+    {
+      while (first != last)
+      {
+        insert(*first++);
+      }
+    }
+
+    //*********************************************************************
+    /// Returns an iterator pointing to the first element in the container
+    /// whose key is not considered to go before the key provided or end()
+    /// if all keys are considered to go before the key provided.
+    ///\return An iterator pointing to the element not before key or end()
+    //*********************************************************************
+    iterator lower_bound(key_parameter_t key)
+    {
+      return iterator(*this, find_lower_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator pointing to the first element in the
+    /// container whose key is not considered to go before the key provided
+    /// or end() if all keys are considered to go before the key provided.
+    ///\return An const_iterator pointing to the element not before key or end()
+    //*********************************************************************
+    const_iterator lower_bound(key_parameter_t key) const
+    {
+      return const_iterator(*this, find_lower_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Returns an iterator pointing to the first element in the container
+    /// whose key is not considered to go after the key provided or end()
+    /// if all keys are considered to go after the key provided.
+    ///\return An iterator pointing to the element after key or end()
+    //*********************************************************************
+    iterator upper_bound(key_parameter_t key)
+    {
+      return iterator(*this, find_upper_node(root_node, key));
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator pointing to the first element in the
+    /// container whose key is not considered to go after the key provided
+    /// or end() if all keys are considered to go after the key provided.
+    ///\return An const_iterator pointing to the element after key or end()
+    //*********************************************************************
+    const_iterator upper_bound(key_parameter_t key) const
+    {
+      return const_iterator(*this, find_upper_node(root_node, key));
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    iset(etl::ipool& node_pool, size_t max_size_)
+      : etl::set_base(max_size_)
+      , p_node_pool(&node_pool)
+    {
+    }
+
+    //*************************************************************************
+    /// Initialise the set.
+    //*************************************************************************
+    void initialise()
+    {
+      erase(begin(), end());
+    }
+
+  private:
+
+    //*************************************************************************
+    /// Allocate a Data_Node.
+    //*************************************************************************
+    Data_Node& allocate_data_node(value_type value)
+    {
+      Data_Node& node = *p_node_pool->allocate<Data_Node>();
+      ::new ((void*)&node.value) value_type(value);
+      ++construct_count;
+      return node;
+    }
+
+    //*************************************************************************
+    /// Destroy a Data_Node.
+    //*************************************************************************
+    void destroy_data_node(Data_Node& node)
+    {
+      node.value.~value_type();
+      p_node_pool->release(&node);
+      --construct_count;
+    }
+
+    //*************************************************************************
+    /// Find the value matching the node provided
+    //*************************************************************************
+    Node* find_node(Node* position, key_parameter_t key)
+    {
+      Node* found = position;
+      while (found)
+      {
+        // Downcast found to Data_Node class for comparison and other operations
+        Data_Node& found_data_node = iset::data_cast(*found);
+
+        // Compare the node value to the current position value
+        if (node_comp(key, found_data_node))
+        {
+          // Keep searching for the node on the left
+          found = found->children[kLeft];
+        }
+        else if (node_comp(found_data_node, key))
+        {
+          // Keep searching for the node on the right
+          found = found->children[kRight];
+        }
+        else
+        {
+          // Node that matches the key provided was found, exit loop
+          break;
+        }
+      }
+
+      // Return the node found (might bestd::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the value matching the node provided
+    //*************************************************************************
+    const Node* find_node(const Node* position, key_parameter_t key) const
+    {
+      const Node* found = position;
+      while (found)
+      {
+        // Downcast found to Data_Node class for comparison and other operations
+        const Data_Node& found_data_node = iset::data_cast(*found);
+
+        // Compare the node value to the current position value
+        if (node_comp(key, found_data_node))
+        {
+          // Keep searching for the node on the left
+          found = found->children[kLeft];
+        }
+        else if (node_comp(found_data_node, key))
+        {
+          // Keep searching for the node on the right
+          found = found->children[kRight];
+        }
+        else
+        {
+          // Node that matches the key provided was found, exit loop
+          break;
+        }
+      }
+
+      // Return the node found (might bestd::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the reference node matching the node provided
+    //*************************************************************************
+    Node*& find_node(Node*& position, const Node* node)
+    {
+      Node* found = position;
+      while (found)
+      {
+        if (found->children[kLeft] == node)
+        {
+          return found->children[kLeft];
+        }
+        else if (found->children[kRight] == node)
+        {
+          return found->children[kRight];
+        }
+        else
+        {
+          // Downcast found to Data_Node class for comparison and other operations
+          Data_Node& found_data_node = iset::data_cast(*found);
+          const Data_Node& data_node = iset::data_cast(*node);
+
+          // Compare the node value to the current position value
+          if (node_comp(data_node, found_data_node))
+          {
+            // Keep searching for the node on the left
+            found = found->children[kLeft];
+          }
+          else if (node_comp(found_data_node, data_node))
+          {
+            // Keep searching for the node on the right
+            found = found->children[kRight];
+          }
+          else
+          {
+            // Return position provided (it matches the node)
+            return position;
+          }
+        }
+      }
+
+      // Return root node if nothing was found
+      return root_node;
+    }
+
+    //*************************************************************************
+    /// Find the parent node that contains the node provided in its left or
+    /// right tree
+    //*************************************************************************
+    Node* find_parent_node(Node* position, const Node* node)
+    {
+      // Default to no parent node found
+      Node* found =std::nullptr;
+
+      // If the position provided is the same as the node then there is no parent
+      if (position && node && position != node)
+      {
+        while (position)
+        {
+          // Is this position not the parent of the node we are looking for?
+          if (position->children[kLeft] != node &&
+            position->children[kRight] != node)
+          {
+            // Downcast node and position to Data_Node references for key comparisons
+            const Data_Node& node_data_node = iset::data_cast(*node);
+            Data_Node& position_data_node = iset::data_cast(*position);
+            // Compare the node value to the current position value
+            if (node_comp(node_data_node, position_data_node))
+            {
+              // Keep looking for parent on the left
+              position = position->children[kLeft];
+            }
+            else if (node_comp(position_data_node, node_data_node))
+            {
+              // Keep looking for parent on the right
+              position = position->children[kRight];
+            }
+          }
+          else
+          {
+            // Return the current position as the parent node found
+            found = position;
+
+            // Parent node found, exit loop
+            break;
+          }
+        }
+      }
+
+      // Return the parent node found (might bestd::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the parent node that contains the node provided in its left or
+    /// right tree
+    //*************************************************************************
+    const Node* find_parent_node(const Node* position, const Node* node) const
+    {
+      // Default to no parent node found
+      const Node* found =std::nullptr;
+
+      // If the position provided is the same as the node then there is no parent
+      if (position && node && position != node)
+      {
+        while (position)
+        {
+          // Is this position not the parent of the node we are looking for?
+          if (position->children[kLeft] != node &&
+            position->children[kRight] != node)
+          {
+            // Downcast node and position to Data_Node references for key comparisons
+            const Data_Node& node_data_node = iset::data_cast(*node);
+            const Data_Node& position_data_node = iset::data_cast(*position);
+            // Compare the node value to the current position value
+            if (node_comp(node_data_node, position_data_node))
+            {
+              // Keep looking for parent on the left
+              position = position->children[kLeft];
+            }
+            else if (node_comp(position_data_node, node_data_node))
+            {
+              // Keep looking for parent on the right
+              position = position->children[kRight];
+            }
+          }
+          else
+          {
+            // Return the current position as the parent node found
+            found = position;
+
+            // Parent node found, exit loop
+            break;
+          }
+        }
+      }
+
+      // Return the parent node found (might bestd::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the node whose key is not considered to go before the key provided
+    //*************************************************************************
+    Node* find_lower_node(Node* position, key_parameter_t key) const
+    {
+      // Something at this position? keep going
+      Node* lower_node = position;
+      while (lower_node)
+      {
+        // Downcast lower node to Data_Node reference for key comparisons
+        Data_Node& data_node = iset::data_cast(*lower_node);
+        // Compare the key value to the current lower node key value
+        if (node_comp(key, data_node))
+        {
+          if (lower_node->children[kLeft])
+          {
+            lower_node = lower_node->children[kLeft];
+          }
+          else
+          {
+            // Found lowest node
+            break;
+          }
+        }
+        else if (node_comp(data_node, key))
+        {
+          lower_node = lower_node->children[kRight];
+        }
+        else
+        {
+          // Found equal node
+          break;
+        }
+      }
+
+      // Return the lower_node position found
+      return lower_node;
+    }
+
+    //*************************************************************************
+    /// Find the node whose key is considered to go after the key provided
+    //*************************************************************************
+    Node* find_upper_node(Node* position, key_parameter_t key) const
+    {
+      // Keep track of parent of last upper node
+      Node* upper_node =std::nullptr;
+      // Start with position provided
+      Node* node = position;
+      while (node)
+      {
+        // Downcast position to Data_Node reference for key comparisons
+        Data_Node& data_node = iset::data_cast(*node);
+        // Compare the key value to the current upper node key value
+        if (node_comp(key, data_node))
+        {
+          upper_node = node;
+          node = node->children[kLeft];
+        }
+        else if (node_comp(data_node, key))
+        {
+          node = node->children[kRight];
+        }
+        else if (node->children[kRight])
+        {
+          upper_node = find_limit_node(node->children[kRight], kLeft);
+          break;
+        }
+        else
+        {
+          break;
+        }
+      }
+
+      // Return the upper node position found (might bestd::nullptr)
+      return upper_node;
+    }
+
+    //*************************************************************************
+    /// Insert a node.
+    //*************************************************************************
+    Node* insert_node(Node*& position, Data_Node& node)
+    {
+      // Find the location where the node belongs
+      Node* found = position;
+
+      // Was position provided not empty? then find where the node belongs
+      if (position)
+      {
+        // Find the critical parent node (default tostd::nullptr)
+        Node* critical_parent_node =std::nullptr;
+        Node* critical_node = root_node;
+
+        while (found)
+        {
+          // Search for critical weight node (all nodes whose weight factor
+          // is set to kNeither (balanced)
+          if (kNeither != found->weight)
+          {
+            critical_node = found;
+          }
+
+          // Downcast found to Data_Node class for comparison and other operations
+          Data_Node& found_data_node = iset::data_cast(*found);
+
+          // Is the node provided to the left of the current position?
+          if (node_comp(node, found_data_node))
+          {
+            // Update direction taken to insert new node in parent node
+            found->dir = kLeft;
+          }
+          // Is the node provided to the right of the current position?
+          else if (node_comp(found_data_node, node))
+          {
+            // Update direction taken to insert new node in parent node
+            found->dir = kRight;
+          }
+          else
+          {
+            // Update direction taken to insert new node in parent node
+            found->dir = kNeither;
+
+            // Clear critical node value to skip weight step below
+            critical_node =std::nullptr;
+
+            // Destroy the node provided (its a duplicate)
+            destroy_data_node(node);
+
+            // Exit loop, duplicate node found
+            break;
+          }
+
+          // Is there a child of this parent node?
+          if (found->children[found->dir])
+          {
+            // Will this node be the parent of the next critical node whose
+            // weight factor is set to kNeither (balanced)?
+            if (kNeither != found->children[found->dir]->weight)
+            {
+              critical_parent_node = found;
+            }
+
+            // Keep looking for empty spot to insert new node
+            found = found->children[found->dir];
+          }
+          else
+          {
+            // Attatch node to right
+            attach_node(found->children[found->dir], node);
+
+            // Return newly added node
+            found = found->children[found->dir];
+
+            // Exit loop
+            break;
+          }
+        }
+
+        // Was a critical node found that should be checked for balance?
+        if (critical_node)
+        {
+          if (critical_parent_node ==std::nullptr && critical_node == root_node)
+          {
+            balance_node(root_node);
+          }
+          else if (critical_parent_node ==std::nullptr && critical_node == position)
+          {
+            balance_node(position);
+          }
+          else
+          {
+            balance_node(critical_parent_node->children[critical_parent_node->dir]);
+          }
+        }
+      }
+      else
+      {
+        // Attatch node to current position
+        attach_node(position, node);
+
+        // Return newly added node at current position
+        found = position;
+      }
+
+      // Return the node found (might bestd::nullptr)
+      return found;
+    }
+
+    //*************************************************************************
+    /// Find the next node in sequence from the node provided
+    //*************************************************************************
+    void next_node(Node*&position)
+    {
+      if (position)
+      {
+        // Is there a tree on the right? then find the minimum of that tree
+        if (position->children[kRight])
+        {
+          // Return minimum node found
+          position = find_limit_node(position->children[kRight], kLeft);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = find_parent_node(root_node, position);
+            // Repeat while previous position was on right side of parent tree
+          } while (parent && parent->children[kRight] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the next node in sequence from the node provided
+    //*************************************************************************
+    void next_node(const Node*& position) const
+    {
+      if (position)
+      {
+        // Is there a tree on the right? then find the minimum of that tree
+        if (position->children[kRight])
+        {
+          // Return minimum node found
+          position = find_limit_node(position->children[kRight], kLeft);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          const Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = find_parent_node(root_node, position);
+            // Repeat while previous position was on right side of parent tree
+          } while (parent && parent->children[kRight] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the previous node in sequence from the node provided
+    //*************************************************************************
+    void prev_node(Node*&position)
+    {
+      // If starting at the terminal end, the previous node is the maximum node
+      // from the root
+      if (!position)
+      {
+        position = find_limit_node(root_node, kRight);
+      }
+      else
+      {
+        // Is there a tree on the left? then find the maximum of that tree
+        if (position->children[kLeft])
+        {
+          // Return maximum node found
+          position = find_limit_node(position->children[kLeft], kRight);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = find_parent_node(root_node, position);
+            // Repeat while previous position was on left side of parent tree
+          } while (parent && parent->children[kLeft] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Find the previous node in sequence from the node provided
+    //*************************************************************************
+    void prev_node(const Node*& position) const
+    {
+      // If starting at the terminal end, the previous node is the maximum node
+      // from the root
+      if (!position)
+      {
+        position = find_limit_node(root_node, kRight);
+      }
+      else
+      {
+        // Is there a tree on the left? then find the maximum of that tree
+        if (position->children[kLeft])
+        {
+          // Return maximum node found
+          position = find_limit_node(position->children[kLeft], kRight);
+        }
+        // Otherwise find the parent of this node
+        else
+        {
+          // Start with current position as parent
+          const Node* parent = position;
+          do {
+            // Update current position as previous parent
+            position = parent;
+            // Find parent of current position
+            parent = find_parent_node(root_node, position);
+            // Repeat while previous position was on left side of parent tree
+          } while (parent && parent->children[kLeft] == position);
+
+          // Set parent node as the next position
+          position = parent;
+        }
+      }
+    }
+
+    //*************************************************************************
+    /// Remove the node specified from somewhere starting at the position
+    /// provided
+    //*************************************************************************
+    Node* remove_node(Node*& position, key_parameter_t key)
+    {
+      // Step 1: Find the target node that matches the key provided, the
+      // replacement node (might be the same as target node), and the critical
+      // node to start rebalancing the tree from (up to the replacement node)
+      Node* found_parent =std::nullptr;
+      Node* found =std::nullptr;
+      Node* replace_parent =std::nullptr;
+      Node* replace = position;
+      Node* balance_parent =std::nullptr;
+      Node* balance = root_node;
+      while (replace)
+      {
+        // Downcast found to Data_Node class for comparison and other operations
+        Data_Node& replace_data_node = iset::data_cast(*replace);
+
+        // Compare the key provided to the replace data node key
+        if (node_comp(key, replace_data_node))
+        {
+          // Update the direction to the target/replace node
+          replace->dir = kLeft;
+        }
+        else if (node_comp(replace_data_node, key))
+        {
+          // Update the direction to the target/replace node
+          replace->dir = kRight;
+        }
+        else
+        {
+          // Update the direction to the replace node (target node found here)
+          replace->dir = replace->children[kLeft] ? kLeft : kRight;
+
+          // Note the target node was found (and its parent)
+          found_parent = replace_parent;
+          found = replace;
+        }
+        // Replacement node found if its missing a child in the replace->dir
+        // value set above
+        if (replace->children[replace->dir] ==std::nullptr)
+        {
+          // Exit loop once replace node is found (target might not have been)
+          break;
+        }
+
+        // If replacement node weight is kNeither or we are taking the shorter
+        // path of replacement node and our sibling (on longer path) is
+        // balanced then we need to update the balance node to match this
+        // replacement node but all our ancestors will not require rebalancing
+        if ((replace->weight == kNeither) ||
+          (replace->weight == (1 - replace->dir) &&
+            replace->children[1 - replace->dir]->weight == kNeither))
+        {
+          // Update balance node (and its parent) to replacement node
+          balance_parent = replace_parent;
+          balance = replace;
+        }
+
+        // Keep searching for the replacement node
+        replace_parent = replace;
+        replace = replace->children[replace->dir];
+      }
+
+      // If target node was found, proceed with rebalancing and replacement
+      if (found)
+      {
+        // Step 2: Update weights from critical node to replacement parent node
+        while (balance)
+        {
+          if (balance->children[balance->dir] ==std::nullptr)
+          {
+            break;
+          }
+
+          if (balance->weight == kNeither)
+          {
+            balance->weight = 1 - balance->dir;
+          }
+          else if (balance->weight == balance->dir)
+          {
+            balance->weight = kNeither;
+          }
+          else
+          {
+            int weight = balance->children[1 - balance->dir]->weight;
+            // Perform a 3 node rotation if weight is same as balance->dir
+            if (weight == balance->dir)
+            {
+              // Is the root node being rebalanced (no parent)
+              if (balance_parent ==std::nullptr)
+              {
+                rotate_3node(root_node, 1 - balance->dir,
+                  balance->children[1 - balance->dir]->children[balance->dir]->weight);
+              }
+              else
+              {
+                rotate_3node(balance_parent->children[balance_parent->dir], 1 - balance->dir,
+                  balance->children[1 - balance->dir]->children[balance->dir]->weight);
+              }
+            }
+            // Already balanced, rebalance and make it heavy in opposite
+            // direction of the node being removed
+            else if (weight == kNeither)
+            {
+              // Is the root node being rebalanced (no parent)
+              if (balance_parent ==std::nullptr)
+              {
+                rotate_2node(root_node, 1 - balance->dir);
+                root_node->weight = balance->dir;
+              }
+              else
+              {
+                rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
+                balance_parent->children[balance_parent->dir]->weight = balance->dir;
+              }
+              // Update balance node weight in opposite direction of node removed
+              balance->weight = 1 - balance->dir;
+            }
+            // Rebalance and leave it balanced
+            else
+            {
+              // Is the root node being rebalanced (no parent)
+              if (balance_parent ==std::nullptr)
+              {
+                rotate_2node(root_node, 1 - balance->dir);
+              }
+              else
+              {
+                rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir);
+              }
+            }
+
+            // Is balance node the same as the target node found? then update
+            // its parent after the rotation performed above
+            if (balance == found)
+            {
+              if (balance_parent)
+              {
+                found_parent = balance_parent->children[balance_parent->dir];
+                // Update dir since it is likely stale
+                found_parent->dir = found_parent->children[kLeft] == found ? kLeft : kRight;
+              }
+              else
+              {
+                found_parent = root_node;
+                root_node->dir = root_node->children[kLeft] == found ? kLeft : kRight;
+              }
+            }
+          }
+
+          // Next balance node to consider
+          balance_parent = balance;
+          balance = balance->children[balance->dir];
+        } // while(balance)
+
+          // Step 3: Swap found node with replacement node
+        if (found_parent)
+        {
+          // Handle traditional case
+          detach_node(found_parent->children[found_parent->dir],
+            replace_parent->children[replace_parent->dir]);
+        }
+        // Handle root node removal
+        else
+        {
+          // Valid replacement node for root node being removed?
+          if (replace_parent)
+          {
+            detach_node(root_node, replace_parent->children[replace_parent->dir]);
+          }
+          else
+          {
+            // Target node and replacement node are both root node
+            detach_node(root_node, root_node);
+          }
+        }
+
+        // Downcast found into data node
+        Data_Node& found_data_node = iset::data_cast(*found);
+
+        // One less.
+        --current_size;
+
+        // Destroy the node removed
+        destroy_data_node(found_data_node);
+      } // if(found)
+
+        // Return node found (might bestd::nullptr)
+      return found;
+    }
+
+    // Disable copy construction.
+    iset(const iset&);
+  };
+
+  //*************************************************************************
+  /// A templated set implementation that uses a fixed size buffer.
+  //*************************************************************************
+  template <typename T, const size_t MAX_SIZE_, typename TCompare = std::less<T> >
+  class set : public etl::iset<T, TCompare>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    set()
+      : etl::iset<T, TCompare>(node_pool, MAX_SIZE)
+    {
+      etl::iset<T, TCompare>::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    set(const set& other)
+      : etl::iset<T, TCompare>(node_pool, MAX_SIZE)
+    {
+      etl::iset<T, TCompare>::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    set(TIterator first, TIterator last)
+      : etl::iset<T, TCompare>(node_pool, MAX_SIZE)
+    {
+      etl::iset<T, TCompare>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~set()
+    {
+      etl::iset<T, TCompare>::initialise();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    set& operator = (const set& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        etl::iset<T, TCompare>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    /// The pool of data nodes used for the set.
+    etl::pool<typename etl::iset<T, TCompare>::Data_Node, MAX_SIZE> node_pool;
+  };
+}
+
+//***************************************************************************
+/// Equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename T, typename TCompare>
+bool operator ==(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs)
+{
+  return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+//***************************************************************************
+/// Not equal operator.
+///\param lhs Reference to the first lookup.
+///\param rhs Reference to the second lookup.
+///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+///\ingroup lookup
+//***************************************************************************
+template <typename T, typename TCompare>
+bool operator !=(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs)
+{
+  return !(lhs == rhs);
+}
+
+//*************************************************************************
+/// Less than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator <(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs)
+{
+  return std::lexicographical_compare(lhs.begin(),
+    lhs.end(),
+    rhs.begin(),
+    rhs.end());
+}
+
+//*************************************************************************
+/// Greater than operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than the
+/// second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator >(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs)
+{
+  return (rhs < lhs);
+}
+
+//*************************************************************************
+/// Less than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically less than or equal
+/// to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator <=(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs)
+{
+  return !(lhs > rhs);
+}
+
+//*************************************************************************
+/// Greater than or equal operator.
+///\param lhs Reference to the first list.
+///\param rhs Reference to the second list.
+///\return <b>true</b> if the first list is lexicographically greater than or
+/// equal to the second, otherwise <b>false</b>.
+//*************************************************************************
+template <typename T, typename TCompare>
+bool operator >=(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs)
+{
+  return !(lhs < rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smallest.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,342 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+#if 0
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+#endif
+
+//***************************************************************************
+// This file has been auto generated. Do not edit this file.
+//***************************************************************************
+
+//***************************************************************************
+// To generate to header file, run this at the command line.
+// Note: You will need Python and COG installed.
+//
+// python -m cogapp -d -e -osmallest.h -DNTypes=<n> smallest_generator.h
+// Where <n> is the number of types to support.
+//
+// e.g.
+// To generate handlers for up to 16 types...
+// python -m cogapp -d -e -osmallest.h -DNTypes=16 smallest_generator.h
+//
+// See generate.bat
+//***************************************************************************
+
+#ifndef __ETL_SMALLEST__
+#define __ETL_SMALLEST__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "integral_limits.h"
+
+///\defgroup smallest smallest
+///\ingroup utilities
+
+namespace etl
+{
+  /* 7.18.2.1  Limits of exact-width integer types */
+    #define INT8_MIN (-128) 
+    #define INT16_MIN (-32768)
+    #define INT32_MIN (-2147483647 - 1)
+    #define INT64_MIN  (-9223372036854775807LL - 1)
+     
+    #define INT8_MAX 127
+    #define INT16_MAX 32767
+    #define INT32_MAX 2147483647
+    #define INT64_MAX 9223372036854775807LL
+ 
+    
+    #define UINT8_MAX 0xff /* 255U */
+    #define UINT16_MAX 0xffff /* 65535U */
+    #define UINT32_MAX 0xffffffff  /* 4294967295U */
+    #define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
+     
+    /* 7.18.2.2  Limits of minimum-width integer types */
+    #define INT_LEAST8_MIN INT8_MIN
+    #define INT_LEAST16_MIN INT16_MIN
+    #define INT_LEAST32_MIN INT32_MIN
+    #define INT_LEAST64_MIN INT64_MIN
+    
+    #define INT_LEAST8_MAX INT8_MAX
+    #define INT_LEAST16_MAX INT16_MAX
+    #define INT_LEAST32_MAX INT32_MAX
+    #define INT_LEAST64_MAX INT64_MAX
+     
+    #define UINT_LEAST8_MAX UINT8_MAX
+    #define UINT_LEAST16_MAX UINT16_MAX
+    #define UINT_LEAST32_MAX UINT32_MAX
+    #define UINT_LEAST64_MAX UINT64_MAX
+  
+  
+  //***************************************************************************
+  /// Template to determine the smallest type and size.
+  /// Supports up to 16 types.
+  /// Defines 'value_type' which is the type of the smallest parameter.
+  /// Defines 'size' which is the size of the smallest parameter.
+  ///\ingroup smallest
+  //***************************************************************************
+  template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void, 
+            typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, 
+            typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, 
+            typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
+  struct smallest_type
+  {
+  private:
+
+    // Declaration.
+    template <const bool Boolean, typename TrueType, typename FalseType>
+    struct choose_type;
+
+    // Specialisation for 'true'.
+    // Defines 'type' as 'TrueType'.
+    template <typename TrueType, typename FalseType>
+    struct choose_type<true, TrueType, FalseType>
+    {
+      typedef TrueType type;
+    };
+
+    // Specialisation for 'false'. 
+    // Defines 'type' as 'FalseType'.
+    template <typename TrueType, typename FalseType>
+    struct choose_type<false, TrueType, FalseType>
+    {
+      typedef FalseType type;
+    };
+
+  public:
+
+    // Define 'smallest_other' as 'smallest_type' with all but the first parameter. 
+    typedef typename smallest_type<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::type smallest_other;
+
+    // Set 'type' to be the smallest of the first parameter and any of the others.
+    // This is recursive.
+    typedef typename choose_type<(sizeof(T1) < sizeof(smallest_other)), // Boolean
+                                  T1,                                   // TrueType
+                                  smallest_other>                       // FalseType
+                                  ::type type;                          // The smallest type of the two.
+
+    // The size of the smallest type.
+    enum
+    {
+      size = sizeof(type)
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for one template parameter.
+  //***************************************************************************
+  template <typename T1>
+  struct smallest_type<T1,   void, void, void, void, void, void, void, 
+                       void, void, void, void, void, void, void, void>
+  {
+    typedef T1 type;
+
+    enum
+    {
+      size = sizeof(type)
+    };
+  };
+  
+  namespace __private_smallest__
+  {
+    //*************************************************************************
+    // Determine the type to hold the number of bits based on the index.
+    //*************************************************************************
+    template <const int index>
+    struct best_fit_uint_type;
+    
+    //*************************************************************************
+    // Less than or equal to 8 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_uint_type<0>
+    {
+      typedef uint_least8_t type;
+    };
+
+    //*************************************************************************
+    // 9 to 16 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_uint_type<1>
+    {
+      typedef uint_least16_t type;
+    };
+
+    //*************************************************************************
+    // 17 to 31 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_uint_type<2>
+    {
+      typedef uint_least32_t type;
+    };
+
+    //*************************************************************************
+    // Greater than 32 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_uint_type<3>
+    {
+      typedef uint_least64_t type;
+    };
+
+    //*************************************************************************
+    // Determine the type to hold the number of bits based on the index.
+    //*************************************************************************
+    template <const int index>
+    struct best_fit_int_type;
+
+    //*************************************************************************
+    // Less than or equal to 8 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_int_type<0>
+    {
+      typedef int_least8_t type;
+    };
+
+    //*************************************************************************
+    // 9 to 16 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_int_type<1>
+    {
+      typedef int_least16_t type;
+    };
+
+    //*************************************************************************
+    // 17 to 31 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_int_type<2>
+    {
+      typedef int_least32_t type;
+    };
+
+    //*************************************************************************
+    // Greater than 32 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_int_type<3>
+    {
+      typedef int_least64_t type;
+    };
+  }
+
+  //***************************************************************************
+  /// Template to determine the smallest unsigned int type that can contain a 
+  /// value with the specified number of bits.
+  /// Defines 'type' which is the type of the smallest unsigned integer.
+  ///\ingroup smallest
+  //***************************************************************************
+  template <const size_t NBITS>
+  struct smallest_uint_for_bits
+  {
+  private:
+    
+    // Determines the index of the best unsigned type for the required number of bits.
+    static const int TYPE_INDEX = ((NBITS >  8) ? 1 : 0) + 
+                                  ((NBITS > 16) ? 1 : 0) +
+                                  ((NBITS > 32) ? 1 : 0);
+
+  public:
+
+    typedef typename __private_smallest__::best_fit_uint_type<TYPE_INDEX>::type type;
+  };
+
+  //***************************************************************************
+  /// Template to determine the smallest signed int type that can contain a 
+  /// value with the specified number of bits.
+  /// Defines 'type' which is the type of the smallest signed integer.
+  ///\ingroup smallest
+  //***************************************************************************
+  template <const size_t NBITS>
+  struct smallest_int_for_bits
+  {
+  private:
+
+    // Determines the index of the best unsigned type for the required number of bits.
+    static const int TYPE_INDEX = ((NBITS >  8) ? 1 : 0) +
+                                  ((NBITS > 16) ? 1 : 0) +
+                                  ((NBITS > 32) ? 1 : 0);
+
+  public:
+
+    typedef typename __private_smallest__::best_fit_int_type<TYPE_INDEX>::type type;
+  };
+
+  //***************************************************************************
+  /// Template to determine the smallest unsigned int type that can contain the
+  /// specified unsigned value.
+  /// Defines 'type' which is the type of the smallest unsigned integer.
+  ///\ingroup smallest
+  //***************************************************************************
+  template <const uintmax_t VALUE>
+  struct smallest_uint_for_value
+  {
+  private:
+
+    // Determines the index of the best unsigned type for the required value.
+    static const int TYPE_INDEX = ((VALUE > UINT_LEAST8_MAX)  ? 1 : 0) +
+                                  ((VALUE > UINT16_MAX) ? 1 : 0) + 
+                                  ((VALUE > UINT32_MAX) ? 1 : 0);
+
+  public:
+
+    typedef typename __private_smallest__::best_fit_uint_type<TYPE_INDEX>::type type;
+  };
+
+  //***************************************************************************
+  /// Template to determine the smallest int type that can contain the
+  /// specified signed value.
+  /// Defines 'type' which is the type of the smallest signed integer.
+  ///\ingroup smallest
+  //***************************************************************************
+  template <const intmax_t VALUE>
+  struct smallest_int_for_value
+  {
+  private:
+
+    // Determines the index of the best signed type for the required value.
+    static const int TYPE_INDEX = (((VALUE > INT_LEAST8_MAX)  || (VALUE < INT_LEAST8_MIN))  ? 1 : 0) + 
+                                  (((VALUE > INT16_MAX) || (VALUE < INT16_MIN)) ? 1 : 0) +
+                                  (((VALUE > INT32_MAX) || (VALUE < INT32_MIN)) ? 1 : 0);
+
+  public:
+
+    typedef typename __private_smallest__::best_fit_int_type<TYPE_INDEX>::type type;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smallest_generator.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,338 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+/*[[[cog
+import cog
+cog.outl("#if 0")
+]]]*/
+/*[[[end]]]*/
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+/*[[[cog
+import cog
+cog.outl("#endif")
+]]]*/
+/*[[[end]]]*/
+
+/*[[[cog
+import cog
+cog.outl("//***************************************************************************")
+cog.outl("// This file has been auto generated. Do not edit this file.")
+cog.outl("//***************************************************************************")
+]]]*/
+/*[[[end]]]*/
+
+//***************************************************************************
+// To generate to header file, run this at the command line.
+// Note: You will need Python and COG installed.
+//
+// python -m cogapp -d -e -osmallest.h -DNTypes=<n> smallest_generator.h
+// Where <n> is the number of types to support.
+//
+// e.g.
+// To generate handlers for up to 16 types...
+// python -m cogapp -d -e -osmallest.h -DNTypes=16 smallest_generator.h
+//
+// See generate.bat
+//***************************************************************************
+
+#ifndef __ETL_SMALLEST__
+#define __ETL_SMALLEST__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "integral_limits.h"
+
+///\defgroup smallest smallest
+///\ingroup utilities
+
+namespace etl
+{
+  /*[[[cog
+  import cog
+  cog.outl("//***************************************************************************")
+  cog.outl("/// Template to determine the smallest type and size.")
+  cog.outl("/// Supports up to %s types." % NTypes)
+  cog.outl("/// Defines 'value_type' which is the type of the smallest parameter.")
+  cog.outl("/// Defines 'size' which is the size of the smallest parameter.")
+  cog.outl("///\ingroup smallest")
+  cog.outl("//***************************************************************************")
+  cog.out("template <typename T1, ")
+  for n in range(2, int(NTypes)):
+      cog.out("typename T%s = void, " % n)
+      if n % 4 == 0:
+          cog.outl("")
+          cog.out("          ")
+  cog.outl("typename T%s = void>" % int(NTypes))
+  cog.outl("struct smallest_type")
+  cog.outl("{")
+  cog.outl("private:")
+  cog.outl("")
+  cog.outl("  // Declaration.")
+  cog.outl("  template <const bool Boolean, typename TrueType, typename FalseType>")
+  cog.outl("  struct choose_type;")
+  cog.outl("")
+  cog.outl("  // Specialisation for 'true'.")
+  cog.outl("  // Defines 'type' as 'TrueType'.")
+  cog.outl("  template <typename TrueType, typename FalseType>")
+  cog.outl("  struct choose_type<true, TrueType, FalseType>")
+  cog.outl("  {")
+  cog.outl("    typedef TrueType type;")
+  cog.outl("  };")
+  cog.outl("")
+  cog.outl("  // Specialisation for 'false'. ")
+  cog.outl("  // Defines 'type' as 'FalseType'.")
+  cog.outl("  template <typename TrueType, typename FalseType>")
+  cog.outl("  struct choose_type<false, TrueType, FalseType>")
+  cog.outl("  {")
+  cog.outl("    typedef FalseType type;")
+  cog.outl("  };")
+  cog.outl("")
+  cog.outl("public:")
+  cog.outl("")
+  cog.outl("  // Define 'smallest_other' as 'smallest_type' with all but the first parameter. ")
+  cog.out("  typedef typename smallest_type<")
+  for n in range(2, int(NTypes)):
+      cog.out("T%s, " % n)
+      if n % 16 == 0:
+          cog.outl("")
+          cog.out("                                ")
+  cog.outl("T%s>::type smallest_other;" % int(NTypes))
+  cog.outl("")
+  cog.outl("  // Set 'type' to be the smallest of the first parameter and any of the others.")
+  cog.outl("  // This is recursive.")
+  cog.outl("  typedef typename choose_type<(sizeof(T1) < sizeof(smallest_other)), // Boolean")
+  cog.outl("                                T1,                                   // TrueType")
+  cog.outl("                                smallest_other>                       // FalseType")
+  cog.outl("                                ::type type;                          // The smallest type of the two.")
+  cog.outl("")
+  cog.outl("  // The size of the smallest type.")
+  cog.outl("  enum")
+  cog.outl("  {")
+  cog.outl("    size = sizeof(type)")
+  cog.outl("  };")
+  cog.outl("};")
+  cog.outl("")
+  cog.outl("//***************************************************************************")
+  cog.outl("// Specialisation for one template parameter.")
+  cog.outl("//***************************************************************************")
+  cog.outl("template <typename T1>")
+  cog.out("struct smallest_type<T1,   ")
+  for n in range(2, int(NTypes)):
+      cog.out("void, ")
+      if n % 8 == 0:
+          cog.outl("")
+          cog.out("                     ")
+  cog.outl("void>")
+  cog.outl("{")
+  cog.outl("  typedef T1 type;")
+  cog.outl("")
+  cog.outl("  enum")
+  cog.outl("  {")
+  cog.outl("    size = sizeof(type)")
+  cog.outl("  };")
+  cog.outl("};")
+  ]]]*/
+  /*[[[end]]]*/
+  
+  namespace __private_smallest__
+  {
+    //*************************************************************************
+    // Determine the type to hold the number of bits based on the index.
+    //*************************************************************************
+    template <const int index>
+    struct best_fit_uint_type;
+    
+    //*************************************************************************
+    // Less than or equal to 8 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_uint_type<0>
+    {
+      typedef uint_least8_t type;
+    };
+
+    //*************************************************************************
+    // 9 to 16 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_uint_type<1>
+    {
+      typedef uint_least16_t type;
+    };
+
+    //*************************************************************************
+    // 17 to 31 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_uint_type<2>
+    {
+      typedef uint_least32_t type;
+    };
+
+    //*************************************************************************
+    // Greater than 32 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_uint_type<3>
+    {
+      typedef uint_least64_t type;
+    };
+
+    //*************************************************************************
+    // Determine the type to hold the number of bits based on the index.
+    //*************************************************************************
+    template <const int index>
+    struct best_fit_int_type;
+
+    //*************************************************************************
+    // Less than or equal to 8 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_int_type<0>
+    {
+      typedef int_least8_t type;
+    };
+
+    //*************************************************************************
+    // 9 to 16 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_int_type<1>
+    {
+      typedef int_least16_t type;
+    };
+
+    //*************************************************************************
+    // 17 to 31 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_int_type<2>
+    {
+      typedef int_least32_t type;
+    };
+
+    //*************************************************************************
+    // Greater than 32 bits.
+    //*************************************************************************
+    template <>
+    struct best_fit_int_type<3>
+    {
+      typedef int_least64_t type;
+    };
+  }
+
+  //***************************************************************************
+  /// Template to determine the smallest unsigned int type that can contain a 
+  /// value with the specified number of bits.
+  /// Defines 'type' which is the type of the smallest unsigned integer.
+  ///\ingroup smallest
+  //***************************************************************************
+  template <const size_t NBITS>
+  struct smallest_uint_for_bits
+  {
+  private:
+    
+    // Determines the index of the best unsigned type for the required number of bits.
+    static const int TYPE_INDEX = ((NBITS >  8) ? 1 : 0) + 
+                                  ((NBITS > 16) ? 1 : 0) +
+                                  ((NBITS > 32) ? 1 : 0);
+
+  public:
+
+    typedef typename __private_smallest__::best_fit_uint_type<TYPE_INDEX>::type type;
+  };
+
+  //***************************************************************************
+  /// Template to determine the smallest signed int type that can contain a 
+  /// value with the specified number of bits.
+  /// Defines 'type' which is the type of the smallest signed integer.
+  ///\ingroup smallest
+  //***************************************************************************
+  template <const size_t NBITS>
+  struct smallest_int_for_bits
+  {
+  private:
+
+    // Determines the index of the best unsigned type for the required number of bits.
+    static const int TYPE_INDEX = ((NBITS >  8) ? 1 : 0) +
+                                  ((NBITS > 16) ? 1 : 0) +
+                                  ((NBITS > 32) ? 1 : 0);
+
+  public:
+
+    typedef typename __private_smallest__::best_fit_int_type<TYPE_INDEX>::type type;
+  };
+
+  //***************************************************************************
+  /// Template to determine the smallest unsigned int type that can contain the
+  /// specified unsigned value.
+  /// Defines 'type' which is the type of the smallest unsigned integer.
+  ///\ingroup smallest
+  //***************************************************************************
+  template <const uintmax_t VALUE>
+  struct smallest_uint_for_value
+  {
+  private:
+
+    // Determines the index of the best unsigned type for the required value.
+    static const int TYPE_INDEX = ((VALUE > UINT_LEAST8_MAX)  ? 1 : 0) +
+                                  ((VALUE > UINT16_MAX) ? 1 : 0) + 
+                                  ((VALUE > UINT32_MAX) ? 1 : 0);
+
+  public:
+
+    typedef typename __private_smallest__::best_fit_uint_type<TYPE_INDEX>::type type;
+  };
+
+  //***************************************************************************
+  /// Template to determine the smallest int type that can contain the
+  /// specified signed value.
+  /// Defines 'type' which is the type of the smallest signed integer.
+  ///\ingroup smallest
+  //***************************************************************************
+  template <const intmax_t VALUE>
+  struct smallest_int_for_value
+  {
+  private:
+
+    // Determines the index of the best signed type for the required value.
+    static const int TYPE_INDEX = (((VALUE > INT_LEAST8_MAX)  || (VALUE < INT_LEAST8_MIN))  ? 1 : 0) + 
+                                  (((VALUE > INT16_MAX) || (VALUE < INT16_MIN)) ? 1 : 0) +
+                                  (((VALUE > INT32_MAX) || (VALUE < INT32_MIN)) ? 1 : 0);
+
+  public:
+
+    typedef typename __private_smallest__::best_fit_int_type<TYPE_INDEX>::type type;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sqrt.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,61 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_SQRT__
+#define __ETL_SQRT__
+
+#include <stddef.h>
+
+#include "platform.h"
+#include "type_traits.h"
+#include "constant.h"
+
+namespace etl 
+{
+  //***************************************************************************
+  /// Calculates the smallest value that, when squared, will be not greater than VALUE.
+  //***************************************************************************
+  template <const size_t VALUE, const size_t I = 1>
+  struct sqrt
+  {
+    typedef typename etl::conditional<((I * I) > VALUE), 
+                                      etl::constant<intmax_t, I - 1>,
+                                      etl::sqrt<VALUE, I + 1> >::type type;
+
+    enum value_type
+    {
+      // Recursive definition.
+      value = type::value
+    };
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stack.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,492 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove, Mark Kitson
+
+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 __ETL_STACK__
+#define __ETL_STACK__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+
+#include "platform.h"
+#include "container.h"
+#include "alignment.h"
+#include "array.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "debug_count.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+
+#define ETL_FILE "15"
+
+//*****************************************************************************
+///\defgroup stack stack
+/// A Last-in / first-out stack with the capacity defined at compile time,
+/// written in the STL style.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  ///\ingroup stack
+  /// The base class for stack exceptions.
+  //***************************************************************************
+  class stack_exception : public exception
+  {
+  public:
+
+    stack_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup stack
+  /// The exception thrown when the stack is full.
+  //***************************************************************************
+  class stack_full : public stack_exception
+  {
+  public:
+
+    stack_full(string_type file_name_, numeric_type line_number_)
+      : stack_exception(ETL_ERROR_TEXT("stack:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup stack
+  /// The exception thrown when the stack is empty.
+  //***************************************************************************
+  class stack_empty : public stack_exception
+  {
+  public:
+
+    stack_empty(string_type file_name_, numeric_type line_number_)
+      : stack_exception(ETL_ERROR_TEXT("stack:empty", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup stack
+  /// A fixed capacity stack written in the STL style.
+  /// \warntopg This stack cannot be used for concurrent access from multiple threads.
+  //***************************************************************************
+  class stack_base
+  {
+  public:
+
+    typedef size_t size_type; ///< The type used for determining the size of stack.
+
+    //*************************************************************************
+    /// Checks to see if the stack is empty.
+    /// \return <b>true</b> if the stack is empty, otherwise <b>false</b>
+    //*************************************************************************
+    bool empty() const
+    {
+      return current_size == 0;
+    }
+
+    //*************************************************************************
+    /// Checks to see if the stack is full.
+    /// \return <b>true</b> if the stack is full, otherwise <b>false</b>
+    //*************************************************************************
+    bool full() const
+    {
+      return current_size == CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the current number of items top the stack.
+    //*************************************************************************
+    size_type size() const
+    {
+      return current_size;
+    }
+
+    //*************************************************************************
+    /// Returns the maximum number of items that can be stacked.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return max_size() - size();
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// The constructor that is called from derived classes.
+    //*************************************************************************
+    stack_base(size_type max_size_)
+      : top_index(0),
+        current_size(0),
+        CAPACITY(max_size_)
+    {
+    }
+
+    //*************************************************************************
+    /// Increments the indexes value to record a stack addition.
+    //*************************************************************************
+    void add_in()
+    {
+      top_index = current_size++;
+      ++construct_count;
+    }
+
+    //*************************************************************************
+    /// Decrements the indexes value to record a queue deletion.
+    //*************************************************************************
+    void del_out()
+    {
+      --top_index;
+      --current_size;
+      --construct_count;
+    }
+
+    size_type top_index;              ///< The index of the top of the stack.
+    size_type current_size;           ///< The number of items in the stack.
+    const size_type CAPACITY;         ///< The maximum number of items in the stack.
+    etl::debug_count construct_count; ///< For internal debugging purposes.
+  };
+
+  //***************************************************************************
+  ///\ingroup stack
+  ///\brief This is the base for all stacks that contain a particular type.
+  ///\details Normally a reference to this type will be taken from a derived stack.
+  ///\code
+  /// etl::stack<int, 10> myStack;
+  /// etl::istack<int>& iStack = myStack;
+  ///\endcode
+  /// \warning This stack cannot be used for concurrent access from multiple threads.
+  /// \tparam T The type of value that the stack holds.
+  //***************************************************************************
+  template <typename T>
+  class istack : public etl::stack_base
+  {
+  public:
+
+    typedef T                     value_type;      ///< The type stored in the stack.
+    typedef T&                    reference;       ///< A reference to the type used in the stack.
+    typedef const T&              const_reference; ///< A const reference to the type used in the stack.
+    typedef T*                    pointer;         ///< A pointer to the type used in the stack.
+    typedef const T*              const_pointer;   ///< A const pointer to the type used in the stack.
+    typedef stack_base::size_type size_type;       ///< The type used for determining the size of the stack.
+
+  private:
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+    typedef typename etl::stack_base              base_t;
+
+  public:
+
+    //*************************************************************************
+    /// Gets a reference to the value at the top of the stack.<br>
+    /// \return A reference to the value at the top of the stack.
+    //*************************************************************************
+    reference top()
+    {
+      return p_buffer[top_index];
+    }
+
+    //*************************************************************************
+    /// Adds a value to the stack.
+    /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full.
+    ///\param value The value to push to the stack.
+    //*************************************************************************
+    void push(parameter_t value)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(stack_full));
+#endif
+      base_t::add_in();
+      ::new (&p_buffer[top_index]) T(value);
+    }
+
+    //*************************************************************************
+    /// Constructs a value in the stack place'.
+    /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full.
+    ///\param value The value to push to the stack.
+    //*************************************************************************
+    template <typename T1>
+    void emplace(const T1& value1)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(stack_full));
+#endif
+      base_t::add_in();
+      ::new (&p_buffer[top_index]) T(value1);
+    }
+
+    //*************************************************************************
+    /// Constructs a value in the stack place'.
+    /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full.
+    ///\param value The value to push to the stack.
+    //*************************************************************************
+    template <typename T1, typename T2>
+    void emplace(const T1& value1, const T2& value2)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(stack_full));
+#endif
+      base_t::add_in();
+      ::new (&p_buffer[top_index]) T(value1, value2);
+    }
+
+    //*************************************************************************
+    /// Constructs a value in the stack place'.
+    /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full.
+    ///\param value The value to push to the stack.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3>
+    void emplace(const T1& value1, const T2& value2, const T3& value3)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(stack_full));
+#endif
+      base_t::add_in();
+      ::new (&p_buffer[top_index]) T(value1, value2, value3);
+    }
+
+    //*************************************************************************
+    /// Constructs a value in the stack place'.
+    /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full.
+    ///\param value The value to push to the stack.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    void emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(stack_full));
+#endif
+      base_t::add_in();
+      ::new (&p_buffer[top_index]) T(value1, value2, value3, value4);
+    }
+
+    //*************************************************************************
+    /// Allows a possibly more efficient 'push' by moving to the next input value
+    /// and returning a reference to it.
+    /// This may eliminate a copy by allowing direct construction in-place.<br>
+    /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full.
+    /// \return A reference to the position to 'push' to.
+    //*************************************************************************
+    reference push()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!full(), ETL_ERROR(stack_full));
+#endif
+      base_t::add_in();
+
+      return p_buffer[top_index];
+    }
+
+    //*************************************************************************
+    /// Gets a const reference to the value at the top of the stack.<br>
+    /// \return A const reference to the value at the top of the stack.
+    //*************************************************************************
+    const_reference top() const
+    {
+      return p_buffer[top_index];
+    }
+
+    //*************************************************************************
+    /// Clears the stack to the empty state.
+    //*************************************************************************
+    void clear()
+    {
+      while (current_size > 0)
+      {
+        p_buffer[top_index].~T();
+        base_t::del_out();
+      }
+    }
+
+    //*************************************************************************
+    /// Removes the oldest item from the top of the stack.
+    //*************************************************************************
+    void pop()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(!empty(), ETL_ERROR(stack_empty));
+#endif
+      p_buffer[top_index].~T();
+      base_t::del_out();
+    }
+
+    //*************************************************************************
+    /// Removes the oldest item from the top of the stack and puts it in the destination.
+    //*************************************************************************
+    void pop_into(reference destination)
+    {
+      destination = top();
+      pop();
+    }
+
+    //*************************************************************************
+    /// Removes the oldest item from the top of the stack and pushes it to the
+    /// destination container.
+    /// NOTE: The destination must support a push(T) member function.
+    //*************************************************************************
+    template <typename TContainer>
+    void pop_into(TContainer& destination)
+    {
+      destination.push(top());
+      pop();
+    }
+
+    //*************************************************************************
+    /// Reverses the stack.
+    //*************************************************************************
+    void reverse()
+    {
+      std::reverse(p_buffer, p_buffer + current_size);
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    istack& operator = (const istack& rhs)
+    {
+      if (&rhs != this)
+      {
+        clear();
+        clone(rhs);
+      }
+
+      return *this;
+    }
+
+  protected:
+
+    //*************************************************************************
+    /// Make this a clone of the supplied stack
+    //*************************************************************************
+    void clone(const istack& other)
+    {
+      size_t index = 0;
+
+      for (size_t i = 0; i < other.size(); ++i)
+      {
+        push(other.p_buffer[index++]);
+      }
+    }
+
+    //*************************************************************************
+    /// The constructor that is called from derived classes.
+    //*************************************************************************
+    istack(T* p_buffer_, size_type max_size_)
+      : stack_base(max_size_),
+        p_buffer(p_buffer_)
+    {
+    }
+
+  private:
+
+    // Disable copy construction.
+    istack(const istack&);
+
+    T* p_buffer; ///< The internal buffer.
+  };
+
+  //***************************************************************************
+  ///\ingroup stack
+  /// A fixed capacity stack.
+  /// This stack does not suppo7rt concurrent access by different threads.
+  /// \tparam T        The type this stack should support.
+  /// \tparam MAX_SIZE The maximum capacity of the stack.
+  //***************************************************************************
+  template <typename T, const size_t SIZE>
+  class stack : public etl::istack<T>
+  {
+  public:
+
+    static const size_t MAX_SIZE = SIZE;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    stack()
+      : etl::istack<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor
+    //*************************************************************************
+    stack(const stack& rhs)
+      : etl::istack<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
+    {
+      etl::istack<T>::clone(rhs);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~stack()
+    {
+      etl::istack<T>::clear();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    stack& operator = (const stack& rhs)
+    {
+      if (&rhs != this)
+      {
+        etl::istack<T>::clone(rhs);
+      }
+
+      return *this;
+    }
+
+  private:
+
+    /// The unintitialised buffer of T used in the stack.
+    typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[SIZE];
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/static_assert.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,53 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_STATIC_ASSERT__
+#define __ETL_STATIC_ASSERT__
+
+#include "platform.h"
+
+#if (ETL_CPP11_SUPPORTED)
+  #define STATIC_ASSERT(Condition, Message) static_assert(Condition, Message)
+#else
+  template <bool Condition>
+  struct STATIC_ASSERT_FAILED;
+
+  template <>
+  struct STATIC_ASSERT_FAILED<true> {};
+
+  #define ETL_SA1(a,b) a##b
+  #define ETL_SA2(a,b) ETL_SA1(a,b)
+  #define STATIC_ASSERT(Condition, Message) \
+		  enum \
+		  { \
+        ETL_SA2(dummy, __LINE__) = sizeof(STATIC_ASSERT_FAILED<(bool)(Condition)>) \
+	    }
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/string_view.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,876 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_STRING_VIEW__
+#define __ETL_STRING_VIEW__
+
+#include "platform.h"
+#include "memory.h"
+#include "iterator.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "char_traits.h"
+#include "integral_limits.h"
+#include "hash.h"
+
+#include <algorithm>
+
+///\defgroup array array
+/// A wrapper for arrays
+///\ingroup containers
+
+#undef ETL_FILE
+#define ETL_FILE "42"
+
+#ifdef ETL_COMPILER_MICROSOFT
+#undef min
+#undef max
+#endif
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for basic_string_view exceptions.
+  //***************************************************************************
+  class string_view_exception : public exception
+  {
+  public:
+
+    string_view_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup stack
+  /// The exception thrown when the index is out of bounds.
+  //***************************************************************************
+  class string_view_bounds : public string_view_exception
+  {
+  public:
+
+    string_view_bounds(string_type file_name_, numeric_type line_number_)
+      : string_view_exception(ETL_ERROR_TEXT("basic_string_view:bounds", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  ///\ingroup stack
+  /// The exception thrown when the view is uninitialised.
+  //***************************************************************************
+  class string_view_uninitialised : public string_view_exception
+  {
+  public:
+
+    string_view_uninitialised(string_type file_name_, numeric_type line_number_)
+      : string_view_exception(ETL_ERROR_TEXT("basic_string_view:uninitialised", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// String view.
+  //***************************************************************************
+  template <typename T, typename TTraits = etl::char_traits<T> >
+  class basic_string_view
+  {
+  public:
+
+    typedef T                                     value_type;
+    typedef TTraits                               traits_type;
+    typedef std::size_t                           size_type;
+    typedef const T&                              const_reference;
+    typedef const T*                              const_pointer;
+    typedef const T*                              const_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+    enum
+    {
+      npos = etl::integral_limits<size_t>::max
+    };
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    basic_string_view()
+      : mbegin(std::nullptr),
+        mend(std::nullptr)
+    {
+    }
+
+    //*************************************************************************
+    /// Construct from T*.
+    //*************************************************************************
+    basic_string_view(const T* begin_)
+      : mbegin(begin_),
+        mend(begin_ + TTraits::length(begin_))
+    {
+    }
+
+    //*************************************************************************
+    /// Construct from pointer range.
+    //*************************************************************************
+    basic_string_view(const T* begin_, const T* end_)
+      : mbegin(begin_),
+        mend(end_)
+    {
+    }
+
+    //*************************************************************************
+    /// Construct from iterator/size.
+    //*************************************************************************
+    template <typename TSize, typename TDummy = typename etl::enable_if<etl::is_integral<TSize>::value, void>::type>
+    basic_string_view(const T* begin_, TSize size_)
+      : mbegin(begin_),
+        mend(begin_ + size_)
+    {
+    }
+
+    //*************************************************************************
+    /// Copy constructor
+    //*************************************************************************
+    basic_string_view(const basic_string_view& other)
+      : mbegin(other.mbegin),
+        mend(other.mend)
+    {
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the first element.
+    //*************************************************************************
+    const_reference front() const
+    {
+      return *mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the last element.
+    //*************************************************************************
+    const_reference back() const
+    {
+      return *(mend - 1);
+    }
+
+    //*************************************************************************
+    /// Returns a const pointer to the first element of the internal storage.
+    //*************************************************************************
+    const_pointer data() const
+    {
+      return mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the beginning of the array.
+    //*************************************************************************
+    const_iterator begin() const
+    {
+      return mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the beginning of the array.
+    //*************************************************************************
+    const_iterator cbegin() const
+    {
+      return mbegin;
+    }
+
+    //*************************************************************************
+    /// Returns a const iterator to the end of the array.
+    //*************************************************************************
+    const_iterator end() const
+    {
+      return mend;
+    }
+
+    //*************************************************************************
+    // Returns a const iterator to the end of the array.
+    //*************************************************************************
+    const_iterator cend() const
+    {
+      return mend;
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(mend);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the array.
+    //*************************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(mend);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the end of the array.
+    //*************************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(mbegin);
+    }
+
+    //*************************************************************************
+    /// Returns a const reverse iterator to the end of the array.
+    //*************************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(mbegin);
+    }
+
+    //*************************************************************************
+    // Capacity
+    //*************************************************************************
+
+    //*************************************************************************
+    /// Returns <b>true</b> if the array size is zero.
+    //*************************************************************************
+    bool empty() const
+    {
+      return (mbegin == mend);
+    }
+
+    //*************************************************************************
+    /// Returns the size of the array.
+    //*************************************************************************
+    size_t size() const
+    {
+      return (mend - mbegin);
+    }
+
+    //*************************************************************************
+    /// Returns the size of the array.
+    //*************************************************************************
+    size_t length() const
+    {
+      return size();
+    }
+
+    //*************************************************************************
+    /// Returns the maximum possible size of the array.
+    //*************************************************************************
+    size_t max_size() const
+    {
+      return size();
+    }
+
+    //*************************************************************************
+    /// Assign from a view.
+    //*************************************************************************
+    etl::basic_string_view<T, TTraits>& operator=(const etl::basic_string_view<T, TTraits>& other)
+    {
+      mbegin = other.mbegin;
+      mend = other.mend;
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Assign from iterators
+    //*************************************************************************
+    template <typename TIterator,
+              typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type>
+      void assign(TIterator begin_, TIterator end_)
+    {
+      mbegin = etl::addressof(*begin_);
+      mend = etl::addressof(*begin_) + std::distance(begin_, end_);
+    }
+
+    //*************************************************************************
+    /// Assign from iterator and size.
+    //*************************************************************************
+    template <typename TIterator,
+              typename TSize,
+              typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type>
+      void assign(TIterator begin_, TSize size_)
+    {
+      mbegin = etl::addressof(*begin_);
+      mend = etl::addressof(*begin_) + size_;
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the indexed value.
+    //*************************************************************************
+    const_reference operator[](size_t i) const
+    {
+      return mbegin[i];
+    }
+
+    //*************************************************************************
+    /// Returns a const reference to the indexed value.
+    //*************************************************************************
+    const_reference at(size_t i) const
+    {
+      ETL_ASSERT((mbegin != std::nullptr && mend != std::nullptr), ETL_ERROR(string_view_uninitialised));
+      ETL_ASSERT(i < size(), ETL_ERROR(string_view_bounds));
+      return mbegin[i];
+    }
+
+    //*************************************************************************
+    /// Swaps with another basic_string_view.
+    //*************************************************************************
+    void swap(basic_string_view& other)
+    {
+      std::swap(mbegin, other.mbegin);
+      std::swap(mend, other.mend);
+    }
+
+    //*************************************************************************
+    /// Copies characters
+    //*************************************************************************
+    size_type copy(T* destination, size_type count, size_type position = 0) const
+    {
+      size_t n = 0;
+
+      if (position < size())
+      {
+        n = std::min(count, size() - position);
+
+        std::copy(mbegin + position, mbegin + position + n, destination);
+      }
+
+      return n;
+    }
+
+    //*************************************************************************
+    /// Returns a substring
+    //*************************************************************************
+    basic_string_view substr(size_type position = 0, size_type count = npos) const
+    {
+      basic_string_view view;
+
+      if (position < size())
+      {
+        size_t n = std::min(count, size() - position);
+
+        view = basic_string_view(mbegin + position, mbegin + position + n);
+      }
+
+      return view;
+    }
+
+    //*************************************************************************
+    /// Shrinks the view by moving its start forward.
+    //*************************************************************************
+    void remove_prefix(size_type n)
+    {
+      mbegin += n;
+    }
+
+    //*************************************************************************
+    /// Shrinks the view by moving its end backward.
+    //*************************************************************************
+    void remove_suffix(size_type n)
+    {
+      mend -= n;
+    }
+
+    //*************************************************************************
+    /// Compares two views
+    //*************************************************************************
+    int compare(basic_string_view<T, TTraits> view) const
+    {
+      return (*this == view) ? 0 : ((*this > view) ? 1 : -1);
+    }
+
+    int compare(size_type position, size_type count, basic_string_view view) const
+    {
+      return substr(position, count).compare(view);
+    }
+
+    int compare(size_type position1, size_type count1,
+                basic_string_view view,
+                size_type position2, size_type count2) const
+    {
+      return substr(position1, count1).compare(view.substr(position2, count2));
+    }
+
+    int compare(const T* text) const
+    {
+      return compare(etl::basic_string_view<T, TTraits>(text));
+    }
+
+    int compare(size_type position, size_type count, const T* text) const
+    {
+      return substr(position, count).compare(etl::basic_string_view<T, TTraits>(text));
+    }
+
+    int compare(size_type position, size_type count1, const T* text, size_type count2) const
+    {
+      return substr(position, count1).compare(etl::basic_string_view<T, TTraits>(text, count2));
+    }
+
+    //*************************************************************************
+    /// Checks if the string view starts with the given prefix
+    //*************************************************************************
+    bool starts_with(etl::basic_string_view<T, TTraits> view) const
+    {
+      return (size() >= view.size()) &&
+             (compare(0, view.size(), view) == 0);
+    }
+
+    bool starts_with(T c) const
+    {
+      return !empty() && (front() == c);
+    }
+
+    bool starts_with(const T* text) const
+    {
+      size_t lengthtext = TTraits::length(text);
+
+      return (size() >= lengthtext) &&
+             (compare(0, lengthtext, text) == 0);
+    }
+
+    //*************************************************************************
+    /// Checks if the string view ends with the given suffix
+    //*************************************************************************
+    bool ends_with(etl::basic_string_view<T, TTraits> view) const
+    {
+      return (size() >= view.size()) &&
+             (compare(size() - view.size(), npos, view) == 0);
+    }
+
+    bool ends_with(T c) const
+    {
+      return !empty() && (back() == c);
+    }
+
+    bool ends_with(const T* text) const
+    {
+      size_t lengthtext = TTraits::length(text);
+      size_t lengthview = size();
+
+      return (lengthview >= lengthtext) &&
+             (compare(lengthview - lengthtext, lengthtext, text) == 0);
+    }
+
+    //*************************************************************************
+    /// Find characters in the view
+    //*************************************************************************
+    size_type find(etl::basic_string_view<T, TTraits> view, size_type position = 0) const
+    {
+      if ((size() < view.size()))
+      {
+        return npos;
+      }
+
+      const_iterator iposition = std::search(begin() + position, end(), view.begin(), view.end());
+
+      if (iposition == end())
+      {
+        return npos;
+      }
+      else
+      {
+        return std::distance(begin(), iposition);
+      }
+    }
+
+    size_type find(T c, size_type position = 0) const
+    {
+      return find(etl::basic_string_view<T, TTraits>(&c, 1), position);
+    }
+
+    size_type find(const T* text, size_type position, size_type count) const
+    {
+      return find(etl::basic_string_view<T, TTraits>(text, count), position);
+    }
+
+    size_type find(const T* text, size_type position = 0) const
+    {
+      return find(etl::basic_string_view<T, TTraits>(text), position);
+    }
+
+    //*************************************************************************
+    /// Find the last occurrence of a substring
+    //*************************************************************************
+    size_type rfind(etl::basic_string_view<T, TTraits> view, size_type position = npos) const
+    {
+      if ((size() < view.size()))
+      {
+        return npos;
+      }
+
+      position = std::min(position, size());
+
+      const_iterator iposition = std::find_end(begin(),
+                                               begin() + position,
+                                               view.begin(),
+                                               view.end());
+
+      if (iposition == end())
+      {
+        return npos;
+      }
+      else
+      {
+        return std::distance(begin(), iposition);
+      }
+    }
+
+    size_type rfind(T c, size_type position = npos) const
+    {
+      return rfind(etl::basic_string_view<T, TTraits>(&c, 1), position);
+    }
+
+    size_type rfind(const T* text, size_type position, size_type count) const
+    {
+      return rfind(etl::basic_string_view<T, TTraits>(text, count), position);
+    }
+
+    size_type rfind(const T* text, size_type position = npos) const
+    {
+      return rfind(etl::basic_string_view<T, TTraits>(text), position);
+    }
+
+    //*************************************************************************
+    ///  Find first occurrence of characters
+    //*************************************************************************
+    size_type find_first_of(etl::basic_string_view<T, TTraits> view, size_type position = 0) const
+    {
+      const size_t lengthtext = size();
+
+      if (position < lengthtext)
+      {
+        for (size_t i = position; i < lengthtext; ++i)
+        {
+          const size_t lengthview = view.size();
+
+          for (size_t j = 0; j < lengthview; ++j)
+          {
+            if (mbegin[i] == view[j])
+            {
+              return i;
+            }
+          }
+        }
+      }
+
+      return npos;
+    }
+
+    size_type find_first_of(T c, size_type position = 0) const
+    {
+      return find_first_of(etl::basic_string_view<T, TTraits>(&c, 1), position);
+    }
+
+    size_type find_first_of(const T* text, size_type position, size_type count) const
+    {
+      return find_first_of(etl::basic_string_view<T, TTraits>(text, count), position);
+    }
+
+    size_type find_first_of(const T* text, size_type position = 0) const
+    {
+      return find_first_of(etl::basic_string_view<T, TTraits>(text), position);
+    }
+
+    //*************************************************************************
+    /// Find last occurrence of characters
+    //*************************************************************************
+    size_type find_last_of(etl::basic_string_view<T, TTraits> view, size_type position = npos) const
+    {
+      if (empty())
+      {
+        return npos;
+      }
+
+      position = std::min(position, size() - 1);
+
+      const_reverse_iterator it = rbegin() + size() - position - 1;
+
+      while (it != rend())
+      {
+        const size_t viewlength = view.size();
+
+        for (size_t j = 0; j < viewlength; ++j)
+        {
+          if (mbegin[position] == view[j])
+          {
+            return position;
+          }
+        }
+
+        ++it;
+        --position;
+      }
+
+      return npos;
+    }
+
+    size_type find_last_of(T c, size_type position = npos) const
+    {
+      return find_last_of(etl::basic_string_view<T, TTraits>(&c, 1), position);;
+    }
+
+    size_type find_last_of(const T* text, size_type position, size_type count) const
+    {
+      return find_last_of(etl::basic_string_view<T, TTraits>(text, count), position);;
+    }
+
+    size_type find_last_of(const T* text, size_type position = npos) const
+    {
+      return find_last_of(etl::basic_string_view<T, TTraits>(text), position);;
+    }
+
+    //*************************************************************************
+    /// Find first absence of characters
+    //*************************************************************************
+    size_type find_first_not_of(etl::basic_string_view<T, TTraits> view, size_type position = 0) const
+    {
+      const size_t lengthtext = size();
+
+      if (position < lengthtext)
+      {
+        for (size_t i = position; i < lengthtext; ++i)
+        {
+          bool found = false;
+
+          const size_t viewlength = view.size();
+
+          for (size_t j = 0; j < viewlength; ++j)
+          {
+            if (mbegin[i] == view[j])
+            {
+              found = true;
+            }
+          }
+
+          if (!found)
+          {
+            return i;
+          }
+        }
+      }
+
+      return npos;
+    }
+
+    size_type find_first_not_of(T c, size_type position = 0) const
+    {
+      return find_first_not_of(etl::basic_string_view<T, TTraits>(&c, 1), position);
+    }
+
+    size_type find_first_not_of(const T* text, size_type position, size_type count) const
+    {
+      return find_first_not_of(etl::basic_string_view<T, TTraits>(text, count), position);
+    }
+
+    size_type find_first_not_of(const T* text, size_type position = 0) const
+    {
+      return find_first_not_of(etl::basic_string_view<T, TTraits>(text), position);
+    }
+
+    //*************************************************************************
+    /// Find last absence of characters
+    //*************************************************************************
+    size_type find_last_not_of(etl::basic_string_view<T, TTraits> view, size_type position = npos) const
+    {
+      if (empty())
+      {
+        return npos;
+      }
+
+      position = std::min(position, size() - 1);
+
+      const_reverse_iterator it = rbegin() + size() - position - 1;
+
+      while (it != rend())
+      {
+        bool found = false;
+
+        const size_t viewlength = view.size();
+
+        for (size_t j = 0; j < viewlength; ++j)
+        {
+          if (mbegin[position] == view[j])
+          {
+            found = true;
+          }
+        }
+
+        if (!found)
+        {
+          return position;
+        }
+
+        ++it;
+        --position;
+      }
+
+      return npos;
+    }
+
+    size_type find_last_not_of(T c, size_type position = npos) const
+    {
+      return find_last_not_of(etl::basic_string_view<T, TTraits>(&c, 1), position);;
+    }
+
+    size_type find_last_not_of(const T* text, size_type position, size_type count) const
+    {
+      return find_last_not_of(etl::basic_string_view<T, TTraits>(text, count), position);;
+    }
+
+    size_type find_last_not_of(const T* text, size_type position = npos) const
+    {
+      return find_last_not_of(etl::basic_string_view<T, TTraits>(text), position);;
+    }
+
+    //*************************************************************************
+    /// Equality for array views.
+    //*************************************************************************
+    friend bool operator == (const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs)
+    {
+      return (lhs.size() == rhs.size()) &&
+        std::equal(lhs.begin(), lhs.end(), rhs.begin());
+    }
+
+    //*************************************************************************
+    /// Inequality for array views.
+    //*************************************************************************
+    friend bool operator != (const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs)
+    {
+      return !(lhs == rhs);
+    }
+
+    //*************************************************************************
+    /// Less-than for array views.
+    //*************************************************************************
+    friend bool operator < (const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs)
+    {
+      return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+    }
+
+    //*************************************************************************
+    /// Greater-than for array views.
+    //*************************************************************************
+    friend bool operator > (const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs)
+    {
+      return rhs < lhs;
+    }
+
+    //*************************************************************************
+    /// Less-than-equal for array views.
+    //*************************************************************************
+    friend bool operator <= (const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs)
+    {
+      return !(lhs > rhs);
+    }
+
+    //*************************************************************************
+    /// Greater-than-equal for array views.
+    //*************************************************************************
+    friend bool operator >= (const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs)
+    {
+      return !(lhs < rhs);
+    }
+
+  private:
+
+    const T* mbegin;
+    const T* mend;
+  };
+
+  typedef etl::basic_string_view<char>     string_view;
+  typedef etl::basic_string_view<wchar_t>  wstring_view;
+  typedef etl::basic_string_view<char16_t> u16string_view;
+  typedef etl::basic_string_view<char32_t> u32string_view;
+
+  //*************************************************************************
+  /// Hash function.
+  //*************************************************************************
+#if ETL_8BIT_SUPPORT
+  template <>
+  struct hash<etl::string_view>
+  {
+    size_t operator()(const etl::string_view& text) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]),
+                                                         reinterpret_cast<const uint8_t*>(&text[text.size()]));
+    }
+  };
+
+  template <>
+  struct hash<etl::wstring_view>
+  {
+    size_t operator()(const etl::wstring_view& text) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]),
+                                                         reinterpret_cast<const uint8_t*>(&text[text.size()]));
+    }
+  };
+
+  template <>
+  struct hash<etl::u16string_view>
+  {
+    size_t operator()(const etl::u16string_view& text) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]),
+                                                         reinterpret_cast<const uint8_t*>(&text[text.size()]));
+    }
+  };
+
+  template <>
+  struct hash<etl::u32string_view>
+  {
+    size_t operator()(const etl::u32string_view& text) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]),
+                                                         reinterpret_cast<const uint8_t*>(&text[text.size()]));
+    }
+  };
+#endif
+}
+
+//*************************************************************************
+/// Swaps the values.
+//*************************************************************************
+template <typename T, typename TTraits = etl::char_traits<T>>
+void swap(etl::basic_string_view<T, TTraits>& lhs, etl::basic_string_view<T, TTraits>& rhs)
+{
+  lhs.swap(rhs);
+}
+
+#ifdef ETL_COMPILER_MICROSOFT
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#undef ETL_FILE
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/task.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,127 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_TASK__
+#define __ETL_TASK__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "error_handler.h"
+#include "exception.h"
+
+#undef ETL_FILE
+#define ETL_FILE "37"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Base exception class for task.
+  //***************************************************************************
+  class task_exception : public etl::exception
+  {
+  public:
+
+    task_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  typedef uint_least8_t task_priority_t;
+
+  //***************************************************************************
+  /// Scheduler.
+  //***************************************************************************
+  class task
+  {
+  public:
+
+    //*******************************************
+    /// Constructor.
+    //*******************************************
+    task(task_priority_t priority)
+      : task_running(true),
+        task_priority(priority)
+    {
+    }
+
+    //*******************************************
+    /// Destructor.
+    //*******************************************
+    virtual ~task()
+    {
+    }
+
+    //*******************************************
+    /// Called to check if the task has work.
+    /// Returns a score as to the amount of work it has to do.
+    //*******************************************
+    virtual uint32_t task_request_work() const = 0;
+
+    //*******************************************
+    /// Called to get the task to do work.
+    //*******************************************
+    virtual void task_process_work() = 0;
+
+    //*******************************************
+    /// Set the running state for the task.
+    //*******************************************
+    void set_task_running(bool task_running_)
+    {
+      task_running = task_running_;
+    }
+
+    //*******************************************
+    /// Get the running state for the task.
+    //*******************************************
+    bool task_is_running() const
+    {
+      return task_running;
+    }
+
+    //*******************************************
+    /// Get the priority of the task.
+    /// Higher value = higher priority.
+    //*******************************************
+    etl::task_priority_t get_task_priority() const
+    {
+      return task_priority;
+    }
+
+  private:
+
+    bool task_running;
+    etl::task_priority_t task_priority;
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/temp.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,898 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_TYPE_LOOKUP__
+#define __ETL_TYPE_LOOKUP__
+
+#undef ETL_FILE
+#define ETL_FILE "41"
+
+#if 0
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+#endif
+
+//***************************************************************************
+// This file has been auto generated. Do not edit this file.
+//***************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  template <const size_t T1ID,      typename T1,
+            const size_t T2ID  = 0, typename T2  = void,
+            const size_t T3ID  = 0, typename T3  = void,
+            const size_t T4ID  = 0, typename T4  = void,
+            const size_t T5ID  = 0, typename T5  = void,
+            const size_t T6ID  = 0, typename T6  = void,
+            const size_t T7ID  = 0, typename T7  = void,
+            const size_t T8ID  = 0, typename T8  = void,
+            const size_t T9ID  = 0, typename T9  = void,
+            const size_t T10ID  = 0, typename T10  = void,
+            const size_t T11ID  = 0, typename T11  = void,
+            const size_t T12ID  = 0, typename T12  = void,
+            const size_t T13ID  = 0, typename T13  = void,
+            const size_t T14ID  = 0, typename T14  = void,
+            const size_t T15ID  = 0, typename T15  = void,
+            const size_t T16ID  = 0, typename T16  = void>
+  struct type_lookup
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            typename etl::conditional<ID == T5ID,  T5,
+            typename etl::conditional<ID == T6ID,  T6,
+            typename etl::conditional<ID == T7ID,  T7,
+            typename etl::conditional<ID == T8ID,  T8,
+            typename etl::conditional<ID == T9ID,  T9,
+            typename etl::conditional<ID == T10ID,  T10,
+            typename etl::conditional<ID == T11ID,  T11,
+            typename etl::conditional<ID == T12ID,  T12,
+            typename etl::conditional<ID == T13ID,  T13,
+            typename etl::conditional<ID == T14ID,  T14,
+            typename etl::conditional<ID == T15ID,  T15,
+            typename etl::conditional<ID == T16ID,  T16,
+            void>::type>::type>::type>::type>::type>::type>::type>
+                 ::type>::type>::type>::type>::type>::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          etl::is_same<T, T5>::value ? T5ID :
+          etl::is_same<T, T6>::value ? T6ID :
+          etl::is_same<T, T7>::value ? T7ID :
+          etl::is_same<T, T8>::value ? T8ID :
+          etl::is_same<T, T9>::value ? T9ID :
+          etl::is_same<T, T10>::value ? T10ID :
+          etl::is_same<T, T11>::value ? T11ID :
+          etl::is_same<T, T12>::value ? T12ID :
+          etl::is_same<T, T13>::value ? T13ID :
+          etl::is_same<T, T14>::value ? T14ID :
+          etl::is_same<T, T15>::value ? T15ID :
+          etl::is_same<T, T16>::value ? T16ID :
+          UNKNOWN
+      };
+    };
+  };
+
+    //*************************************************************************
+
+  //***************************************************************************
+  // Specialisation for 15 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3,
+            const size_t T4ID, typename T4,
+            const size_t T5ID, typename T5,
+            const size_t T6ID, typename T6,
+            const size_t T7ID, typename T7,
+            const size_t T8ID, typename T8,
+            const size_t T9ID, typename T9,
+            const size_t T10ID, typename T10,
+            const size_t T11ID, typename T11,
+            const size_t T12ID, typename T12,
+            const size_t T13ID, typename T13,
+            const size_t T14ID, typename T14,
+            const size_t T15ID, typename T15>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, 
+                     T9ID, T9, T10ID, T10, T11ID, T11, T12ID, T12, T13ID, T13, T14ID, T14, T15ID, T15, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            typename etl::conditional<ID == T5ID,  T5,
+            typename etl::conditional<ID == T6ID,  T6,
+            typename etl::conditional<ID == T7ID,  T7,
+            typename etl::conditional<ID == T8ID,  T8,
+            typename etl::conditional<ID == T9ID,  T9,
+            typename etl::conditional<ID == T10ID,  T10,
+            typename etl::conditional<ID == T11ID,  T11,
+            typename etl::conditional<ID == T12ID,  T12,
+            typename etl::conditional<ID == T13ID,  T13,
+            typename etl::conditional<ID == T14ID,  T14,
+            typename etl::conditional<ID == T15ID,  T15,
+            void>::type>::type>::type>::type>::type>::type>::type>
+                 ::type>::type>::type>::type>::type>::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          etl::is_same<T, T5>::value ? T5ID :
+          etl::is_same<T, T6>::value ? T6ID :
+          etl::is_same<T, T7>::value ? T7ID :
+          etl::is_same<T, T8>::value ? T8ID :
+          etl::is_same<T, T9>::value ? T9ID :
+          etl::is_same<T, T10>::value ? T10ID :
+          etl::is_same<T, T11>::value ? T11ID :
+          etl::is_same<T, T12>::value ? T12ID :
+          etl::is_same<T, T13>::value ? T13ID :
+          etl::is_same<T, T14>::value ? T14ID :
+          etl::is_same<T, T15>::value ? T15ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 14 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3,
+            const size_t T4ID, typename T4,
+            const size_t T5ID, typename T5,
+            const size_t T6ID, typename T6,
+            const size_t T7ID, typename T7,
+            const size_t T8ID, typename T8,
+            const size_t T9ID, typename T9,
+            const size_t T10ID, typename T10,
+            const size_t T11ID, typename T11,
+            const size_t T12ID, typename T12,
+            const size_t T13ID, typename T13,
+            const size_t T14ID, typename T14>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, 
+                     T9ID, T9, T10ID, T10, T11ID, T11, T12ID, T12, T13ID, T13, T14ID, T14, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            typename etl::conditional<ID == T5ID,  T5,
+            typename etl::conditional<ID == T6ID,  T6,
+            typename etl::conditional<ID == T7ID,  T7,
+            typename etl::conditional<ID == T8ID,  T8,
+            typename etl::conditional<ID == T9ID,  T9,
+            typename etl::conditional<ID == T10ID,  T10,
+            typename etl::conditional<ID == T11ID,  T11,
+            typename etl::conditional<ID == T12ID,  T12,
+            typename etl::conditional<ID == T13ID,  T13,
+            typename etl::conditional<ID == T14ID,  T14,
+            void>::type>::type>::type>::type>::type>::type>::type>
+                 ::type>::type>::type>::type>::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          etl::is_same<T, T5>::value ? T5ID :
+          etl::is_same<T, T6>::value ? T6ID :
+          etl::is_same<T, T7>::value ? T7ID :
+          etl::is_same<T, T8>::value ? T8ID :
+          etl::is_same<T, T9>::value ? T9ID :
+          etl::is_same<T, T10>::value ? T10ID :
+          etl::is_same<T, T11>::value ? T11ID :
+          etl::is_same<T, T12>::value ? T12ID :
+          etl::is_same<T, T13>::value ? T13ID :
+          etl::is_same<T, T14>::value ? T14ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 13 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3,
+            const size_t T4ID, typename T4,
+            const size_t T5ID, typename T5,
+            const size_t T6ID, typename T6,
+            const size_t T7ID, typename T7,
+            const size_t T8ID, typename T8,
+            const size_t T9ID, typename T9,
+            const size_t T10ID, typename T10,
+            const size_t T11ID, typename T11,
+            const size_t T12ID, typename T12,
+            const size_t T13ID, typename T13>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, 
+                     T9ID, T9, T10ID, T10, T11ID, T11, T12ID, T12, T13ID, T13, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            typename etl::conditional<ID == T5ID,  T5,
+            typename etl::conditional<ID == T6ID,  T6,
+            typename etl::conditional<ID == T7ID,  T7,
+            typename etl::conditional<ID == T8ID,  T8,
+            typename etl::conditional<ID == T9ID,  T9,
+            typename etl::conditional<ID == T10ID,  T10,
+            typename etl::conditional<ID == T11ID,  T11,
+            typename etl::conditional<ID == T12ID,  T12,
+            typename etl::conditional<ID == T13ID,  T13,
+            void>::type>::type>::type>::type>::type>::type>::type>
+                 ::type>::type>::type>::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          etl::is_same<T, T5>::value ? T5ID :
+          etl::is_same<T, T6>::value ? T6ID :
+          etl::is_same<T, T7>::value ? T7ID :
+          etl::is_same<T, T8>::value ? T8ID :
+          etl::is_same<T, T9>::value ? T9ID :
+          etl::is_same<T, T10>::value ? T10ID :
+          etl::is_same<T, T11>::value ? T11ID :
+          etl::is_same<T, T12>::value ? T12ID :
+          etl::is_same<T, T13>::value ? T13ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 12 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3,
+            const size_t T4ID, typename T4,
+            const size_t T5ID, typename T5,
+            const size_t T6ID, typename T6,
+            const size_t T7ID, typename T7,
+            const size_t T8ID, typename T8,
+            const size_t T9ID, typename T9,
+            const size_t T10ID, typename T10,
+            const size_t T11ID, typename T11,
+            const size_t T12ID, typename T12>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, 
+                     T9ID, T9, T10ID, T10, T11ID, T11, T12ID, T12, 0, void, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            typename etl::conditional<ID == T5ID,  T5,
+            typename etl::conditional<ID == T6ID,  T6,
+            typename etl::conditional<ID == T7ID,  T7,
+            typename etl::conditional<ID == T8ID,  T8,
+            typename etl::conditional<ID == T9ID,  T9,
+            typename etl::conditional<ID == T10ID,  T10,
+            typename etl::conditional<ID == T11ID,  T11,
+            typename etl::conditional<ID == T12ID,  T12,
+            void>::type>::type>::type>::type>::type>::type>::type>
+                 ::type>::type>::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          etl::is_same<T, T5>::value ? T5ID :
+          etl::is_same<T, T6>::value ? T6ID :
+          etl::is_same<T, T7>::value ? T7ID :
+          etl::is_same<T, T8>::value ? T8ID :
+          etl::is_same<T, T9>::value ? T9ID :
+          etl::is_same<T, T10>::value ? T10ID :
+          etl::is_same<T, T11>::value ? T11ID :
+          etl::is_same<T, T12>::value ? T12ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 11 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3,
+            const size_t T4ID, typename T4,
+            const size_t T5ID, typename T5,
+            const size_t T6ID, typename T6,
+            const size_t T7ID, typename T7,
+            const size_t T8ID, typename T8,
+            const size_t T9ID, typename T9,
+            const size_t T10ID, typename T10,
+            const size_t T11ID, typename T11>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, 
+                     T9ID, T9, T10ID, T10, T11ID, T11, 0, void, 0, void, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            typename etl::conditional<ID == T5ID,  T5,
+            typename etl::conditional<ID == T6ID,  T6,
+            typename etl::conditional<ID == T7ID,  T7,
+            typename etl::conditional<ID == T8ID,  T8,
+            typename etl::conditional<ID == T9ID,  T9,
+            typename etl::conditional<ID == T10ID,  T10,
+            typename etl::conditional<ID == T11ID,  T11,
+            void>::type>::type>::type>::type>::type>::type>::type>
+                 ::type>::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          etl::is_same<T, T5>::value ? T5ID :
+          etl::is_same<T, T6>::value ? T6ID :
+          etl::is_same<T, T7>::value ? T7ID :
+          etl::is_same<T, T8>::value ? T8ID :
+          etl::is_same<T, T9>::value ? T9ID :
+          etl::is_same<T, T10>::value ? T10ID :
+          etl::is_same<T, T11>::value ? T11ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 10 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3,
+            const size_t T4ID, typename T4,
+            const size_t T5ID, typename T5,
+            const size_t T6ID, typename T6,
+            const size_t T7ID, typename T7,
+            const size_t T8ID, typename T8,
+            const size_t T9ID, typename T9,
+            const size_t T10ID, typename T10>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, 
+                     T9ID, T9, T10ID, T10, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            typename etl::conditional<ID == T5ID,  T5,
+            typename etl::conditional<ID == T6ID,  T6,
+            typename etl::conditional<ID == T7ID,  T7,
+            typename etl::conditional<ID == T8ID,  T8,
+            typename etl::conditional<ID == T9ID,  T9,
+            typename etl::conditional<ID == T10ID,  T10,
+            void>::type>::type>::type>::type>::type>::type>::type>
+                 ::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          etl::is_same<T, T5>::value ? T5ID :
+          etl::is_same<T, T6>::value ? T6ID :
+          etl::is_same<T, T7>::value ? T7ID :
+          etl::is_same<T, T8>::value ? T8ID :
+          etl::is_same<T, T9>::value ? T9ID :
+          etl::is_same<T, T10>::value ? T10ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 9 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3,
+            const size_t T4ID, typename T4,
+            const size_t T5ID, typename T5,
+            const size_t T6ID, typename T6,
+            const size_t T7ID, typename T7,
+            const size_t T8ID, typename T8,
+            const size_t T9ID, typename T9>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, 
+                     T9ID, T9, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            typename etl::conditional<ID == T5ID,  T5,
+            typename etl::conditional<ID == T6ID,  T6,
+            typename etl::conditional<ID == T7ID,  T7,
+            typename etl::conditional<ID == T8ID,  T8,
+            typename etl::conditional<ID == T9ID,  T9,
+            void>::type>::type>::type>::type>::type>::type>::type>
+                 ::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          etl::is_same<T, T5>::value ? T5ID :
+          etl::is_same<T, T6>::value ? T6ID :
+          etl::is_same<T, T7>::value ? T7ID :
+          etl::is_same<T, T8>::value ? T8ID :
+          etl::is_same<T, T9>::value ? T9ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 8 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3,
+            const size_t T4ID, typename T4,
+            const size_t T5ID, typename T5,
+            const size_t T6ID, typename T6,
+            const size_t T7ID, typename T7,
+            const size_t T8ID, typename T8>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, 
+                     0, void, 
+                     0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            typename etl::conditional<ID == T5ID,  T5,
+            typename etl::conditional<ID == T6ID,  T6,
+            typename etl::conditional<ID == T7ID,  T7,
+            typename etl::conditional<ID == T8ID,  T8,
+            void>::type>::type>::type>::type>::type>::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          etl::is_same<T, T5>::value ? T5ID :
+          etl::is_same<T, T6>::value ? T6ID :
+          etl::is_same<T, T7>::value ? T7ID :
+          etl::is_same<T, T8>::value ? T8ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 7 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3,
+            const size_t T4ID, typename T4,
+            const size_t T5ID, typename T5,
+            const size_t T6ID, typename T6,
+            const size_t T7ID, typename T7>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, 0, void, 0, void, 
+                     0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            typename etl::conditional<ID == T5ID,  T5,
+            typename etl::conditional<ID == T6ID,  T6,
+            typename etl::conditional<ID == T7ID,  T7,
+            void>::type>::type>::type>::type>::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          etl::is_same<T, T5>::value ? T5ID :
+          etl::is_same<T, T6>::value ? T6ID :
+          etl::is_same<T, T7>::value ? T7ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 6 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3,
+            const size_t T4ID, typename T4,
+            const size_t T5ID, typename T5,
+            const size_t T6ID, typename T6>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, 0, void, 0, void, 0, void, 
+                     0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            typename etl::conditional<ID == T5ID,  T5,
+            typename etl::conditional<ID == T6ID,  T6,
+            void>::type>::type>::type>::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          etl::is_same<T, T5>::value ? T5ID :
+          etl::is_same<T, T6>::value ? T6ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 5 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3,
+            const size_t T4ID, typename T4,
+            const size_t T5ID, typename T5>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, 0, void, 0, void, 0, void, 0, void, 
+                     0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            typename etl::conditional<ID == T5ID,  T5,
+            void>::type>::type>::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          etl::is_same<T, T5>::value ? T5ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 4 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3,
+            const size_t T4ID, typename T4>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, 0, void, 0, void, 0, void, 0, void, 0, void, 
+                     0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            typename etl::conditional<ID == T4ID,  T4,
+            void>::type>::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          etl::is_same<T, T4>::value ? T4ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 3 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2,
+            const size_t T3ID, typename T3>
+  struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 
+                     0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            typename etl::conditional<ID == T3ID,  T3,
+            void>::type>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          etl::is_same<T, T3>::value ? T3ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 2 types.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T2ID, typename T2>
+  struct type_lookup<T1ID, T1, T2ID, T2, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 
+                     0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            typename etl::conditional<ID == T2ID,  T2,
+            void>::type>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          etl::is_same<T, T2>::value ? T2ID :
+          UNKNOWN
+      };
+    };
+  };
+
+  //***************************************************************************
+  // Specialisation for 1 type.
+  //***************************************************************************
+  template <const size_t T1ID, typename T1,
+            const size_t T1ID, typename T1>
+  struct type_lookup<T1ID, T1, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 
+                     0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void>
+  {
+    //************************************
+    template <size_t ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1ID,  T1,
+            void>::type type;
+      };
+
+    //************************************
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        UNKNOWN = 0xFFFFFFFF,
+        value = 
+          etl::is_same<T, T1>::value ? T1ID :
+          UNKNOWN
+      };
+    };
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/timer.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,102 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_TIMER__
+#define __ETL_TIMER__
+
+#include <stdint.h>
+
+#include "platform.h"
+
+#include "atomic.h"
+
+//*****************************************************************************
+// Definitions common to timers.
+//*****************************************************************************
+
+namespace etl
+{
+#ifdef ETL_TIMER_SEMAPHORE_TYPE
+  typedef ETL_TIMER_SEMAPHORE_TYPE timer_semaphore_t;
+#else
+  typedef etl::atomic_uint32_t timer_semaphore_t;
+#endif
+
+  //***************************************************************************
+  /// Common definitions for the timer framework.
+  //***************************************************************************
+  struct timer
+  {
+    // Timer modes.
+    struct mode
+    {
+      enum
+      {
+        SINGLE_SHOT = false,
+        REPEATING   = true
+      };
+
+      typedef bool type;
+    };
+
+    // Timer start status.
+    struct start
+    {
+      enum
+      {
+        DELAYED   = false,
+        IMMEDIATE = true
+      };
+
+      typedef bool type;
+    };
+
+    // Timer id.
+    struct id
+    {
+      enum
+      {
+        NO_TIMER = 255
+      };
+
+      typedef uint_least8_t type;
+    };
+
+    // Timer state.
+    struct state
+    {
+      enum
+      {
+        INACTIVE = 0xFFFFFFFF
+      };
+    };
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/type_def.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,309 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_TYPE_DEF__
+#define __ETL_TYPE_DEF__
+
+#include "platform.h"
+
+namespace etl
+{
+    #define ETL_TYPEDEF(T, name) class name##_tag; typedef etl::type_def<name##_tag, T> name
+
+    //*************************************************************************
+    /// A template type to define strong typedefs.
+    /// Usage:
+    ///\code
+    /// // Short form.
+    /// ETL_TYPEDEF(int, mytype);
+    ///
+    /// // Long form.
+    /// class mytype_t_tag;
+    /// typedef etl::type_def<mytype_t_tag, int> mytype_t_tag;
+    ///\endcode
+    //*************************************************************************
+    template <typename TIdType, typename TValue>
+    class type_def
+    {
+    public:
+
+        typedef TValue  value_type;
+        typedef TIdType id_type;
+
+        //*********************************************************************
+        type_def()
+            : value(TValue())
+        {
+        }
+
+        //*********************************************************************
+        type_def(TValue value_)
+            : value(value_)
+        {
+        }
+
+        //*********************************************************************
+        type_def(const type_def& other)
+            : value(other.value)
+        {
+        }
+
+        //*********************************************************************
+        operator TValue() const
+        {
+            return value;
+        }
+
+        //*********************************************************************
+        type_def& operator ++()
+        {
+            ++value;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def operator ++(int)
+        {
+            type_def temp(*this);
+            type_def::operator ++();
+            return temp;
+        }
+
+        //*********************************************************************
+        type_def& operator --()
+        {
+            --value;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def operator --(int)
+        {
+            type_def temp(*this);
+            type_def::operator --();
+            return temp;
+        }
+
+        //*********************************************************************
+        type_def& operator +=(TValue rhs)
+        {
+            value += rhs;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator +=(const type_def& rhs)
+        {
+            value += rhs.value;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator -=(TValue rhs)
+        {
+            value -= rhs;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator -=(const type_def& rhs)
+        {
+            value -= rhs.value;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator *=(TValue rhs)
+        {
+            value *= rhs;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator *=(const type_def& rhs)
+        {
+            value *= rhs.value;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator /=(TValue rhs)
+        {
+            value /= rhs;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator /=(const type_def& rhs)
+        {
+            value /= rhs.value;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator %=(TValue rhs)
+        {
+            value %= rhs;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator %=(const type_def& rhs)
+        {
+            value %= rhs.value;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator &=(TValue rhs)
+        {
+            value &= rhs;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator &=(const type_def& rhs)
+        {
+            value &= rhs.value;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator |=(TValue rhs)
+        {
+            value |= rhs;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator |=(const type_def& rhs)
+        {
+            value |= rhs.value;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator ^=(TValue rhs)
+        {
+            value ^= rhs;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator ^=(const type_def& rhs)
+        {
+            value ^= rhs.value;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator <<=(TValue rhs)
+        {
+            value <<= rhs;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator >>=(TValue rhs)
+        {
+            value >>= rhs;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator =(TValue rhs)
+        {
+            value = rhs;
+            return *this;
+        }
+
+        //*********************************************************************
+        type_def& operator =(const type_def& rhs)
+        {
+          value = rhs.value;
+          return *this;
+        }
+
+        //*********************************************************************
+        TValue& get()
+        {
+            return value;
+        }
+
+        //*********************************************************************
+        const TValue& get() const
+        {
+            return value;
+        }
+
+        //*********************************************************************
+        friend bool operator <(const type_def& lhs, const type_def& rhs)
+        {
+            return lhs.value < rhs.value;
+        }
+
+        //*********************************************************************
+        friend bool operator <=(const type_def& lhs, const type_def& rhs)
+        {
+            return lhs.value <= rhs.value;
+        }
+
+        //*********************************************************************
+        friend bool operator >(const type_def& lhs, const type_def& rhs)
+        {
+            return lhs.value > rhs.value;
+        }
+
+        //*********************************************************************
+        friend bool operator >=(const type_def& lhs, const type_def& rhs)
+        {
+            return lhs.value >= rhs.value;
+        }
+
+        //*********************************************************************
+        friend bool operator ==(const type_def& lhs, const type_def& rhs)
+        {
+            return lhs.value == rhs.value;
+        }
+
+        //*********************************************************************
+        friend bool operator !=(const type_def& lhs, const type_def& rhs)
+        {
+            return lhs.value != rhs.value;
+        }
+
+    private:
+
+        TValue value;
+    };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/type_lookup.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,233 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_TYPE_LOOKUP__
+#define __ETL_TYPE_LOOKUP__
+
+#include <limits.h>
+
+#include "platform.h"
+#include "type_traits.h"
+#include "static_assert.h"
+
+#undef ETL_FILE
+#define ETL_FILE "41"
+
+#if 0
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+#endif
+
+//***************************************************************************
+// This file has been auto generated. Do not edit this file.
+//***************************************************************************
+
+namespace etl
+{
+  struct null_type {};
+
+  //***************************************************************************
+  /// The type/id pair type to use for type/id lookup template parameters.
+  //***************************************************************************
+  template <typename T, int ID_>
+  struct type_id_pair
+  {
+    typedef T type;
+
+    enum
+    {
+      ID = ID_
+    };
+  };
+
+  //***************************************************************************
+  /// The type/type pair type to use for type/type lookup template parameters.
+  //***************************************************************************
+  template <typename T1, typename T2>
+  struct type_type_pair
+  {
+    typedef T1 type1;
+    typedef T2 type2;
+  };
+
+  //***************************************************************************
+  // For 16 types.
+  //***************************************************************************
+  template <typename T1,
+            typename T2 = etl::type_id_pair<etl::null_type, -2>,
+            typename T3 = etl::type_id_pair<etl::null_type, -3>,
+            typename T4 = etl::type_id_pair<etl::null_type, -4>,
+            typename T5 = etl::type_id_pair<etl::null_type, -5>,
+            typename T6 = etl::type_id_pair<etl::null_type, -6>,
+            typename T7 = etl::type_id_pair<etl::null_type, -7>,
+            typename T8 = etl::type_id_pair<etl::null_type, -8>,
+            typename T9 = etl::type_id_pair<etl::null_type, -9>,
+            typename T10 = etl::type_id_pair<etl::null_type, -10>,
+            typename T11 = etl::type_id_pair<etl::null_type, -11>,
+            typename T12 = etl::type_id_pair<etl::null_type, -12>,
+            typename T13 = etl::type_id_pair<etl::null_type, -13>,
+            typename T14 = etl::type_id_pair<etl::null_type, -14>,
+            typename T15 = etl::type_id_pair<etl::null_type, -15>,
+            typename T16 = etl::type_id_pair<etl::null_type, -16> >
+  struct type_id_lookup
+  {
+  public:
+
+    //************************************
+    template <int ID>
+    struct type_from_id
+    {
+      typedef 
+            typename etl::conditional<ID == T1::ID, typename T1::type,
+            typename etl::conditional<ID == T2::ID, typename T2::type,
+            typename etl::conditional<ID == T3::ID, typename T3::type,
+            typename etl::conditional<ID == T4::ID, typename T4::type,
+            typename etl::conditional<ID == T5::ID, typename T5::type,
+            typename etl::conditional<ID == T6::ID, typename T6::type,
+            typename etl::conditional<ID == T7::ID, typename T7::type,
+            typename etl::conditional<ID == T8::ID, typename T8::type,
+            typename etl::conditional<ID == T9::ID, typename T9::type,
+            typename etl::conditional<ID == T10::ID, typename T10::type,
+            typename etl::conditional<ID == T11::ID, typename T11::type,
+            typename etl::conditional<ID == T12::ID, typename T12::type,
+            typename etl::conditional<ID == T13::ID, typename T13::type,
+            typename etl::conditional<ID == T14::ID, typename T14::type,
+            typename etl::conditional<ID == T15::ID, typename T15::type,
+            typename etl::conditional<ID == T16::ID, typename T16::type,
+            etl::null_type>::type>::type>::type>::type>
+                           ::type>::type>::type>::type>
+                           ::type>::type>::type>::type>
+                           ::type>::type>::type>::type type;
+
+      STATIC_ASSERT(!(etl::is_same<etl::null_type, type>::value), "Invalid id");
+    };
+
+    //************************************
+    enum
+    {
+      UNKNOWN = UINT_MAX
+    };
+
+    template <typename T>
+    struct id_from_type
+    {
+      enum
+      {
+        value =
+          (unsigned int) etl::is_same<T, typename T1::type>::value ? T1::ID :
+          (unsigned int) etl::is_same<T, typename T2::type>::value ? T2::ID :
+          (unsigned int) etl::is_same<T, typename T3::type>::value ? T3::ID :
+          (unsigned int) etl::is_same<T, typename T4::type>::value ? T4::ID :
+          (unsigned int) etl::is_same<T, typename T5::type>::value ? T5::ID :
+          (unsigned int) etl::is_same<T, typename T6::type>::value ? T6::ID :
+          (unsigned int) etl::is_same<T, typename T7::type>::value ? T7::ID :
+          (unsigned int) etl::is_same<T, typename T8::type>::value ? T8::ID :
+          (unsigned int) etl::is_same<T, typename T9::type>::value ? T9::ID :
+          (unsigned int) etl::is_same<T, typename T10::type>::value ? T10::ID :
+          (unsigned int) etl::is_same<T, typename T11::type>::value ? T11::ID :
+          (unsigned int) etl::is_same<T, typename T12::type>::value ? T12::ID :
+          (unsigned int) etl::is_same<T, typename T13::type>::value ? T13::ID :
+          (unsigned int) etl::is_same<T, typename T14::type>::value ? T14::ID :
+          (unsigned int) etl::is_same<T, typename T15::type>::value ? T15::ID :
+          (unsigned int) etl::is_same<T, typename T16::type>::value ? T16::ID :
+          (unsigned int) UNKNOWN
+      };
+
+      STATIC_ASSERT(((unsigned int)value != (unsigned int)UNKNOWN), "Invalid type");
+    };
+
+    //************************************
+    template <typename T>
+    static unsigned int get_id_from_type(const T&)
+    {
+      return get_id_from_type<T>();
+    }
+
+    //************************************
+    template <typename T>
+    static unsigned int get_id_from_type()
+    {
+      return id_from_type<T>::value;
+    }
+  };
+
+  //***************************************************************************
+  // For 16 types.
+  //***************************************************************************
+  template <typename T1,
+            typename T2 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T3 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T4 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T5 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T6 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T7 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T8 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T9 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T10 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T11 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T12 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T13 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T14 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T15 = etl::type_type_pair<etl::null_type, etl::null_type>,
+            typename T16 = etl::type_type_pair<etl::null_type, etl::null_type> >
+  struct type_type_lookup
+  {
+  public:
+
+    //************************************
+    template <typename T>
+    struct type_from_type
+    {
+      typedef 
+            typename etl::conditional<etl::is_same<T, typename T1::type1>::value, typename T1::type2,
+            typename etl::conditional<etl::is_same<T, typename T2::type1>::value, typename T2::type2,
+            typename etl::conditional<etl::is_same<T, typename T3::type1>::value, typename T3::type2,
+            typename etl::conditional<etl::is_same<T, typename T4::type1>::value, typename T4::type2,
+            typename etl::conditional<etl::is_same<T, typename T5::type1>::value, typename T5::type2,
+            typename etl::conditional<etl::is_same<T, typename T6::type1>::value, typename T6::type2,
+            typename etl::conditional<etl::is_same<T, typename T7::type1>::value, typename T7::type2,
+            typename etl::conditional<etl::is_same<T, typename T8::type1>::value, typename T8::type2,
+            typename etl::conditional<etl::is_same<T, typename T9::type1>::value, typename T9::type2,
+            typename etl::conditional<etl::is_same<T, typename T10::type1>::value, typename T10::type2,
+            typename etl::conditional<etl::is_same<T, typename T11::type1>::value, typename T11::type2,
+            typename etl::conditional<etl::is_same<T, typename T12::type1>::value, typename T12::type2,
+            typename etl::conditional<etl::is_same<T, typename T13::type1>::value, typename T13::type2,
+            typename etl::conditional<etl::is_same<T, typename T14::type1>::value, typename T14::type2,
+            typename etl::conditional<etl::is_same<T, typename T15::type1>::value, typename T15::type2,
+            typename etl::conditional<etl::is_same<T, typename T16::type1>::value, typename T16::type2,
+            etl::null_type>::type>::type>::type>::type>::type>::type>::type>::type>
+                           ::type>::type>::type>::type>::type>::type>::type>::type type;
+
+      STATIC_ASSERT(!(etl::is_same<etl::null_type, type>::value), "Invalid type");
+    };
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/type_lookup_generator.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,197 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_TYPE_LOOKUP__
+#define __ETL_TYPE_LOOKUP__
+
+#include <limits.h>
+
+#include "platform.h"
+#include "type_traits.h"
+#include "static_assert.h"
+
+#undef ETL_FILE
+#define ETL_FILE "41"
+
+/*[[[cog
+import cog
+cog.outl("#if 0")
+]]]*/
+/*[[[end]]]*/
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+/*[[[cog
+import cog
+cog.outl("#endif")
+]]]*/
+/*[[[end]]]*/
+
+/*[[[cog
+import cog
+cog.outl("//***************************************************************************")
+cog.outl("// This file has been auto generated. Do not edit this file.")
+cog.outl("//***************************************************************************")
+]]]*/
+/*[[[end]]]*/
+
+namespace etl
+{
+  struct null_type {};
+
+  //***************************************************************************
+  /// The type/id pair type to use for type/id lookup template parameters.
+  //***************************************************************************
+  template <typename T, int ID_>
+  struct type_id_pair
+  {
+    typedef T type;
+
+    enum
+    {
+      ID = ID_
+    };
+  };
+
+  //***************************************************************************
+  /// The type/type pair type to use for type/type lookup template parameters.
+  //***************************************************************************
+  template <typename T1, typename T2>
+  struct type_type_pair
+  {
+    typedef T1 type1;
+    typedef T2 type2;
+  };
+
+  /*[[[cog
+  import cog
+  cog.outl("//***************************************************************************")
+  cog.outl("// For %s types." % int(NTypes))
+  cog.outl("//***************************************************************************")
+  cog.outl("template <typename T1,")
+  for n in range(2, int(NTypes)):
+      cog.outl("          typename T%s = etl::type_id_pair<etl::null_type, -%s>," %(n, n))
+  cog.outl("          typename T%s = etl::type_id_pair<etl::null_type, -%s> >" %(NTypes, NTypes))
+  cog.outl("struct type_id_lookup")
+  cog.outl("{")
+  cog.outl("public:")
+  cog.outl("")
+  cog.outl("  //************************************")
+  cog.outl("  template <int ID>")
+  cog.outl("  struct type_from_id")
+  cog.outl("  {")
+  cog.outl("    typedef ")
+  for n in range(1, int(NTypes) + 1):
+      cog.outl("          typename etl::conditional<ID == T%s::ID, typename T%s::type," %(n, n))
+  cog.out("          etl::null_type>")
+  for n in range(1, int(NTypes) + 1):
+      if n == int(NTypes):
+          cog.outl("::type type;")
+      else:
+          cog.out("::type>")
+      if n % 4 == 0:          
+          if n != int(NTypes):
+              cog.outl("")
+              cog.out("                         ")
+  cog.outl("")
+  cog.outl("    STATIC_ASSERT(!(etl::is_same<etl::null_type, type>::value), \"Invalid id\");")
+  cog.outl("  };")
+  cog.outl("")
+  cog.outl("  //************************************")
+  cog.outl("  enum")
+  cog.outl("  {")
+  cog.outl("    UNKNOWN = UINT_MAX")
+  cog.outl("  };")
+  cog.outl("")
+  cog.outl("  template <typename T>")
+  cog.outl("  struct id_from_type")
+  cog.outl("  {")
+  cog.outl("    enum")
+  cog.outl("    {")
+  cog.outl("      value =")
+  for n in range(1, int(NTypes) + 1) :
+      cog.outl("        (unsigned int) etl::is_same<T, typename T%s::type>::value ? T%s::ID :" % (n, n))
+  cog.outl("        (unsigned int) UNKNOWN")
+  cog.outl("    };")
+  cog.outl("")
+  cog.outl("    STATIC_ASSERT(((unsigned int)value != (unsigned int)UNKNOWN), \"Invalid type\");")
+  cog.outl("  };")
+  cog.outl("")
+  cog.outl("  //************************************")
+  cog.outl("  template <typename T>")
+  cog.outl("  static unsigned int get_id_from_type(const T&)")
+  cog.outl("  {")
+  cog.outl("    return get_id_from_type<T>();")
+  cog.outl("  }")
+  cog.outl("")
+  cog.outl("  //************************************")
+  cog.outl("  template <typename T>")
+  cog.outl("  static unsigned int get_id_from_type()")
+  cog.outl("  {")
+  cog.outl("    return id_from_type<T>::value;")
+  cog.outl("  }")
+  cog.outl("};")
+  cog.outl("")
+  cog.outl("//***************************************************************************")
+  cog.outl("// For %s types." % int(NTypes))
+  cog.outl("//***************************************************************************")
+  cog.outl("template <typename T1,")
+  for n in range(2, int(NTypes)):
+      cog.outl("          typename T%s = etl::type_type_pair<etl::null_type, etl::null_type>," %n)
+  cog.outl("          typename T%s = etl::type_type_pair<etl::null_type, etl::null_type> >" %NTypes)
+  cog.outl("struct type_type_lookup")
+  cog.outl("{")
+  cog.outl("public:")
+  cog.outl("")
+  cog.outl("  //************************************")
+  cog.outl("  template <typename T>")
+  cog.outl("  struct type_from_type")
+  cog.outl("  {")
+  cog.outl("    typedef ")
+  for n in range(1, int(NTypes) + 1):
+      cog.outl("          typename etl::conditional<etl::is_same<T, typename T%s::type1>::value, typename T%s::type2," %(n, n))
+  cog.out("          etl::null_type>")
+  for n in range(1, int(NTypes) + 1):
+      if n == int(NTypes):
+          cog.outl("::type type;")
+      else:
+          cog.out("::type>")
+      if n % 8 == 0:
+          if n != int(NTypes):
+              cog.outl("")
+              cog.out("                         ")
+  cog.outl("")
+  cog.outl("    STATIC_ASSERT(!(etl::is_same<etl::null_type, type>::value), \"Invalid type\");")
+  cog.outl("  };")
+  cog.outl("};")
+  ]]]*/
+  /*[[[end]]]*/
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/type_traits.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,593 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+#if 0
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+#endif
+
+//***************************************************************************
+// This file has been auto generated. Do not edit this file.
+//***************************************************************************
+
+//***************************************************************************
+// To generate to header file, run this at the command line.
+// Note: You will need Python and COG installed.
+//
+// python -m cogapp -d -e -otypes.h -DHandlers=<n> types_generator.h
+// Where <n> is the number of types to support.
+//
+// e.g.
+// To generate handlers for up to 16 types...
+// python -m cogapp -d -e -otype_traits.h -DIsOneOf=16 type_traits_generator.h
+//
+// See generate.bat
+//***************************************************************************
+
+#ifndef __ETL_TYPE_TRAITS__
+#define __ETL_TYPE_TRAITS__
+
+#include <cstddef>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "platform.h"
+#include "nullptr.h"
+#include "static_assert.h"
+
+#if (ETL_CPP11_SUPPORTED)
+  #include <type_traits>
+#endif
+
+///\defgroup type_traits type_traits
+/// A set of type traits definitions for compilers that do not support the standard header.
+/// \ingroup utilities
+
+namespace etl
+{
+  /// integral_constant
+  ///\ingroup type_traits
+  template <typename T, const T VALUE>
+  struct integral_constant
+  {
+    static const T value = VALUE;
+
+    typedef T value_type;
+    typedef integral_constant<T, VALUE> type;
+
+    operator value_type() const
+    {
+       return value;
+    }
+  };
+
+  /// integral_constant specialisations
+  ///\ingroup type_traits
+  typedef integral_constant<bool, false> false_type;
+  typedef integral_constant<bool, true>  true_type;
+
+  /// remove_reference
+  ///\ingroup type_traits
+  template <typename T> struct remove_reference { typedef T type; };
+  template <typename T> struct remove_reference<T&> { typedef T type; };
+
+  /// add_reference
+  ///\ingroup type_traits
+  template <typename T> struct add_reference { typedef T& type; };
+  template <typename T> struct add_reference<T&> { typedef T& type; };
+
+  /// remove_pointer
+  ///\ingroup type_traits
+  template <typename T> struct remove_pointer { typedef T type; };
+  template <typename T> struct remove_pointer<T*> { typedef T type; };
+  template <typename T> struct remove_pointer<const T*> { typedef const T type; };
+  template <typename T> struct remove_pointer<volatile T*> { typedef volatile T type; };
+  template <typename T> struct remove_pointer<const volatile T*> { typedef const volatile T type; };
+  template <typename T> struct remove_pointer<T* const> { typedef T type; };
+  template <typename T> struct remove_pointer<const T* const> { typedef const T type; };
+  template <typename T> struct remove_pointer<volatile T* const> { typedef volatile T type; };
+  template <typename T> struct remove_pointer<const volatile T* const> { typedef const volatile T type; };
+
+  /// add_pointer
+  ///\ingroup type_traits
+  template <typename T> struct add_pointer { typedef typename remove_reference<T>::type* type; };
+
+  /// is_const
+  ///\ingroup type_traits
+  template <typename T> struct is_const : false_type {};
+  template <typename T> struct is_const<const T> : true_type {};
+  template <typename T> struct is_const<const volatile T> : true_type {};
+
+  /// remove_const
+  ///\ingroup type_traits
+  template <typename T> struct remove_const { typedef T type; };
+  template <typename T> struct remove_const<const T> { typedef T type; };
+
+  /// add_const
+  ///\ingroup type_traits
+  template <typename T> struct add_const { typedef const T type; };
+  template <typename T> struct add_const<const T> { typedef const T type; };
+
+  /// is_volatile
+  ///\ingroup type_traits
+  template <typename T> struct is_volatile : false_type {};
+  template <typename T> struct is_volatile<volatile T> : true_type {};
+  template <typename T> struct is_volatile<const volatile T> : true_type {};
+
+  /// remove_volatile
+  ///\ingroup type_traits
+  template <typename T> struct remove_volatile { typedef T type; };
+  template <typename T> struct remove_volatile<volatile T> { typedef T type; };
+
+  /// add_volatile
+  ///\ingroup type_traits
+  template <typename T> struct add_volatile { typedef volatile T type; };
+  template <typename T> struct add_volatile<volatile T> { typedef volatile T type; };
+
+  /// remove_cv
+  ///\ingroup type_traits
+  template <typename T> struct remove_cv
+  {
+    typedef typename remove_volatile<typename remove_const<T>::type>::type type;
+  };
+
+  /// add_cv
+  ///\ingroup type_traits
+  template <typename T> struct add_cv
+  {
+    typedef typename add_volatile<typename add_const<T>::type>::type type;
+  };
+
+  /// is_integral
+  ///\ingroup type_traits
+  template <typename T> struct is_integral : false_type {};
+  template <> struct is_integral<bool> : true_type {};
+  template <> struct is_integral<char> : true_type {};
+  template <> struct is_integral<unsigned char> : true_type {};
+  template <> struct is_integral<signed char> : true_type {};
+  template <> struct is_integral<wchar_t> : true_type {};
+  template <> struct is_integral<short> : true_type {};
+  template <> struct is_integral<unsigned short> : true_type {};
+  template <> struct is_integral<int> : true_type {};
+  template <> struct is_integral<unsigned int> : true_type {};
+  template <> struct is_integral<long> : true_type {};
+  template <> struct is_integral<unsigned long> : true_type {};
+  template <> struct is_integral<long long> : true_type {};
+  template <> struct is_integral<unsigned long long> : true_type {};
+  template <typename T> struct is_integral<const T> : is_integral<T> {};
+  template <typename T> struct is_integral<volatile T> : is_integral<T> {};
+  template <typename T> struct is_integral<const volatile T> : is_integral<T> {};
+
+  /// is_signed
+  ///\ingroup type_traits
+  template <typename T> struct is_signed : false_type {};
+  template <> struct is_signed<char> : integral_constant<bool, (char(255) < 0)> {};
+  template <> struct is_signed<wchar_t> : public etl::integral_constant<bool, static_cast<bool>(wchar_t(-1) < wchar_t(0))> {};
+  template <> struct is_signed<signed char> : true_type {};
+  template <> struct is_signed<short> : true_type {};
+  template <> struct is_signed<int> : true_type {};
+  template <> struct is_signed<long> : true_type {};
+  template <> struct is_signed<long long> : true_type {};
+  template <> struct is_signed<float> : true_type{};
+  template <> struct is_signed<double> : true_type{};
+  template <> struct is_signed<long double> : true_type{};
+  template <typename T> struct is_signed<const T> : is_signed<T> {};
+  template <typename T> struct is_signed<volatile T> : is_signed<T> {};
+  template <typename T> struct is_signed<const volatile T> : is_signed<T> {};
+
+  /// is_unsigned
+  ///\ingroup type_traits
+  template <typename T> struct is_unsigned : false_type {};
+  template <> struct is_unsigned<bool> : true_type {};
+  template <> struct is_unsigned<char> : integral_constant<bool, (char(255) > 0)> {};
+  template <> struct is_unsigned<unsigned char> : true_type {};
+  template <> struct is_unsigned<wchar_t> : public etl::integral_constant<bool, (wchar_t(-1) > wchar_t(0))> {};
+  template <> struct is_unsigned<unsigned short> : true_type {};
+  template <> struct is_unsigned<unsigned int> : true_type {};
+  template <> struct is_unsigned<unsigned long> : true_type {};
+  template <> struct is_unsigned<unsigned long long> : true_type {};
+  template <typename T> struct is_unsigned<const T> : is_unsigned<T> {};
+  template <typename T> struct is_unsigned<volatile T> : is_unsigned<T> {};
+  template <typename T> struct is_unsigned<const volatile T> : is_unsigned<T> {};
+
+  /// is_floating_point
+  ///\ingroup type_traits
+  template <typename T> struct is_floating_point : false_type {};
+  template <> struct is_floating_point<float> : true_type {};
+  template <> struct is_floating_point<double> : true_type {};
+  template <> struct is_floating_point<long double> : true_type {};
+  template <typename T> struct is_floating_point<const T> : is_floating_point<T> {};
+  template <typename T> struct is_floating_point<volatile T> : is_floating_point<T> {};
+  template <typename T> struct is_floating_point<const volatile T> : is_floating_point<T> {};
+
+  /// is_same
+  ///\ingroup type_traits
+  template <typename T1, typename T2> struct is_same : public false_type {};
+  template <typename T> struct is_same<T, T> : public true_type {};
+
+  /// is_void
+  ///\ingroup type_traits
+  template<typename T> struct is_void : false_type {};
+  template<> struct is_void<void> : true_type {};
+
+  /// is_arithmetic
+  ///\ingroup type_traits
+  template<typename T> struct is_arithmetic : integral_constant<bool, is_integral<T>::value || is_floating_point<T>::value> {};
+
+  /// is_fundamental
+  ///\ingroup type_traits
+  template <typename T> struct is_fundamental : integral_constant<bool, is_arithmetic<T>::value ||
+                                                                        is_void<T>::value  ||
+                                                                        is_same<std::nullptr_t,
+                                                                  typename remove_cv<T>::type>::value> {};
+
+  /// is_compound
+  ///\ingroup type_traits
+  template <typename T> struct is_compound : integral_constant<bool, !is_fundamental<T>::value> {};
+
+  /// is_array
+  ///\ingroup type_traits
+  template <typename T> struct is_array : false_type {};
+  template <typename T> struct is_array<T[]> : true_type {};
+  template <typename T, size_t MAXN> struct is_array<T[MAXN]> : true_type {};
+
+  /// is_pointer
+  ///\ingroup type_traits
+  template <typename T> struct is_pointer : false_type {};
+  template <typename T> struct is_pointer<T*> : true_type {};
+
+  /// is_reference
+  ///\ingroup type_traits
+  template <typename T> struct is_reference : false_type {};
+  template <typename T> struct is_reference<T&> : true_type {};
+
+  /// is_pod
+  /// For C++03, only fundamental and pointers types are recognised.
+  ///\ingroup type_traits
+#if (ETL_CPP11_SUPPORTED && !defined(ARDUINO)) && !defined(ETL_IN_UNIT_TEST)
+  // For compilers that support C++11
+  template <typename T> struct is_pod : std::is_pod<T> {};
+#else
+  template <typename T> struct is_pod : etl::integral_constant<bool, etl::is_fundamental<T>::value || etl::is_pointer<T>::value> {};
+#endif
+
+#if (ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED) && !defined(ETL_IN_UNIT_TEST)
+  /// is_trivially_constructible
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_constructible : std::is_trivially_constructible<T> {};
+
+  /// is_trivially_copy_constructible
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T> {};
+
+  /// is_trivially_destructible
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_destructible : std::is_trivially_destructible<T> {};
+
+  /// is_trivially_copy_assignable
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_copy_assignable : std::is_trivially_copy_assignable<T> {};
+#else
+  /// is_trivially_constructible
+  /// For C++03, only POD types are recognised.
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_constructible : etl::is_pod<T> {};
+
+  /// is_trivially_copy_constructible
+  /// For C++03, only POD types are recognised.
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_copy_constructible : etl::is_pod<T> {};
+
+  /// is_trivially_destructible
+  /// For C++03, only POD types are recognised.
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_destructible : etl::is_pod<T> {};
+
+  /// is_trivially_copy_assignable
+  /// For C++03, only POD types are recognised.
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_copy_assignable : etl::is_pod<T> {};
+#endif
+
+  /// conditional
+  ///\ingroup type_traits
+  template <bool B, typename T, typename F>  struct conditional { typedef T type; };
+  template <typename T, typename F> struct conditional<false, T, F> { typedef F type; };
+
+  /// conditional_integral_constant
+  ///\ingroup type_traits
+  template <bool B, typename T, T TRUE_VALUE, T FALSE_VALUE>
+  struct conditional_integral_constant;
+
+  template <typename T, T TRUE_VALUE, T FALSE_VALUE>
+  struct conditional_integral_constant<true, T, TRUE_VALUE, FALSE_VALUE>
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+    static const T value = TRUE_VALUE;
+  };
+
+  template <typename T, T TRUE_VALUE, T FALSE_VALUE>
+  struct conditional_integral_constant<false, T, TRUE_VALUE, FALSE_VALUE>
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+    static const T value = FALSE_VALUE; 
+  };
+
+  /// make_signed
+  ///\ingroup type_traits
+  template <typename T> struct make_signed { typedef  T type; };
+  template <> struct make_signed<char> { typedef  signed char type; };
+  template <> struct make_signed<unsigned char> { typedef  signed char type; };
+
+  template <> struct make_signed<wchar_t>
+  {
+    typedef etl::conditional<sizeof(wchar_t) == sizeof(int16_t),
+                                    int16_t,
+                                    etl::conditional<sizeof(wchar_t) == sizeof(int32_t),
+                                                            int32_t,
+                                                            void>::type>::type type;
+  };
+
+  template <> struct make_signed<unsigned short> { typedef  short type; };
+  template <> struct make_signed<unsigned int> { typedef int type; };
+  template <> struct make_signed<unsigned long> { typedef  long type; };
+  template <> struct make_signed<unsigned long long> { typedef long long type; };
+  template <typename T> struct make_signed<const T> : add_const<typename make_signed<T>::type> {};
+  template <typename T> struct make_signed<volatile T> : add_volatile<typename make_signed<T>::type> {};
+  template <typename T> struct make_signed<const volatile T> : add_const<typename add_volatile<typename make_signed<T>::type>::type> {};
+
+  /// make_unsigned
+  ///\ingroup type_traits
+  template <typename T> struct make_unsigned { typedef  T type; };
+  template <> struct make_unsigned<char> { typedef unsigned char type; };
+  template <> struct make_unsigned<signed char> { typedef unsigned char type; };
+  template <> struct make_unsigned<short> { typedef unsigned short type; };
+
+  template <> struct make_unsigned<wchar_t>
+  {
+    typedef etl::conditional<sizeof(wchar_t) == sizeof(uint16_t),
+                                    uint16_t,
+                                    etl::conditional<sizeof(wchar_t) == sizeof(uint32_t),
+                                                     uint32_t,
+                                                     void>::type>::type type;
+  };
+
+  template <> struct make_unsigned<int> { typedef unsigned int type; };
+  template <> struct make_unsigned<long> { typedef unsigned long type; };
+  template <> struct make_unsigned<long long> { typedef unsigned long long type; };
+  template <typename T> struct make_unsigned<const T> : add_const<typename make_unsigned<T>::type> {};
+  template <typename T> struct make_unsigned<volatile T> : add_volatile<typename make_unsigned<T>::type> {};
+  template <typename T> struct make_unsigned<const volatile T> : add_const<typename add_volatile<typename make_unsigned<T>::type>::type> {};
+
+  /// enable_if
+  ///\ingroup type_traits
+  template <bool B, typename T = void> struct enable_if {};
+  template <typename T> struct enable_if<true, T> { typedef T type; };
+
+  /// extent
+  ///\ingroup type_traits
+  template <typename T, size_t MAXN = 0>
+  struct extent : integral_constant<size_t, 0> {};
+
+  template <typename T>
+  struct extent<T[], 0> : integral_constant<size_t, 0> {};
+
+  template <typename T, size_t MAXN>
+  struct extent<T[], MAXN> : integral_constant<size_t, extent<T, MAXN - 1>::value> {};
+
+  template <typename T, size_t MAXN>
+  struct extent<T[MAXN], 0> : integral_constant<size_t, MAXN> {};
+
+  template <typename T, size_t I, size_t MAXN>
+  struct extent<T[I], MAXN> : integral_constant<size_t, extent<T, MAXN - 1>::value> {};
+
+  /// remove_extent
+  ///\ingroup type_traits
+  template <typename T> struct remove_extent { typedef T type; };
+  template <typename T> struct remove_extent<T[]> { typedef T type; };
+  template <typename T, size_t MAXN> struct remove_extent<T[MAXN]> { typedef T type;};
+
+  /// remove_all_extents
+  ///\ingroup type_traits
+  template <typename T> struct remove_all_extents { typedef T type;};
+  template <typename T> struct remove_all_extents<T[]> { typedef typename remove_all_extents<T>::type type; };
+  template <typename T, size_t MAXN> struct remove_all_extents<T[MAXN]> { typedef typename remove_all_extents<T>::type type; };
+
+  /// rank
+  ///\ingroup type_traits
+  template <typename T>struct rank : integral_constant<size_t, 0> {};
+  template <typename T> struct rank<T[]> : public integral_constant<size_t, rank<T>::value + 1> {};
+  template <typename T, size_t MAXN> struct rank<T[MAXN]> : public integral_constant<size_t, rank<T>::value + 1> {};
+
+  /// decay
+  ///\ingroup type_traits
+  template <typename T>
+  struct decay
+  {
+    typedef typename etl::remove_reference<T>::type U;
+    typedef typename etl::conditional<etl::is_array<U>::value,
+                                      typename etl::remove_extent<U>::type*,
+                                      typename etl::remove_cv<U>::type>::type type;
+  };
+
+  /// is_base_of
+  ///\ingroup type_traits
+  template<typename TBase,
+    typename TDerived,
+    const bool IsFundamental = (etl::is_fundamental<TBase>::value || etl::is_fundamental<TDerived>::value)>
+    struct is_base_of
+  {
+  private:
+
+    template<typename T> struct dummy {};
+    struct internal: TDerived, dummy<int>{};
+
+    static TBase* check(TBase*);
+    template<typename T> static char check(dummy<T>*);
+
+  public:
+
+    static const bool value = (sizeof(check((internal*)0)) == sizeof(TBase*));
+  };
+
+  // For when TBase or TDerived is a fundamental type.
+  template<typename TBase, typename TDerived>
+  struct is_base_of<TBase, TDerived, true>
+  {
+    static const bool value = false;
+  };
+
+  /// Alignment templates.
+  /// These require compiler specific intrinsics.
+  ///\ingroup type_traits
+#ifdef ETL_COMPILER_MICROSOFT
+  template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof(T))> {};
+
+#elif defined(ETL_COMPILER_IAR) || defined(ETL_COMPILER_TI)
+  template <typename T> struct alignment_of : integral_constant<size_t, size_t(__ALIGNOF__(T))> {};
+
+#else
+  template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof__(T))> {};
+
+#endif
+
+  /// Specialisation of 'alignment_of' for 'void'.
+  ///\ingroup type_traits
+  template <> struct alignment_of<void> : integral_constant <size_t, 0>{};
+
+  //***************************************************************************
+  /// Template to determine if a type is one of a specified list.
+  ///\ingroup types
+  //***************************************************************************
+  template <typename T,
+            typename T1, typename T2 = void, typename T3 = void, typename T4 = void, 
+            typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, 
+            typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, 
+            typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void, 
+            typename T17 = void>
+  struct is_one_of
+  {
+    static const bool value = 
+        etl::is_same<T, T1>::value ||
+        etl::is_same<T, T2>::value ||
+        etl::is_same<T, T3>::value ||
+        etl::is_same<T, T4>::value ||
+        etl::is_same<T, T5>::value ||
+        etl::is_same<T, T6>::value ||
+        etl::is_same<T, T7>::value ||
+        etl::is_same<T, T8>::value ||
+        etl::is_same<T, T9>::value ||
+        etl::is_same<T, T10>::value ||
+        etl::is_same<T, T11>::value ||
+        etl::is_same<T, T12>::value ||
+        etl::is_same<T, T13>::value ||
+        etl::is_same<T, T14>::value ||
+        etl::is_same<T, T15>::value ||
+        etl::is_same<T, T16>::value ||
+        etl::is_same<T, T17>::value;
+  };
+
+  //***************************************************************************
+  // A set of templates to allow related types to be derived.
+  //***************************************************************************
+  // Default.
+  template <typename T>
+  struct types
+  {
+  private:
+
+    typedef typename etl::remove_cv<T>::type type_t;
+
+  public:
+
+    typedef type_t              type;
+    typedef type_t&             reference;
+    typedef const type_t&       const_reference;
+    typedef type_t*             pointer;
+    typedef const type_t*       const_pointer;
+    typedef const type_t* const const_pointer_const;
+  };
+
+  // Pointers.
+  template <typename T>
+  struct types<T*>
+  {
+  private:
+
+    typedef typename etl::remove_cv<T>::type type_t;
+
+  public:
+
+    typedef type_t              type;
+    typedef type_t&             reference;
+    typedef const type_t&       const_reference;
+    typedef type_t*             pointer;
+    typedef const type_t*       const_pointer;
+    typedef const type_t* const const_pointer_const;
+  };
+
+  // Pointers.
+  template <typename T>
+  struct types<T* const>
+  {
+  private:
+
+    typedef typename etl::remove_cv<T>::type type_t;
+
+  public:
+
+    typedef type_t              type;
+    typedef type_t&             reference;
+    typedef const type_t&       const_reference;
+    typedef type_t*             pointer;
+    typedef const type_t* const_pointer;
+    typedef const type_t* const const_pointer_const;
+  };
+
+  // References.
+  template <typename T>
+  struct types<T&>
+  {
+  private:
+
+    typedef typename etl::remove_cv<T>::type type_t;
+
+  public:
+
+    typedef type_t              type;
+    typedef type_t&             reference;
+    typedef const type_t&       const_reference;
+    typedef type_t*             pointer;
+    typedef const type_t*       const_pointer;
+    typedef const type_t* const const_pointer_const;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/type_traits_generator.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,597 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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.
+******************************************************************************/
+
+/*[[[cog
+import cog
+cog.outl("#if 0")
+]]]*/
+/*[[[end]]]*/
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+/*[[[cog
+import cog
+cog.outl("#endif")
+]]]*/
+/*[[[end]]]*/
+
+/*[[[cog
+import cog
+cog.outl("//***************************************************************************")
+cog.outl("// This file has been auto generated. Do not edit this file.")
+cog.outl("//***************************************************************************")
+]]]*/
+/*[[[end]]]*/
+
+//***************************************************************************
+// To generate to header file, run this at the command line.
+// Note: You will need Python and COG installed.
+//
+// python -m cogapp -d -e -otypes.h -DHandlers=<n> types_generator.h
+// Where <n> is the number of types to support.
+//
+// e.g.
+// To generate handlers for up to 16 types...
+// python -m cogapp -d -e -otype_traits.h -DIsOneOf=16 type_traits_generator.h
+//
+// See generate.bat
+//***************************************************************************
+
+#ifndef __ETL_TYPE_TRAITS__
+#define __ETL_TYPE_TRAITS__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "platform.h"
+#include "nullptr.h"
+#include "static_assert.h"
+
+#if (ETL_CPP11_SUPPORTED)
+  #include <type_traits>
+#endif
+
+///\defgroup type_traits type_traits
+/// A set of type traits definitions for compilers that do not support the standard header.
+/// \ingroup utilities
+
+namespace etl
+{
+  /// integral_constant
+  ///\ingroup type_traits
+  template <typename T, const T VALUE>
+  struct integral_constant
+  {
+    static const T value = VALUE;
+
+    typedef T value_type;
+    typedef integral_constant<T, VALUE> type;
+
+    operator value_type() const
+    {
+       return value;
+    }
+  };
+
+  /// integral_constant specialisations
+  ///\ingroup type_traits
+  typedef integral_constant<bool, false> false_type;
+  typedef integral_constant<bool, true>  true_type;
+
+  /// remove_reference
+  ///\ingroup type_traits
+  template <typename T> struct remove_reference { typedef T type; };
+  template <typename T> struct remove_reference<T&> { typedef T type; };
+
+  /// add_reference
+  ///\ingroup type_traits
+  template <typename T> struct add_reference { typedef T& type; };
+  template <typename T> struct add_reference<T&> { typedef T& type; };
+
+  /// remove_pointer
+  ///\ingroup type_traits
+  template <typename T> struct remove_pointer { typedef T type; };
+  template <typename T> struct remove_pointer<T*> { typedef T type; };
+  template <typename T> struct remove_pointer<const T*> { typedef const T type; };
+  template <typename T> struct remove_pointer<volatile T*> { typedef volatile T type; };
+  template <typename T> struct remove_pointer<const volatile T*> { typedef const volatile T type; };
+  template <typename T> struct remove_pointer<T* const> { typedef T type; };
+  template <typename T> struct remove_pointer<const T* const> { typedef const T type; };
+  template <typename T> struct remove_pointer<volatile T* const> { typedef volatile T type; };
+  template <typename T> struct remove_pointer<const volatile T* const> { typedef const volatile T type; };
+
+  /// add_pointer
+  ///\ingroup type_traits
+  template <typename T> struct add_pointer { typedef typename remove_reference<T>::type* type; };
+
+  /// is_const
+  ///\ingroup type_traits
+  template <typename T> struct is_const : false_type {};
+  template <typename T> struct is_const<const T> : true_type {};
+  template <typename T> struct is_const<const volatile T> : true_type {};
+
+  /// remove_const
+  ///\ingroup type_traits
+  template <typename T> struct remove_const { typedef T type; };
+  template <typename T> struct remove_const<const T> { typedef T type; };
+
+  /// add_const
+  ///\ingroup type_traits
+  template <typename T> struct add_const { typedef const T type; };
+  template <typename T> struct add_const<const T> { typedef const T type; };
+
+  /// is_volatile
+  ///\ingroup type_traits
+  template <typename T> struct is_volatile : false_type {};
+  template <typename T> struct is_volatile<volatile T> : true_type {};
+  template <typename T> struct is_volatile<const volatile T> : true_type {};
+
+  /// remove_volatile
+  ///\ingroup type_traits
+  template <typename T> struct remove_volatile { typedef T type; };
+  template <typename T> struct remove_volatile<volatile T> { typedef T type; };
+
+  /// add_volatile
+  ///\ingroup type_traits
+  template <typename T> struct add_volatile { typedef volatile T type; };
+  template <typename T> struct add_volatile<volatile T> { typedef volatile T type; };
+
+  /// remove_cv
+  ///\ingroup type_traits
+  template <typename T> struct remove_cv
+  {
+    typedef typename remove_volatile<typename remove_const<T>::type>::type type;
+  };
+
+  /// add_cv
+  ///\ingroup type_traits
+  template <typename T> struct add_cv
+  {
+    typedef typename add_volatile<typename add_const<T>::type>::type type;
+  };
+
+  /// is_integral
+  ///\ingroup type_traits
+  template <typename T> struct is_integral : false_type {};
+  template <> struct is_integral<bool> : true_type {};
+  template <> struct is_integral<char> : true_type {};
+  template <> struct is_integral<unsigned char> : true_type {};
+  template <> struct is_integral<signed char> : true_type {};
+  template <> struct is_integral<wchar_t> : true_type {};
+  template <> struct is_integral<short> : true_type {};
+  template <> struct is_integral<unsigned short> : true_type {};
+  template <> struct is_integral<int> : true_type {};
+  template <> struct is_integral<unsigned int> : true_type {};
+  template <> struct is_integral<long> : true_type {};
+  template <> struct is_integral<unsigned long> : true_type {};
+  template <> struct is_integral<long long> : true_type {};
+  template <> struct is_integral<unsigned long long> : true_type {};
+  template <typename T> struct is_integral<const T> : is_integral<T> {};
+  template <typename T> struct is_integral<volatile T> : is_integral<T> {};
+  template <typename T> struct is_integral<const volatile T> : is_integral<T> {};
+
+  /// is_signed
+  ///\ingroup type_traits
+  template <typename T> struct is_signed : false_type {};
+  template <> struct is_signed<char> : integral_constant<bool, (char(255) < 0)> {};
+  template <> struct is_signed<wchar_t> : public etl::integral_constant<bool, static_cast<bool>(wchar_t(-1) < wchar_t(0))> {};
+  template <> struct is_signed<signed char> : true_type {};
+  template <> struct is_signed<short> : true_type {};
+  template <> struct is_signed<int> : true_type {};
+  template <> struct is_signed<long> : true_type {};
+  template <> struct is_signed<long long> : true_type {};
+  template <> struct is_signed<float> : true_type{};
+  template <> struct is_signed<double> : true_type{};
+  template <> struct is_signed<long double> : true_type{};
+  template <typename T> struct is_signed<const T> : is_signed<T> {};
+  template <typename T> struct is_signed<volatile T> : is_signed<T> {};
+  template <typename T> struct is_signed<const volatile T> : is_signed<T> {};
+
+  /// is_unsigned
+  ///\ingroup type_traits
+  template <typename T> struct is_unsigned : false_type {};
+  template <> struct is_unsigned<bool> : true_type {};
+  template <> struct is_unsigned<char> : integral_constant<bool, (char(255) > 0)> {};
+  template <> struct is_unsigned<unsigned char> : true_type {};
+  template <> struct is_unsigned<wchar_t> : public etl::integral_constant<bool, (wchar_t(-1) > wchar_t(0))> {};
+  template <> struct is_unsigned<unsigned short> : true_type {};
+  template <> struct is_unsigned<unsigned int> : true_type {};
+  template <> struct is_unsigned<unsigned long> : true_type {};
+  template <> struct is_unsigned<unsigned long long> : true_type {};
+  template <typename T> struct is_unsigned<const T> : is_unsigned<T> {};
+  template <typename T> struct is_unsigned<volatile T> : is_unsigned<T> {};
+  template <typename T> struct is_unsigned<const volatile T> : is_unsigned<T> {};
+
+  /// is_floating_point
+  ///\ingroup type_traits
+  template <typename T> struct is_floating_point : false_type {};
+  template <> struct is_floating_point<float> : true_type {};
+  template <> struct is_floating_point<double> : true_type {};
+  template <> struct is_floating_point<long double> : true_type {};
+  template <typename T> struct is_floating_point<const T> : is_floating_point<T> {};
+  template <typename T> struct is_floating_point<volatile T> : is_floating_point<T> {};
+  template <typename T> struct is_floating_point<const volatile T> : is_floating_point<T> {};
+
+  /// is_same
+  ///\ingroup type_traits
+  template <typename T1, typename T2> struct is_same : public false_type {};
+  template <typename T> struct is_same<T, T> : public true_type {};
+
+  /// is_void
+  ///\ingroup type_traits
+  template<typename T> struct is_void : false_type {};
+  template<> struct is_void<void> : true_type {};
+
+  /// is_arithmetic
+  ///\ingroup type_traits
+  template<typename T> struct is_arithmetic : integral_constant<bool, is_integral<T>::value || is_floating_point<T>::value> {};
+
+  /// is_fundamental
+  ///\ingroup type_traits
+  template <typename T> struct is_fundamental : integral_constant<bool, is_arithmetic<T>::value ||
+                                                                        is_void<T>::value  ||
+                                                                        is_same<std::nullptr_t,
+                                                                  typename remove_cv<T>::type>::value> {};
+
+  /// is_compound
+  ///\ingroup type_traits
+  template <typename T> struct is_compound : integral_constant<bool, !is_fundamental<T>::value> {};
+
+  /// is_array
+  ///\ingroup type_traits
+  template <typename T> struct is_array : false_type {};
+  template <typename T> struct is_array<T[]> : true_type {};
+  template <typename T, size_t MAXN> struct is_array<T[MAXN]> : true_type {};
+
+  /// is_pointer
+  ///\ingroup type_traits
+  template <typename T> struct is_pointer : false_type {};
+  template <typename T> struct is_pointer<T*> : true_type {};
+
+  /// is_reference
+  ///\ingroup type_traits
+  template <typename T> struct is_reference : false_type {};
+  template <typename T> struct is_reference<T&> : true_type {};
+
+  /// is_pod
+  /// For C++03, only fundamental and pointers types are recognised.
+  ///\ingroup type_traits
+#if (ETL_CPP11_SUPPORTED && !defined(ARDUINO)) && !defined(ETL_IN_UNIT_TEST)
+  // For compilers that support C++11
+  template <typename T> struct is_pod : std::is_pod<T> {};
+#else
+  template <typename T> struct is_pod : etl::integral_constant<bool, etl::is_fundamental<T>::value || etl::is_pointer<T>::value> {};
+#endif
+
+#if (ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED) && !defined(ETL_IN_UNIT_TEST)
+  /// is_trivially_constructible
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_constructible : std::is_trivially_constructible<T> {};
+
+  /// is_trivially_copy_constructible
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T> {};
+
+  /// is_trivially_destructible
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_destructible : std::is_trivially_destructible<T> {};
+
+  /// is_trivially_copy_assignable
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_copy_assignable : std::is_trivially_copy_assignable<T> {};
+#else
+  /// is_trivially_constructible
+  /// For C++03, only POD types are recognised.
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_constructible : etl::is_pod<T> {};
+
+  /// is_trivially_copy_constructible
+  /// For C++03, only POD types are recognised.
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_copy_constructible : etl::is_pod<T> {};
+
+  /// is_trivially_destructible
+  /// For C++03, only POD types are recognised.
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_destructible : etl::is_pod<T> {};
+
+  /// is_trivially_copy_assignable
+  /// For C++03, only POD types are recognised.
+  ///\ingroup type_traits
+  template <typename T> struct is_trivially_copy_assignable : etl::is_pod<T> {};
+#endif
+
+  /// conditional
+  ///\ingroup type_traits
+  template <bool B, typename T, typename F>  struct conditional { typedef T type; };
+  template <typename T, typename F> struct conditional<false, T, F> { typedef F type; };
+
+  /// conditional_integral_constant
+  ///\ingroup type_traits
+  template <bool B, typename T, T TRUE_VALUE, T FALSE_VALUE>
+  struct conditional_integral_constant;
+
+  template <typename T, T TRUE_VALUE, T FALSE_VALUE>
+  struct conditional_integral_constant<true, T, TRUE_VALUE, FALSE_VALUE>
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+    static const T value = TRUE_VALUE;
+  };
+
+  template <typename T, T TRUE_VALUE, T FALSE_VALUE>
+  struct conditional_integral_constant<false, T, TRUE_VALUE, FALSE_VALUE>
+  {
+    STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
+    static const T value = FALSE_VALUE; 
+  };
+
+  /// make_signed
+  ///\ingroup type_traits
+  template <typename T> struct make_signed { typedef  T type; };
+  template <> struct make_signed<char> { typedef  signed char type; };
+  template <> struct make_signed<unsigned char> { typedef  signed char type; };
+
+  template <> struct make_signed<wchar_t>
+  {
+    typedef etl::conditional<sizeof(wchar_t) == sizeof(int16_t),
+                                    int16_t,
+                                    etl::conditional<sizeof(wchar_t) == sizeof(int32_t),
+                                                            int32_t,
+                                                            void>::type>::type type;
+  };
+
+  template <> struct make_signed<unsigned short> { typedef  short type; };
+  template <> struct make_signed<unsigned int> { typedef int type; };
+  template <> struct make_signed<unsigned long> { typedef  long type; };
+  template <> struct make_signed<unsigned long long> { typedef long long type; };
+  template <typename T> struct make_signed<const T> : add_const<typename make_signed<T>::type> {};
+  template <typename T> struct make_signed<volatile T> : add_volatile<typename make_signed<T>::type> {};
+  template <typename T> struct make_signed<const volatile T> : add_const<typename add_volatile<typename make_signed<T>::type>::type> {};
+
+  /// make_unsigned
+  ///\ingroup type_traits
+  template <typename T> struct make_unsigned { typedef  T type; };
+  template <> struct make_unsigned<char> { typedef unsigned char type; };
+  template <> struct make_unsigned<signed char> { typedef unsigned char type; };
+  template <> struct make_unsigned<short> { typedef unsigned short type; };
+
+  template <> struct make_unsigned<wchar_t>
+  {
+    typedef etl::conditional<sizeof(wchar_t) == sizeof(uint16_t),
+                                    uint16_t,
+                                    etl::conditional<sizeof(wchar_t) == sizeof(uint32_t),
+                                                     uint32_t,
+                                                     void>::type>::type type;
+  };
+
+  template <> struct make_unsigned<int> { typedef unsigned int type; };
+  template <> struct make_unsigned<long> { typedef unsigned long type; };
+  template <> struct make_unsigned<long long> { typedef unsigned long long type; };
+  template <typename T> struct make_unsigned<const T> : add_const<typename make_unsigned<T>::type> {};
+  template <typename T> struct make_unsigned<volatile T> : add_volatile<typename make_unsigned<T>::type> {};
+  template <typename T> struct make_unsigned<const volatile T> : add_const<typename add_volatile<typename make_unsigned<T>::type>::type> {};
+
+  /// enable_if
+  ///\ingroup type_traits
+  template <bool B, typename T = void> struct enable_if {};
+  template <typename T> struct enable_if<true, T> { typedef T type; };
+
+  /// extent
+  ///\ingroup type_traits
+  template <typename T, size_t MAXN = 0>
+  struct extent : integral_constant<size_t, 0> {};
+
+  template <typename T>
+  struct extent<T[], 0> : integral_constant<size_t, 0> {};
+
+  template <typename T, size_t MAXN>
+  struct extent<T[], MAXN> : integral_constant<size_t, extent<T, MAXN - 1>::value> {};
+
+  template <typename T, size_t MAXN>
+  struct extent<T[MAXN], 0> : integral_constant<size_t, MAXN> {};
+
+  template <typename T, size_t I, size_t MAXN>
+  struct extent<T[I], MAXN> : integral_constant<size_t, extent<T, MAXN - 1>::value> {};
+
+  /// remove_extent
+  ///\ingroup type_traits
+  template <typename T> struct remove_extent { typedef T type; };
+  template <typename T> struct remove_extent<T[]> { typedef T type; };
+  template <typename T, size_t MAXN> struct remove_extent<T[MAXN]> { typedef T type;};
+
+  /// remove_all_extents
+  ///\ingroup type_traits
+  template <typename T> struct remove_all_extents { typedef T type;};
+  template <typename T> struct remove_all_extents<T[]> { typedef typename remove_all_extents<T>::type type; };
+  template <typename T, size_t MAXN> struct remove_all_extents<T[MAXN]> { typedef typename remove_all_extents<T>::type type; };
+
+  /// rank
+  ///\ingroup type_traits
+  template <typename T>struct rank : integral_constant<size_t, 0> {};
+  template <typename T> struct rank<T[]> : public integral_constant<size_t, rank<T>::value + 1> {};
+  template <typename T, size_t MAXN> struct rank<T[MAXN]> : public integral_constant<size_t, rank<T>::value + 1> {};
+
+  /// decay
+  ///\ingroup type_traits
+  template <typename T>
+  struct decay
+  {
+    typedef typename etl::remove_reference<T>::type U;
+    typedef typename etl::conditional<etl::is_array<U>::value,
+                                      typename etl::remove_extent<U>::type*,
+                                      typename etl::remove_cv<U>::type>::type type;
+  };
+
+  /// is_base_of
+  ///\ingroup type_traits
+  template<typename TBase,
+    typename TDerived,
+    const bool IsFundamental = (etl::is_fundamental<TBase>::value || etl::is_fundamental<TDerived>::value)>
+    struct is_base_of
+  {
+  private:
+
+    template<typename T> struct dummy {};
+    struct internal: TDerived, dummy<int>{};
+
+    static TBase* check(TBase*);
+    template<typename T> static char check(dummy<T>*);
+
+  public:
+
+    static const bool value = (sizeof(check((internal*)0)) == sizeof(TBase*));
+  };
+
+  // For when TBase or TDerived is a fundamental type.
+  template<typename TBase, typename TDerived>
+  struct is_base_of<TBase, TDerived, true>
+  {
+    static const bool value = false;
+  };
+
+  /// Alignment templates.
+  /// These require compiler specific intrinsics.
+  ///\ingroup type_traits
+#ifdef ETL_COMPILER_MICROSOFT
+  template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof(T))> {};
+
+#elif defined(ETL_COMPILER_IAR) || defined(ETL_COMPILER_TI)
+  template <typename T> struct alignment_of : integral_constant<size_t, size_t(__ALIGNOF__(T))> {};
+
+#else
+  template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof__(T))> {};
+
+#endif
+
+  /// Specialisation of 'alignment_of' for 'void'.
+  ///\ingroup type_traits
+  template <> struct alignment_of<void> : integral_constant <size_t, 0>{};
+
+  /*[[[cog
+  import cog
+  cog.outl("//***************************************************************************")
+  cog.outl("/// Template to determine if a type is one of a specified list.")
+  cog.outl("///\ingroup types")
+  cog.outl("//***************************************************************************")
+  cog.outl("template <typename T,")
+  cog.out("          ")
+  cog.out("typename T1, ")
+  for n in range(2, int(IsOneOf)):
+      cog.out("typename T%s = void, " % n)
+      if n % 4 == 0:
+          cog.outl("")
+          cog.out("          ")
+  cog.outl("typename T%s = void>" % IsOneOf)
+  cog.outl("struct is_one_of")
+  cog.outl("{")
+  cog.outl("  static const bool value = ")
+  for n in range(1, int(IsOneOf)):
+      cog.outl("      etl::is_same<T, T%s>::value ||" % n)
+  cog.outl("      etl::is_same<T, T%s>::value;" % IsOneOf)
+  cog.outl("};")
+  ]]]*/
+  /*[[[end]]]*/
+
+  //***************************************************************************
+  // A set of templates to allow related types to be derived.
+  //***************************************************************************
+  // Default.
+  template <typename T>
+  struct types
+  {
+  private:
+
+    typedef typename etl::remove_cv<T>::type type_t;
+
+  public:
+
+    typedef type_t              type;
+    typedef type_t&             reference;
+    typedef const type_t&       const_reference;
+    typedef type_t*             pointer;
+    typedef const type_t*       const_pointer;
+    typedef const type_t* const const_pointer_const;
+  };
+
+  // Pointers.
+  template <typename T>
+  struct types<T*>
+  {
+  private:
+
+    typedef typename etl::remove_cv<T>::type type_t;
+
+  public:
+
+    typedef type_t              type;
+    typedef type_t&             reference;
+    typedef const type_t&       const_reference;
+    typedef type_t*             pointer;
+    typedef const type_t*       const_pointer;
+    typedef const type_t* const const_pointer_const;
+  };
+
+  // Pointers.
+  template <typename T>
+  struct types<T* const>
+  {
+  private:
+
+    typedef typename etl::remove_cv<T>::type type_t;
+
+  public:
+
+    typedef type_t              type;
+    typedef type_t&             reference;
+    typedef const type_t&       const_reference;
+    typedef type_t*             pointer;
+    typedef const type_t* const_pointer;
+    typedef const type_t* const const_pointer_const;
+  };
+
+  // References.
+  template <typename T>
+  struct types<T&>
+  {
+  private:
+
+    typedef typename etl::remove_cv<T>::type type_t;
+
+  public:
+
+    typedef type_t              type;
+    typedef type_t&             reference;
+    typedef const type_t&       const_reference;
+    typedef type_t*             pointer;
+    typedef const type_t*       const_pointer;
+    typedef const type_t* const const_pointer_const;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/u16string.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,224 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_U16STRING__
+#define __ETL_U16STRING__
+
+#include "platform.h"
+#include "basic_string.h"
+#include "hash.h"
+
+#if defined(ETL_COMPILER_MICROSOFT)
+  #undef min
+#endif
+
+namespace etl
+{
+  typedef ibasic_string<char16_t> iu16string;
+
+  //***************************************************************************
+  /// A u16string implementation that uses a fixed size buffer.
+  ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+  ///\ingroup u16string
+  //***************************************************************************
+  template <const size_t MAX_SIZE_>
+  class u16string : public iu16string
+  {
+  public:
+
+    typedef iu16string::value_type value_type;
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    u16string()
+      : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iu16string::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    ///\param other The other string.
+    //*************************************************************************
+    u16string(const etl::u16string<MAX_SIZE_>& other)
+      : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iu16string::initialise();
+      iu16string::assign(other.begin(), other.end());
+    }
+
+    //*************************************************************************
+    /// From other string, position, length.
+    ///\param other The other string.
+    ///\param position The position of the first character.
+    ///\param length   The number of characters. Default = npos.
+    //*************************************************************************
+    u16string(const etl::u16string<MAX_SIZE_>& other, size_t position, size_t length_ = npos)
+      : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
+
+      // Set the length to the exact amount.
+      length_ = (length_ > MAX_SIZE_) ? MAX_SIZE_ : length_;
+
+      iu16string::initialise();
+      iu16string::assign(other.begin() + position, other.begin() + position + length_);
+    }
+
+    //*************************************************************************
+    /// Constructor, from null terminated text.
+    ///\param text The initial text of the u16string.
+    //*************************************************************************
+    u16string(const value_type* text)
+      : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iu16string::initialise();
+      iu16string::assign(text, text + etl::char_traits<value_type>::length(text));
+    }
+
+    //*************************************************************************
+    /// Constructor, from null terminated text and count.
+    ///\param text  The initial text of the u16string.
+    ///\param count The number of characters to copy.
+    //*************************************************************************
+    u16string(const value_type* text, size_t count)
+      : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iu16string::initialise();
+      iu16string::assign(text, text + count);
+    }
+
+    //*************************************************************************
+    /// Constructor, from initial size and value.
+    ///\param initialSize  The initial size of the u16string.
+    ///\param value        The value to fill the u16string with.
+    //*************************************************************************
+    u16string(size_t count, value_type c)
+      : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iu16string::initialise();
+      iu16string::resize(count, c);
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    u16string(TIterator first, TIterator last)
+      : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iu16string::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Returns a sub-string.
+    ///\param position The position of the first character. Default = 0.
+    ///\param length   The number of characters. Default = npos.
+    //*************************************************************************
+    etl::u16string<MAX_SIZE_> substr(size_t position = 0, size_t length_ = npos) const
+    {
+      etl::u16string<MAX_SIZE_> new_string;
+
+      if (position != size())
+      {
+        ETL_ASSERT(position < size(), ETL_ERROR(string_out_of_bounds));
+
+        length_ = std::min(length_, size() - position);
+
+        new_string.assign(buffer + position, buffer + position + length_);
+      }
+
+      return new_string;
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    u16string& operator = (const u16string& rhs)
+    {
+      if (&rhs != this)
+      {
+        iu16string::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    void repair()
+    {
+      etl::iu16string::repair(buffer);
+    }
+
+  private:
+
+    value_type buffer[MAX_SIZE + 1];
+  };
+
+  //*************************************************************************
+  /// Hash function.
+  //*************************************************************************
+#if ETL_8BIT_SUPPORT
+  template <>
+  struct hash<etl::iu16string>
+  {
+    size_t operator()(const etl::iu16string& text) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]),
+                                                         reinterpret_cast<const uint8_t*>(&text[text.size()]));
+    }
+  };
+
+  template <const size_t SIZE>
+  struct hash<etl::u16string<SIZE> >
+  {
+    size_t operator()(const etl::u16string<SIZE>& text) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]),
+                                                         reinterpret_cast<const uint8_t*>(&text[text.size()]));
+    }
+  };
+#endif
+}
+
+#if defined(ETL_COMPILER_MICROSOFT)
+  #define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/u32string.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,224 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_U32STRING__
+#define __ETL_U32STRING__
+
+#include "platform.h"
+#include "basic_string.h"
+#include "hash.h"
+
+#if defined(ETL_COMPILER_MICROSOFT)
+  #undef min
+#endif
+
+namespace etl
+{
+  typedef ibasic_string<char32_t> iu32string;
+
+  //***************************************************************************
+  /// A u32string implementation that uses a fixed size buffer.
+  ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+  ///\ingroup u32string
+  //***************************************************************************
+  template <const size_t MAX_SIZE_>
+  class u32string : public iu32string
+  {
+  public:
+
+    typedef iu32string::value_type value_type;
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    u32string()
+      : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iu32string::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    ///\param other The other string.
+    //*************************************************************************
+    u32string(const etl::u32string<MAX_SIZE_>& other)
+      : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iu32string::initialise();
+      iu32string::assign(other.begin(), other.end());
+    }
+
+    //*************************************************************************
+    /// From other string, position, length.
+    ///\param other The other string.
+    ///\param position The position of the first character.
+    ///\param length   The number of characters. Default = npos.
+    //*************************************************************************
+    u32string(const etl::u32string<MAX_SIZE_>& other, size_t position, size_t length_ = npos)
+      : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
+
+      // Set the length to the exact amount.
+      length_ = (length_ > MAX_SIZE_) ? MAX_SIZE_ : length_;
+
+      iu32string::initialise();
+      iu32string::assign(other.begin() + position, other.begin() + position + length_);
+    }
+
+    //*************************************************************************
+    /// Constructor, from null terminated text.
+    ///\param text The initial text of the u32string.
+    //*************************************************************************
+    u32string(const value_type* text)
+      : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iu32string::initialise();
+      iu32string::assign(text, text + etl::char_traits<value_type>::length(text));
+    }
+
+    //*************************************************************************
+    /// Constructor, from null terminated text and count.
+    ///\param text  The initial text of the u32string.
+    ///\param count The number of characters to copy.
+    //*************************************************************************
+    u32string(const value_type* text, size_t count)
+      : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iu32string::initialise();
+      iu32string::assign(text, text + count);
+    }
+
+    //*************************************************************************
+    /// Constructor, from initial size and value.
+    ///\param initialSize  The initial size of the u32string.
+    ///\param value        The value to fill the u32string with.
+    //*************************************************************************
+    u32string(size_t count, value_type c)
+      : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iu32string::initialise();
+      iu32string::resize(count, c);
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    u32string(TIterator first, TIterator last)
+      : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iu32string::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Returns a sub-string.
+    ///\param position The position of the first character. Default = 0.
+    ///\param length   The number of characters. Default = npos.
+    //*************************************************************************
+    etl::u32string<MAX_SIZE_> substr(size_t position = 0, size_t length_ = npos) const
+    {
+      etl::u32string<MAX_SIZE_> new_string;
+
+      if (position != size())
+      {
+        ETL_ASSERT(position < size(), ETL_ERROR(string_out_of_bounds));
+
+        length_ = std::min(length_, size() - position);
+
+        new_string.assign(buffer + position, buffer + position + length_);
+      }
+
+      return new_string;
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    u32string& operator = (const u32string& rhs)
+    {
+      if (&rhs != this)
+      {
+        iu32string::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    void repair()
+    {
+      etl::iu32string::repair(buffer);
+    }
+
+  private:
+
+    value_type buffer[MAX_SIZE + 1];
+  };
+
+  //*************************************************************************
+  /// Hash function.
+  //*************************************************************************
+#if ETL_8BIT_SUPPORT
+  template <>
+  struct hash<etl::iu32string>
+  {
+    size_t operator()(const etl::iu32string& text) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]),
+                                                         reinterpret_cast<const uint8_t*>(&text[text.size()]));
+    }
+  };
+
+  template <const size_t SIZE>
+  struct hash<etl::u32string<SIZE> >
+  {
+    size_t operator()(const etl::u32string<SIZE>& text) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]),
+                                                         reinterpret_cast<const uint8_t*>(&text[text.size()]));
+    }
+  };
+#endif
+}
+
+#if defined(ETL_COMPILER_MICROSOFT)
+    #define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/unordered_map.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1395 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_UNORDERED_MAP__
+#define __ETL_UNORDERED_MAP__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+#include "platform.h"
+#include "container.h"
+#include "pool.h"
+#include "array.h"
+#include "intrusive_forward_list.h"
+#include "hash.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "nullptr.h"
+#include "vector.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "debug_count.h"
+
+#undef ETL_FILE
+#define ETL_FILE "16"
+
+//*****************************************************************************
+///\defgroup unordered_map unordered_map
+/// A unordered_map with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the unordered_map.
+  ///\ingroup unordered_map
+  //***************************************************************************
+  class unordered_map_exception : public etl::exception
+  {
+  public:
+
+    unordered_map_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Full exception for the unordered_map.
+  ///\ingroup unordered_map
+  //***************************************************************************
+  class unordered_map_full : public etl::unordered_map_exception
+  {
+  public:
+
+    unordered_map_full(string_type file_name_, numeric_type line_number_)
+      : etl::unordered_map_exception(ETL_ERROR_TEXT("unordered_map:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Out of range exception for the unordered_map.
+  ///\ingroup unordered_map
+  //***************************************************************************
+  class unordered_map_out_of_range : public etl::unordered_map_exception
+  {
+  public:
+
+    unordered_map_out_of_range(string_type file_name_, numeric_type line_number_)
+      : etl::unordered_map_exception(ETL_ERROR_TEXT("unordered_map:range", ETL_FILE"B"), file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the unordered_map.
+  ///\ingroup unordered_map
+  //***************************************************************************
+  class unordered_map_iterator : public etl::unordered_map_exception
+  {
+  public:
+
+    unordered_map_iterator(string_type file_name_, numeric_type line_number_)
+      : etl::unordered_map_exception(ETL_ERROR_TEXT("unordered_map:iterator", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for specifically sized unordered_map.
+  /// Can be used as a reference type for all unordered_map containing a specific type.
+  ///\ingroup unordered_map
+  //***************************************************************************
+  template <typename TKey, typename T, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+  class iunordered_map
+  {
+  public:
+
+    typedef std::pair<const TKey, T> value_type;
+
+    typedef TKey              key_type;
+    typedef T                 mapped_type;
+    typedef THash             hasher;
+    typedef TKeyEqual         key_equal;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef size_t            size_type;
+
+
+    typedef typename etl::parameter_type<TKey>::type key_parameter_t;
+
+    typedef etl::forward_link<0> link_t; // Default link.
+
+                                         // The nodes that store the elements.
+    struct node_t : public link_t
+    {
+      node_t(const value_type& key_value_pair_)
+        : key_value_pair(key_value_pair_)
+      {
+      }
+
+      value_type key_value_pair;
+    };
+
+  private:
+
+    typedef etl::intrusive_forward_list<node_t, link_t> bucket_t;
+    typedef etl::ipool pool_t;
+
+  public:
+
+    // Local iterators iterate over one bucket.
+    typedef typename bucket_t::iterator       local_iterator;
+    typedef typename bucket_t::const_iterator local_const_iterator;
+
+    //*********************************************************************
+    class iterator : public std::iterator<std::forward_iterator_tag, T>
+    {
+    public:
+
+      typedef typename iunordered_map::value_type      value_type;
+      typedef typename iunordered_map::key_type        key_type;
+      typedef typename iunordered_map::mapped_type     mapped_type;
+      typedef typename iunordered_map::hasher          hasher;
+      typedef typename iunordered_map::key_equal       key_equal;
+      typedef typename iunordered_map::reference       reference;
+      typedef typename iunordered_map::const_reference const_reference;
+      typedef typename iunordered_map::pointer         pointer;
+      typedef typename iunordered_map::const_pointer   const_pointer;
+      typedef typename iunordered_map::size_type       size_type;
+
+      friend class iunordered_map;
+
+      //*********************************
+      iterator()
+      {
+      }
+
+      //*********************************
+      iterator(const iterator& other)
+        : pbuckets_end(other.pbuckets_end),
+        pbucket(other.pbucket),
+        inode(other.inode)
+      {
+      }
+
+      //*********************************
+      iterator& operator ++()
+      {
+        ++inode;
+
+        // The end of this node list?
+        if (inode == pbucket->end())
+        {
+          // Search for the next non-empty bucket.
+          ++pbucket;
+          while ((pbucket != pbuckets_end) && (pbucket->empty()))
+          {
+            ++pbucket;
+          }
+
+          // If not past the end, get the first node in the bucket.
+          if (pbucket != pbuckets_end)
+          {
+            inode = pbucket->begin();
+          }
+        }
+
+        return *this;
+      }
+
+      //*********************************
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        operator++();
+        return temp;
+      }
+
+      //*********************************
+      iterator operator =(const iterator& other)
+      {
+        pbuckets_end = other.pbuckets_end;
+        pbucket = other.pbucket;
+        inode = other.inode;
+        return *this;
+      }
+
+      //*********************************
+      std::pair<const TKey, T> operator *()
+      {
+        return inode->key_value_pair;
+      }
+
+      //*********************************
+      const_reference operator *() const
+      {
+        return inode->key_value_pair;
+      }
+
+      //*********************************
+      pointer operator &()
+      {
+        return &(inode->key_value_pair);
+      }
+
+      //*********************************
+      const_pointer operator &() const
+      {
+        return &(inode->key_value_pair);
+      }
+
+      //*********************************
+      pointer operator ->()
+      {
+        return &(inode->key_value_pair);
+      }
+
+      //*********************************
+      const_pointer operator ->() const
+      {
+        return &(inode->key_value_pair);
+      }
+
+      //*********************************
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.compare(rhs);
+      }
+
+      //*********************************
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      //*********************************
+      iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
+        : pbuckets_end(pbuckets_end_),
+          pbucket(pbucket_),
+          inode(inode_)
+      {
+      }
+
+      //*********************************
+      bool compare(const iterator& rhs) const
+      {
+        return rhs.inode == inode;
+      }
+
+      //*********************************
+      bucket_t& get_bucket()
+      {
+        return *pbucket;
+      }
+
+      //*********************************
+      bucket_t* get_bucket_list_iterator()
+      {
+        return pbucket;
+      }
+
+      //*********************************
+      local_iterator get_local_iterator()
+      {
+        return inode;
+      }
+
+      bucket_t* pbuckets_end;
+      bucket_t* pbucket;
+      local_iterator inode;
+    };
+
+    //*********************************************************************
+    class const_iterator : public std::iterator<std::forward_iterator_tag, const T>
+    {
+    public:
+
+      typedef typename iunordered_map::value_type      value_type;
+      typedef typename iunordered_map::key_type        key_type;
+      typedef typename iunordered_map::mapped_type     mapped_type;
+      typedef typename iunordered_map::hasher          hasher;
+      typedef typename iunordered_map::key_equal       key_equal;
+      typedef typename iunordered_map::reference       reference;
+      typedef typename iunordered_map::const_reference const_reference;
+      typedef typename iunordered_map::pointer         pointer;
+      typedef typename iunordered_map::const_pointer   const_pointer;
+      typedef typename iunordered_map::size_type       size_type;
+
+      friend class iunordered_map;
+      friend class iterator;
+
+      //*********************************
+      const_iterator()
+      {
+      }
+
+      //*********************************
+      const_iterator(const typename iunordered_map::iterator& other)
+        : pbuckets_end(other.pbuckets_end),
+          pbucket(other.pbucket),
+          inode(other.inode)
+      {
+      }
+
+      //*********************************
+      const_iterator(const const_iterator& other)
+        : pbuckets_end(other.pbuckets_end),
+          pbucket(other.pbucket),
+          inode(other.inode)
+      {
+      }
+
+      //*********************************
+      const_iterator& operator ++()
+      {
+        ++inode;
+
+        // The end of this node list?
+        if (inode == pbucket->end())
+        {
+          // Search for the next non-empty bucket.
+          ++pbucket;
+          while ((pbucket != pbuckets_end) && (pbucket->empty()))
+          {
+            ++pbucket;
+          }
+
+          // If not past the end, get the first node in the bucket.
+          if (pbucket != pbuckets_end)
+          {
+            inode = pbucket->begin();
+          }
+        }
+
+        return *this;
+      }
+
+      //*********************************
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        operator++();
+        return temp;
+      }
+
+      //*********************************
+      const_iterator operator =(const const_iterator& other)
+      {
+        pbuckets_end = other.pbuckets_end;
+        pbucket = other.pbucket;
+        inode = other.inode;
+        return *this;
+      }
+
+      //*********************************
+      const_reference operator *() const
+      {
+        return inode->key_value_pair;
+      }
+
+      //*********************************
+      const_pointer operator &() const
+      {
+        return &(inode->key_value_pair);
+      }
+
+      //*********************************
+      const_pointer operator ->() const
+      {
+        return &(inode->key_value_pair);
+      }
+
+      //*********************************
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.compare(rhs);
+      }
+
+      //*********************************
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      //*********************************
+      const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
+        : pbuckets_end(pbuckets_end_),
+          pbucket(pbucket_),
+          inode(inode_)
+      {
+      }
+
+      //*********************************
+      bool compare(const const_iterator& rhs) const
+      {
+        return rhs.inode == inode;
+      }
+
+      //*********************************
+      bucket_t& get_bucket()
+      {
+        return *pbucket;
+      }
+
+      //*********************************
+      bucket_t* get_bucket_list_iterator()
+      {
+        return pbucket;
+      }
+
+      //*********************************
+      local_iterator get_local_iterator()
+      {
+        return inode;
+      }
+
+      bucket_t* pbuckets_end;
+      bucket_t* pbucket;
+      local_iterator inode;
+    };
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the unordered_map.
+    ///\return An iterator to the beginning of the unordered_map.
+    //*********************************************************************
+    iterator begin()
+    {
+      return iterator((pbuckets + number_of_buckets), first, first->begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_map.
+    ///\return A const iterator to the beginning of the unordered_map.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator((pbuckets + number_of_buckets), first, first->begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_map.
+    ///\return A const iterator to the beginning of the unordered_map.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator((pbuckets + number_of_buckets), first, first->begin());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the unordered_map bucket.
+    ///\return An iterator to the beginning of the unordered_map bucket.
+    //*********************************************************************
+    local_iterator begin(size_t i)
+    {
+      return (*pbuckets)[i].begin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_map bucket.
+    ///\return A const iterator to the beginning of the unordered_map bucket.
+    //*********************************************************************
+    local_const_iterator begin(size_t i) const
+    {
+      return (*pbuckets)[i].cbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_map bucket.
+    ///\return A const iterator to the beginning of the unordered_map bucket.
+    //*********************************************************************
+    local_const_iterator cbegin(size_t i) const
+    {
+      return (*pbuckets)[i].cbegin();
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the unordered_map.
+    ///\return An iterator to the end of the unordered_map.
+    //*********************************************************************
+    iterator end()
+    {
+      return iterator((pbuckets + number_of_buckets), last, last->end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_map.
+    ///\return A const iterator to the end of the unordered_map.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return const_iterator((pbuckets + number_of_buckets), last, last->end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_map.
+    ///\return A const iterator to the end of the unordered_map.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator((pbuckets + number_of_buckets), last, last->end());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the unordered_map bucket.
+    ///\return An iterator to the end of the unordered_map bucket.
+    //*********************************************************************
+    local_iterator end(size_t i)
+    {
+      return (*pbuckets)[i].end();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_map bucket.
+    ///\return A const iterator to the end of the unordered_map bucket.
+    //*********************************************************************
+    local_const_iterator end(size_t i) const
+    {
+      return (*pbuckets)[i].cend();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_map bucket.
+    ///\return A const iterator to the end of the unordered_map bucket.
+    //*********************************************************************
+    local_const_iterator cend(size_t i) const
+    {
+      return (*pbuckets)[i].cend();
+    }
+
+    //*********************************************************************
+    /// Returns the bucket index for the key.
+    ///\return The bucket index for the key.
+    //*********************************************************************
+    size_type get_bucket_index(key_parameter_t key) const
+    {
+      return key_hash_function(key) % number_of_buckets;
+    }
+
+    //*********************************************************************
+    /// Returns the size of the bucket key.
+    ///\return The bucket size of the bucket key.
+    //*********************************************************************
+    size_type bucket_size(key_parameter_t key) const
+    {
+      size_t index = bucket(key);
+
+      return std::distance((*pbuckets)[index].begin(), (*pbuckets)[index].end());
+    }
+
+    //*********************************************************************
+    /// Returns the maximum number of the buckets the container can hold.
+    ///\return The maximum number of the buckets the container can hold.
+    //*********************************************************************
+    size_type max_bucket_count() const
+    {
+      return number_of_buckets;
+    }
+
+    //*********************************************************************
+    /// Returns the number of the buckets the container holds.
+    ///\return The number of the buckets the container holds.
+    //*********************************************************************
+    size_type bucket_count() const
+    {
+      return number_of_buckets;
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'key'
+    ///\param key The key.
+    ///\return A reference to the value at index 'key'
+    //*********************************************************************
+    mapped_type& operator [](key_parameter_t key)
+    {
+      // Find the bucket.
+      bucket_t* pbucket = pbuckets + get_bucket_index(key);
+
+      // Find the first node in the bucket.
+      local_iterator inode = pbucket->begin();
+
+      // Walk the list looking for the right one.
+      while (inode != pbucket->end())
+      {
+        // Equal keys?
+        if (key_equal_function(key, inode->key_value_pair.first))
+        {
+          // Found a match.
+          return inode->key_value_pair.second;
+        }
+        else
+        {
+          ++inode;
+        }
+      }
+
+      // Doesn't exist, so add a new one.
+      // Get a new node.
+      node_t& node = *pnodepool->allocate<node_t>();
+      ::new (&node.key_value_pair) value_type(key, T());
+      ++construct_count;
+
+      pbucket->insert_after(pbucket->before_begin(), node);
+
+      return pbucket->begin()->key_value_pair.second;
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'key'
+    /// If asserts or exceptions are enabled, emits an etl::unordered_map_out_of_range if the key is not in the range.
+    ///\param key The key.
+    ///\return A reference to the value at index 'key'
+    //*********************************************************************
+    mapped_type& at(key_parameter_t key)
+    {
+      // Find the bucket.
+      bucket_t* pbucket = pbuckets + get_bucket_index(key);
+
+      // Find the first node in the bucket.
+      local_iterator inode = pbucket->begin();
+
+      // Walk the list looking for the right one.
+      while (inode != pbucket->end())
+      {
+        // Equal keys?
+        if (key_equal_function(key, inode->key_value_pair.first))
+        {
+          // Found a match.
+          return inode->key_value_pair.second;
+        }
+        else
+        {
+          ++inode;
+        }
+      }
+
+      // Doesn't exist.
+      ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range));
+
+      return begin()->second;
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'key'
+    /// If asserts or exceptions are enabled, emits an etl::unordered_map_out_of_range if the key is not in the range.
+    ///\param key The key.
+    ///\return A const reference to the value at index 'key'
+    //*********************************************************************
+    const mapped_type& at(key_parameter_t key) const
+    {
+      // Find the bucket.
+      bucket_t* pbucket = pbuckets + get_bucket_index(key);
+
+      // Find the first node in the bucket.
+      local_iterator inode = pbucket->begin();
+
+      // Walk the list looking for the right one.
+      while (inode != pbucket->end())
+      {
+        // Equal keys?
+        if (key_equal_function(key, inode->key_value_pair.first))
+        {
+          // Found a match.
+          return inode->key_value_pair.second;
+        }
+        else
+        {
+          ++inode;
+        }
+      }
+
+      // Doesn't exist.
+      ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range));
+
+      return begin()->second;
+    }
+
+    //*********************************************************************
+    /// Assigns values to the unordered_map.
+    /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map does not have enough free space.
+    /// If asserts or exceptions are enabled, emits unordered_map_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first_, TIterator last_)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first_, last_);
+      ETL_ASSERT(d >= 0, ETL_ERROR(unordered_map_iterator));
+      ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_map_full));
+#endif
+
+      clear();
+
+      while (first_ != last_)
+      {
+        insert(*first_++);
+      }
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the unordered_map.
+    /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map is already full.
+    ///\param value The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(const value_type& key_value_pair)
+    {
+      std::pair<iterator, bool> result(end(), false);
+
+      ETL_ASSERT(!full(), ETL_ERROR(unordered_map_full));
+
+      const key_type&    key = key_value_pair.first;
+      const mapped_type& mapped = key_value_pair.second;
+
+      // Get the hash index.
+      size_t index = get_bucket_index(key);
+
+      // Get the bucket & bucket iterator.
+      bucket_t* pbucket = pbuckets + index;
+      bucket_t& bucket = *pbucket;
+
+      size_t s = pbuckets->size();
+
+      // The first one in the bucket?
+      if (bucket.empty())
+      {
+        // Get a new node.
+        node_t& node = *pnodepool->allocate<node_t>();
+        ::new (&node.key_value_pair) value_type(key_value_pair);
+        ++construct_count;
+
+        // Just add the pointer to the bucket;
+        bucket.insert_after(bucket.before_begin(), node);
+
+        result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
+        result.second = true;
+
+        adjust_first_last_markers(pbucket);
+      }
+      else
+      {
+        // Step though the bucket looking for a place to insert.
+        local_iterator inode_previous = bucket.before_begin();
+        local_iterator inode = bucket.begin();
+
+        while (inode != bucket.end())
+        {
+          // Do we already have this key?
+          if (inode->key_value_pair.first == key)
+          {
+            break;
+          }
+
+          ++inode_previous;
+          ++inode;
+        }
+
+        // Not already there?
+        if (inode == bucket.end())
+        {
+          // Get a new node.
+          node_t& node = *pnodepool->allocate<node_t>();
+          ::new (&node.key_value_pair) value_type(key_value_pair);
+          ++construct_count;
+
+          // Add the node to the end of the bucket;
+          bucket.insert_after(inode_previous, node);
+          ++inode_previous;
+
+          result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
+          result.second = true;
+        }
+      }
+
+      return result;
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the unordered_map.
+    /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map is already full.
+    ///\param position The position to insert at.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(const_iterator position, const value_type& key_value_pair)
+    {
+      return insert(key_value_pair).first;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the unordered_map.
+    /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first_, TIterator last_)
+    {
+      while (first_ != last_)
+      {
+        insert(*first_++);
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param key The key to erase.
+    ///\return The number of elements erased. 0 or 1.
+    //*********************************************************************
+    size_t erase(key_parameter_t key)
+    {
+      size_t n = 0;
+      size_t index = get_bucket_index(key);
+
+      bucket_t& bucket = pbuckets[index];
+
+      local_iterator iprevious = bucket.before_begin();
+      local_iterator icurrent = bucket.begin();
+
+      // Search for the key, if we have it.
+      while ((icurrent != bucket.end()) && (icurrent->key_value_pair.first != key))
+      {
+        ++iprevious;
+        ++icurrent;
+      }
+
+      // Did we find it?
+      if (icurrent != bucket.end())
+      {
+        bucket.erase_after(iprevious);          // Unlink from the bucket.
+        icurrent->key_value_pair.~value_type(); // Destroy the value.
+        pnodepool->release(&*icurrent);         // Release it back to the pool.
+        n = 1;
+        --construct_count;
+      }
+
+      return n;
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param ielement Iterator to the element.
+    //*********************************************************************
+    iterator erase(const_iterator ielement)
+    {
+      // Make a note of the next one.
+      iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
+      ++inext;
+
+      bucket_t&      bucket = ielement.get_bucket();
+      local_iterator iprevious = bucket.before_begin();
+      local_iterator icurrent = ielement.get_local_iterator();
+
+      // Find the node previous to the one we're interested in.
+      while (iprevious->etl_next != &*icurrent)
+      {
+        ++iprevious;
+      }
+
+      bucket.erase_after(iprevious);          // Unlink from the bucket.
+      icurrent->key_value_pair.~value_type(); // Destroy the value.
+      pnodepool->release(&*icurrent);         // Release it back to the pool.
+      --construct_count;
+
+      return inext;
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed to by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    //*********************************************************************
+    iterator erase(const_iterator first_, const_iterator last_)
+    {
+      // Make a note of the last.
+      iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator());
+
+      // Get the starting point.
+      bucket_t*      pbucket   = first_.get_bucket_list_iterator();
+      local_iterator iprevious = pbucket->before_begin();
+      local_iterator icurrent  = first_.get_local_iterator();
+      local_iterator iend      = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent.
+
+      // Find the node previous to the first one.
+      while (iprevious->etl_next != &*icurrent)
+      {
+        ++iprevious;
+      }
+
+      while (icurrent != iend)
+      {
+
+        local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket.
+        icurrent->key_value_pair.~value_type(); // Destroy the value.
+        pnodepool->release(&*icurrent);         // Release it back to the pool.
+        --construct_count;
+
+        icurrent = inext;
+
+        // Are we there yet?
+        if (icurrent != iend)
+        {
+          // At the end of this bucket?
+          if ((icurrent == pbucket->end()))
+          {
+            // Find the next non-empty one.
+            do
+            {
+              ++pbucket;
+            } while (pbucket->empty());
+
+            iprevious = pbucket->before_begin();
+            icurrent = pbucket->begin();
+          }
+        }
+      }
+
+      return result;
+    }
+
+    //*************************************************************************
+    /// Clears the unordered_map.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*********************************************************************
+    /// Counts an element.
+    ///\param key The key to search for.
+    ///\return 1 if the key exists, otherwise 0.
+    //*********************************************************************
+    size_t count(key_parameter_t key) const
+    {
+      return (find(key) == end()) ? 0 : 1;
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator to the element if the key exists, otherwise end().
+    //*********************************************************************
+    iterator find(key_parameter_t key)
+    {
+      size_t index = get_bucket_index(key);
+
+      bucket_t* pbucket = pbuckets + index;
+      bucket_t& bucket = *pbucket;
+
+      // Is the bucket not empty?
+      if (!bucket.empty())
+      {
+        // Step though the list until we find the end or an equivalent key.
+        local_iterator inode = bucket.begin();
+        local_iterator iend = bucket.end();
+
+        while (inode != iend)
+        {
+          // Do we have this one?
+          if (key_equal_function(key, inode->key_value_pair.first))
+          {
+            return iterator((pbuckets + number_of_buckets), pbucket, inode);
+          }
+
+          ++inode;
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator to the element if the key exists, otherwise end().
+    //*********************************************************************
+    const_iterator find(key_parameter_t key) const
+    {
+      size_t index = get_bucket_index(key);
+
+      bucket_t* pbucket = pbuckets + index;
+      bucket_t& bucket = *pbucket;
+
+      // Is the bucket not empty?
+      if (!bucket.empty())
+      {
+        // Step though the list until we find the end or an equivalent key.
+        local_iterator inode = bucket.begin();
+        local_iterator iend = bucket.end();
+
+        while (inode != iend)
+        {
+          // Do we have this one?
+          if (key_equal_function(key, inode->key_value_pair.first))
+          {
+            return iterator((pbuckets + number_of_buckets), pbucket, inode);
+          }
+
+          ++inode;
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Returns a range containing all elements with key key in the container.
+    /// The range is defined by two iterators, the first pointing to the first
+    /// element of the wanted range and the second pointing past the last
+    /// element of the range.
+    ///\param key The key to search for.
+    ///\return An iterator pair to the range of elements if the key exists, otherwise end().
+    //*********************************************************************
+    std::pair<iterator, iterator> equal_range(key_parameter_t key)
+    {
+      iterator f = find(key);
+      iterator l = f;
+
+      if (l != end())
+      {
+        ++l;
+      }
+
+      return std::pair<iterator, iterator>(f, l);
+    }
+
+    //*********************************************************************
+    /// Returns a range containing all elements with key key in the container.
+    /// The range is defined by two iterators, the first pointing to the first
+    /// element of the wanted range and the second pointing past the last
+    /// element of the range.
+    ///\param key The key to search for.
+    ///\return A const iterator pair to the range of elements if the key exists, otherwise end().
+    //*********************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
+    {
+      const_iterator f = find(key);
+      const_iterator l = f;
+
+      if (l != end())
+      {
+        ++l;
+      }
+
+      return std::pair<const_iterator, const_iterator>(f, l);
+    }
+
+    //*************************************************************************
+    /// Gets the size of the unordered_map.
+    //*************************************************************************
+    size_type size() const
+    {
+      return pnodepool->size();
+    }
+
+    //*************************************************************************
+    /// Gets the maximum possible size of the unordered_map.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return pnodepool->max_size();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the unordered_map is empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return pnodepool->empty();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the unordered_map is full.
+    //*************************************************************************
+    bool full() const
+    {
+      return pnodepool->full();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return pnodepool->available();
+    }
+
+    //*************************************************************************
+    /// Returns the load factor = size / bucket_count.
+    ///\return The load factor = size / bucket_count.
+    //*************************************************************************
+    float load_factor() const
+    {
+      return static_cast<float>(size()) / static_cast<float>(bucket_count());
+    }
+
+    //*************************************************************************
+    /// Returns the function that hashes the keys.
+    ///\return The function that hashes the keys..
+    //*************************************************************************
+    hasher hash_function() const
+    {
+      return key_hash_function;
+    }
+
+    //*************************************************************************
+    /// Returns the function that compares the keys.
+    ///\return The function that compares the keys..
+    //*************************************************************************
+    key_equal key_eq() const
+    {
+      return key_equal_function;
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    iunordered_map& operator = (const iunordered_map& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    iunordered_map(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_)
+      : pnodepool(&node_pool_),
+        pbuckets(pbuckets_),
+        number_of_buckets(number_of_buckets_)
+    {
+    }
+
+    //*********************************************************************
+    /// Initialise the unordered_map.
+    //*********************************************************************
+    void initialise()
+    {
+      if (!empty())
+      {
+        // For each bucket...
+        for (size_t i = 0; i < number_of_buckets; ++i)
+        {
+          bucket_t& bucket = pbuckets[i];
+
+          if (!bucket.empty())
+          {
+            // For each item in the bucket...
+            local_iterator it = bucket.begin();
+
+            while (it != bucket.end())
+            {
+              // Destroy the value contents.
+              it->key_value_pair.~value_type();
+              --construct_count;
+
+              ++it;
+            }
+
+            // Now it's safe to clear the bucket.
+            bucket.clear();
+          }
+        }
+
+        // Now it's safe to clear the entire pool in one go.
+        pnodepool->release_all();
+      }
+
+      first = pbuckets;
+      last = first;
+    }
+
+  private:
+
+    //*********************************************************************
+    /// Adjust the first and last markers according to the new entry.
+    //*********************************************************************
+    void adjust_first_last_markers(bucket_t* pbucket)
+    {
+      if (pbucket < first)
+      {
+        first = pbucket;
+      }
+      else if (pbucket > last)
+      {
+        last = pbucket;
+      }
+    }
+
+    // Disable copy construction.
+    iunordered_map(const iunordered_map&);
+
+    /// The pool of data nodes used in the list.
+    pool_t* pnodepool;
+
+    /// The bucket list.
+    bucket_t* pbuckets;
+
+    /// The number of buckets.
+    const size_t number_of_buckets;
+
+    /// The first and last pointers to buckets with values.
+    bucket_t* first;
+    bucket_t* last;
+
+    /// The function that creates the hashes.
+    hasher key_hash_function;
+
+    /// The function that compares the keys for equality.
+    key_equal key_equal_function;
+
+    /// For library debugging purposes only.
+    etl::debug_count construct_count;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first unordered_map.
+  ///\param rhs Reference to the second unordered_map.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup unordered_map
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator ==(const etl::iunordered_map<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_map<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first unordered_map.
+  ///\param rhs Reference to the second unordered_map.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup unordered_map
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator !=(const etl::iunordered_map<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_map<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //*************************************************************************
+  /// A templated unordered_map implementation that uses a fixed size buffer.
+  //*************************************************************************
+  template <typename TKey, typename TValue, const size_t MAX_SIZE_, const size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+  class unordered_map : public etl::iunordered_map<TKey, TValue, THash, TKeyEqual>
+  {
+  private:
+
+    typedef iunordered_map<TKey, TValue, THash, TKeyEqual> base;
+
+  public:
+
+    static const size_t MAX_SIZE    = MAX_SIZE_;
+    static const size_t MAX_BUCKETS = MAX_BUCKETS_;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    unordered_map()
+      : base(node_pool, buckets, MAX_BUCKETS_)
+    {
+      base::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    unordered_map(const unordered_map& other)
+      : base(node_pool, buckets, MAX_BUCKETS_)
+    {
+      base::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    unordered_map(TIterator first_, TIterator last_)
+      : base(node_pool, buckets, MAX_BUCKETS_)
+    {
+      base::assign(first_, last_);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~unordered_map()
+    {
+      base::initialise();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    unordered_map& operator = (const unordered_map& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        base::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    /// The pool of nodes used for the unordered_map.
+    etl::pool<typename base::node_t, MAX_SIZE> node_pool;
+
+    /// The buckets of node lists.
+    etl::intrusive_forward_list<typename base::node_t> buckets[MAX_BUCKETS_];
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/unordered_multimap.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1305 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_UNORDERED_MULTIMAP__
+#define __ETL_UNORDERED_MULTIMAP__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+#include "platform.h"
+#include "container.h"
+#include "pool.h"
+#include "vector.h"
+#include "intrusive_forward_list.h"
+#include "hash.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "nullptr.h"
+#include "pool.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "debug_count.h"
+
+#undef ETL_FILE
+#define ETL_FILE "25"
+
+//*****************************************************************************
+///\defgroup unordered_multimap unordered_multimap
+/// A unordered_multimap with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the unordered_multimap.
+  ///\ingroup unordered_multimap
+  //***************************************************************************
+  class unordered_multimap_exception : public etl::exception
+  {
+  public:
+
+    unordered_multimap_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Full exception for the unordered_multimap.
+  ///\ingroup unordered_multimap
+  //***************************************************************************
+  class unordered_multimap_full : public etl::unordered_multimap_exception
+  {
+  public:
+
+    unordered_multimap_full(string_type file_name_, numeric_type line_number_)
+      : etl::unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Out of range exception for the unordered_multimap.
+  ///\ingroup unordered_multimap
+  //***************************************************************************
+  class unordered_multimap_out_of_range : public etl::unordered_multimap_exception
+  {
+  public:
+
+    unordered_multimap_out_of_range(string_type file_name_, numeric_type line_number_)
+      : etl::unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:range", ETL_FILE"B"), file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the unordered_multimap.
+  ///\ingroup unordered_multimap
+  //***************************************************************************
+  class unordered_multimap_iterator : public etl::unordered_multimap_exception
+  {
+  public:
+
+    unordered_multimap_iterator(string_type file_name_, numeric_type line_number_)
+      : etl::unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:iterator", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for specifically sized unordered_multimap.
+  /// Can be used as a reference type for all unordered_multimap containing a specific type.
+  ///\ingroup unordered_multimap
+  //***************************************************************************
+  template <typename TKey, typename T, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+  class iunordered_multimap
+  {
+  public:
+
+    typedef std::pair<const TKey, T> value_type;
+
+    typedef TKey              key_type;
+    typedef T                 mapped_type;
+    typedef THash             hasher;
+    typedef TKeyEqual         key_equal;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef size_t            size_type;
+
+
+    typedef typename etl::parameter_type<TKey>::type key_parameter_t;
+
+    typedef etl::forward_link<0> link_t; // Default link.
+
+    struct node_t : public link_t // The nodes that store the elements.
+    {
+      node_t(const value_type& key_value_pair_)
+        : key_value_pair(key_value_pair_)
+      {
+      }
+
+      value_type key_value_pair;
+    };
+
+  private:
+
+    typedef etl::intrusive_forward_list<node_t, link_t> bucket_t;
+    typedef etl::ipool pool_t;
+
+  public:
+
+    // Local iterators iterate over one bucket.
+    typedef typename bucket_t::iterator       local_iterator;
+    typedef typename bucket_t::const_iterator local_const_iterator;
+
+    //*********************************************************************
+    class iterator : public std::iterator<std::forward_iterator_tag, T>
+    {
+    public:
+
+      typedef typename iunordered_multimap::value_type      value_type;
+      typedef typename iunordered_multimap::key_type        key_type;
+      typedef typename iunordered_multimap::mapped_type     mapped_type;
+      typedef typename iunordered_multimap::hasher          hasher;
+      typedef typename iunordered_multimap::key_equal       key_equal;
+      typedef typename iunordered_multimap::reference       reference;
+      typedef typename iunordered_multimap::const_reference const_reference;
+      typedef typename iunordered_multimap::pointer         pointer;
+      typedef typename iunordered_multimap::const_pointer   const_pointer;
+      typedef typename iunordered_multimap::size_type       size_type;
+
+      friend class iunordered_multimap;
+
+      //*********************************
+      iterator()
+      {
+      }
+
+      //*********************************
+      iterator(const iterator& other)
+        : pbuckets_end(other.pbuckets_end),
+        pbucket(other.pbucket),
+        inode(other.inode)
+      {
+      }
+
+      //*********************************
+      iterator& operator ++()
+      {
+        ++inode;
+
+        // The end of this node list?
+        if (inode == pbucket->end())
+        {
+          // Search for the next non-empty bucket.
+          ++pbucket;
+          while ((pbucket != pbuckets_end) && (pbucket->empty()))
+          {
+            ++pbucket;
+          }
+
+          // If not past the end, get the first node in the bucket.
+          if (pbucket != pbuckets_end)
+          {
+            inode = pbucket->begin();
+          }
+        }
+
+        return *this;
+      }
+
+      //*********************************
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        operator++();
+        return temp;
+      }
+
+      //*********************************
+      iterator operator =(const iterator& other)
+      {
+        pbuckets_end = other.pbuckets_end;
+        pbucket = other.pbucket;
+        inode = other.inode;
+        return *this;
+      }
+
+      //*********************************
+      std::pair<const TKey, T> operator *()
+      {
+        return inode->key_value_pair;
+      }
+
+      //*********************************
+      const_reference operator *() const
+      {
+        return inode->key_value_pair;
+      }
+
+      //*********************************
+      pointer operator &()
+      {
+        return &(inode->key_value_pair);
+      }
+
+      //*********************************
+      const_pointer operator &() const
+      {
+        return &(inode->key_value_pair);
+      }
+
+      //*********************************
+      pointer operator ->()
+      {
+        return &(inode->key_value_pair);
+      }
+
+      //*********************************
+      const_pointer operator ->() const
+      {
+        return &(inode->key_value_pair);
+      }
+
+      //*********************************
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.compare(rhs);
+      }
+
+      //*********************************
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      //*********************************
+      iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
+        : pbuckets_end(pbuckets_end_),
+          pbucket(pbucket_),
+          inode(inode_)
+      {
+      }
+
+      //*********************************
+      bool compare(const iterator& rhs) const
+      {
+        return rhs.inode == inode;
+      }
+
+      //*********************************
+      bucket_t& get_bucket()
+      {
+        return *pbucket;
+      }
+
+      //*********************************
+      bucket_t*& get_bucket_list_iterator()
+      {
+        return pbucket;
+      }
+
+      //*********************************
+      local_iterator get_local_iterator()
+      {
+        return inode;
+      }
+
+      bucket_t* pbuckets_end;
+      bucket_t* pbucket;
+      local_iterator       inode;
+    };
+
+    //*********************************************************************
+    class const_iterator : public std::iterator<std::forward_iterator_tag, const T>
+    {
+    public:
+
+      typedef typename iunordered_multimap::value_type      value_type;
+      typedef typename iunordered_multimap::key_type        key_type;
+      typedef typename iunordered_multimap::mapped_type     mapped_type;
+      typedef typename iunordered_multimap::hasher          hasher;
+      typedef typename iunordered_multimap::key_equal       key_equal;
+      typedef typename iunordered_multimap::reference       reference;
+      typedef typename iunordered_multimap::const_reference const_reference;
+      typedef typename iunordered_multimap::pointer         pointer;
+      typedef typename iunordered_multimap::const_pointer   const_pointer;
+      typedef typename iunordered_multimap::size_type       size_type;
+
+      friend class iunordered_multimap;
+      friend class iterator;
+
+      //*********************************
+      const_iterator()
+      {
+      }
+
+      //*********************************
+      const_iterator(const typename iunordered_multimap::iterator& other)
+        : pbuckets_end(other.pbuckets_end),
+        pbucket(other.pbucket),
+        inode(other.inode)
+      {
+      }
+
+      //*********************************
+      const_iterator(const const_iterator& other)
+        : pbuckets_end(other.pbuckets_end),
+        pbucket(other.pbucket),
+        inode(other.inode)
+      {
+      }
+
+      //*********************************
+      const_iterator& operator ++()
+      {
+        ++inode;
+
+        // The end of this node list?
+        if (inode == pbucket->end())
+        {
+          // Search for the next non-empty bucket.
+
+          ++pbucket;
+          while ((pbucket != pbuckets_end) && (pbucket->empty()))
+          {
+            ++pbucket;
+          }
+
+          // If not past the end, get the first node in the bucket.
+          if (pbucket != pbuckets_end)
+          {
+            inode = pbucket->begin();
+          }
+        }
+
+        return *this;
+      }
+
+      //*********************************
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        operator++();
+        return temp;
+      }
+
+      //*********************************
+      const_iterator operator =(const const_iterator& other)
+      {
+        pbuckets_end = other.pbuckets_end;
+        pbucket = other.pbucket;
+        inode = other.inode;
+        return *this;
+      }
+
+      //*********************************
+      const_reference operator *() const
+      {
+        return inode->key_value_pair;
+      }
+
+      //*********************************
+      const_pointer operator &() const
+      {
+        return &(inode->key_value_pair);
+      }
+
+      //*********************************
+      const_pointer operator ->() const
+      {
+        return &(inode->key_value_pair);
+      }
+
+      //*********************************
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.compare(rhs);
+      }
+
+      //*********************************
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      //*********************************
+      const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
+        : pbuckets_end(pbuckets_end_),
+          pbucket(pbucket_),
+          inode(inode_)
+      {
+      }
+
+      //*********************************
+      bool compare(const const_iterator& rhs) const
+      {
+        return rhs.inode == inode;
+      }
+
+      //*********************************
+      bucket_t& get_bucket()
+      {
+        return *pbucket;
+      }
+
+      //*********************************
+      bucket_t*& get_bucket_list_iterator()
+      {
+        return pbucket;
+      }
+
+      //*********************************
+      local_iterator get_local_iterator()
+      {
+        return inode;
+      }
+
+      bucket_t* pbuckets_end;
+      bucket_t* pbucket;
+      local_iterator       inode;
+    };
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the unordered_multimap.
+    ///\return An iterator to the beginning of the unordered_multimap.
+    //*********************************************************************
+    iterator begin()
+    {
+      return iterator((pbuckets + number_of_buckets), first, first->begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_multimap.
+    ///\return A const iterator to the beginning of the unordered_multimap.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator((pbuckets + number_of_buckets), first, first->begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_multimap.
+    ///\return A const iterator to the beginning of the unordered_multimap.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator((pbuckets + number_of_buckets), first, first->begin());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the unordered_multimap bucket.
+    ///\return An iterator to the beginning of the unordered_multimap bucket.
+    //*********************************************************************
+    local_iterator begin(size_t i)
+    {
+      return pbuckets[i].begin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_multimap bucket.
+    ///\return A const iterator to the beginning of the unordered_multimap bucket.
+    //*********************************************************************
+    local_const_iterator begin(size_t i) const
+    {
+      return pbuckets[i].cbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_multimap bucket.
+    ///\return A const iterator to the beginning of the unordered_multimap bucket.
+    //*********************************************************************
+    local_const_iterator cbegin(size_t i) const
+    {
+      return pbuckets[i].cbegin();
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the unordered_multimap.
+    ///\return An iterator to the end of the unordered_multimap.
+    //*********************************************************************
+    iterator end()
+    {
+      return iterator((pbuckets + number_of_buckets), last, last->end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_multimap.
+    ///\return A const iterator to the end of the unordered_multimap.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return const_iterator((pbuckets + number_of_buckets), last, last->end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_multimap.
+    ///\return A const iterator to the end of the unordered_multimap.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator((pbuckets + number_of_buckets), last, last->end());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the unordered_multimap bucket.
+    ///\return An iterator to the end of the unordered_multimap bucket.
+    //*********************************************************************
+    local_iterator end(size_t i)
+    {
+      return pbuckets[i].end();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_multimap bucket.
+    ///\return A const iterator to the end of the unordered_multimap bucket.
+    //*********************************************************************
+    local_const_iterator end(size_t i) const
+    {
+      return pbuckets[i].cend();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_multimap bucket.
+    ///\return A const iterator to the end of the unordered_multimap bucket.
+    //*********************************************************************
+    local_const_iterator cend(size_t i) const
+    {
+      return pbuckets[i].cend();
+    }
+
+    //*********************************************************************
+    /// Returns the bucket index for the key.
+    ///\return The bucket index for the key.
+    //*********************************************************************
+    size_type get_bucket_index(key_parameter_t key) const
+    {
+      return key_hash_function(key) % number_of_buckets;
+    }
+
+    //*********************************************************************
+    /// Returns the size of the bucket key.
+    ///\return The bucket size of the bucket key.
+    //*********************************************************************
+    size_type bucket_size(key_parameter_t key) const
+    {
+      size_t index = bucket(key);
+
+      return std::distance(pbuckets[index].begin(), pbuckets[index].end());
+    }
+
+    //*********************************************************************
+    /// Returns the maximum number of the buckets the container can hold.
+    ///\return The maximum number of the buckets the container can hold.
+    //*********************************************************************
+    size_type max_bucket_count() const
+    {
+      return number_of_buckets;
+    }
+
+    //*********************************************************************
+    /// Returns the number of the buckets the container holds.
+    ///\return The number of the buckets the container holds.
+    //*********************************************************************
+    size_type bucket_count() const
+    {
+      return number_of_buckets;
+    }
+
+    //*********************************************************************
+    /// Assigns values to the unordered_multimap.
+    /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap does not have enough free space.
+    /// If asserts or exceptions are enabled, emits unordered_multimap_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first_, TIterator last_)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first_, last_);
+      ETL_ASSERT(d >= 0, ETL_ERROR(unordered_multimap_iterator));
+      ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_multimap_full));
+#endif
+
+      clear();
+
+      while (first_ != last_)
+      {
+        insert(*first_++);
+      }
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the unordered_multimap.
+    /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap is already full.
+    ///\param value The value to insert.
+    //*********************************************************************
+    iterator insert(const value_type& key_value_pair)
+    {
+      iterator result = end();
+
+      ETL_ASSERT(!full(), ETL_ERROR(unordered_multimap_full));
+
+      const key_type&    key = key_value_pair.first;
+      const mapped_type& mapped = key_value_pair.second;
+
+      // Get the hash index.
+      size_t index = get_bucket_index(key);
+
+      // Get the bucket & bucket iterator.
+      bucket_t* pbucket = pbuckets + index;
+      bucket_t& bucket = *pbucket;
+
+      // The first one in the bucket?
+      if (bucket.empty())
+      {
+        // Get a new node.
+        node_t& node = *pnodepool->allocate<node_t>();
+        ::new (&node.key_value_pair) value_type(key_value_pair);
+        ++construct_count;
+
+        // Just add the pointer to the bucket;
+        bucket.insert_after(bucket.before_begin(), node);
+
+        result = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
+
+        adjust_first_last_markers(pbucket);
+      }
+      else
+      {
+        // Step though the bucket looking for a place to insert.
+        local_iterator inode_previous = bucket.before_begin();
+        local_iterator inode = bucket.begin();
+
+        while (inode != bucket.end())
+        {
+          // Do we already have this key?
+          if (inode->key_value_pair.first == key)
+          {
+            break;
+          }
+
+          ++inode_previous;
+          ++inode;
+        }
+
+        // Get a new node.
+        node_t& node = *pnodepool->allocate<node_t>();
+        ::new (&node.key_value_pair) value_type(key_value_pair);
+        ++construct_count;
+
+        // Add the node to the end of the bucket;
+        bucket.insert_after(inode_previous, node);
+        ++inode_previous;
+
+        result = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
+      }
+
+      return result;
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the unordered_multimap.
+    /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap is already full.
+    ///\param position The position to insert at.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(const_iterator position, const value_type& key_value_pair)
+    {
+      return insert(key_value_pair);
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the unordered_multimap.
+    /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first_, TIterator last_)
+    {
+      while (first_ != last_)
+      {
+        insert(*first_++);
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param key The key to erase.
+    ///\return The number of elements erased.
+    //*********************************************************************
+    size_t erase(key_parameter_t key)
+    {
+      size_t n = 0;
+      size_t bucket_id = get_bucket_index(key);
+
+      bucket_t& bucket = pbuckets[bucket_id];
+
+      local_iterator iprevious = bucket.before_begin();
+      local_iterator icurrent = bucket.begin();
+
+      while (icurrent != bucket.end())
+      {
+        if (icurrent->key_value_pair.first == key)
+        {
+          bucket.erase_after(iprevious);          // Unlink from the bucket.
+          icurrent->key_value_pair.~value_type(); // Destroy the value.
+          pnodepool->release(&*icurrent);         // Release it back to the pool.
+          ++n;
+          icurrent = iprevious;
+          --construct_count;
+        }
+        else
+        {
+          ++iprevious;
+        }
+
+        ++icurrent;
+      }
+
+      return n;
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param ielement Iterator to the element.
+    //*********************************************************************
+    iterator erase(const_iterator ielement)
+    {
+      // Make a note of the next one.
+      iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
+      ++inext;
+
+      bucket_t&      bucket = ielement.get_bucket();
+      local_iterator iprevious = bucket.before_begin();
+      local_iterator icurrent = ielement.get_local_iterator();
+
+      // Find the node previous to the one we're interested in.
+      while (iprevious->etl_next != &*icurrent)
+      {
+        ++iprevious;
+      }
+
+      bucket.erase_after(iprevious);          // Unlink from the bucket.
+      icurrent->key_value_pair.~value_type(); // Destroy the value.
+      pnodepool->release(&*icurrent);         // Release it back to the pool.
+      --construct_count;
+
+      return inext;
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed to by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    //*********************************************************************
+    iterator erase(const_iterator first_, const_iterator last_)
+    {
+      // Make a note of the last.
+      iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator());
+
+      // Get the starting point.
+      bucket_t*      pbucket   = first_.get_bucket_list_iterator();
+      local_iterator iprevious = pbucket->before_begin();
+      local_iterator icurrent  = first_.get_local_iterator();
+      local_iterator iend      = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent.
+
+                                                       // Find the node previous to the first one.
+      while (iprevious->etl_next != &*icurrent)
+      {
+        ++iprevious;
+      }
+
+      while (icurrent != iend)
+      {
+
+        local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket.
+        icurrent->key_value_pair.~value_type(); // Destroy the value.
+        pnodepool->release(&*icurrent);         // Release it back to the pool.
+        --construct_count;
+
+        icurrent = inext;
+
+        // Are we there yet?
+        if (icurrent != iend)
+        {
+          // At the end of this bucket?
+          if ((icurrent == pbucket->end()))
+          {
+            // Find the next non-empty one.
+            do
+            {
+              ++pbucket;
+            } while (pbucket->empty());
+
+            iprevious = pbucket->before_begin();
+            icurrent = pbucket->begin();
+          }
+        }
+      }
+
+      return result;
+    }
+
+    //*************************************************************************
+    /// Clears the unordered_multimap.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*********************************************************************
+    /// Counts an element.
+    ///\param key The key to search for.
+    ///\return 1 if the key exists, otherwise 0.
+    //*********************************************************************
+    size_t count(key_parameter_t key) const
+    {
+      size_t n = 0;
+      const_iterator f = find(key);
+      const_iterator l = f;
+
+      if (l != end())
+      {
+        ++l;
+        ++n;
+
+        while ((l != end()) && (key == l->first))
+        {
+          ++l;
+          ++n;
+        }
+      }
+
+      return n;
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator to the element if the key exists, otherwise end().
+    //*********************************************************************
+    iterator find(key_parameter_t key)
+    {
+      size_t index = get_bucket_index(key);
+
+      bucket_t* pbucket = pbuckets + index;
+      bucket_t& bucket = *pbucket;
+
+      // Is the bucket not empty?
+      if (!bucket.empty())
+      {
+        // Step though the list until we find the end or an equivalent key.
+        local_iterator inode = bucket.begin();
+        local_iterator iend = bucket.end();
+
+        while (inode != iend)
+        {
+          // Do we have this one?
+          if (key_equal_function(key, inode->key_value_pair.first))
+          {
+            return iterator((pbuckets + number_of_buckets), pbucket, inode);
+          }
+
+          ++inode;
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator to the element if the key exists, otherwise end().
+    //*********************************************************************
+    const_iterator find(key_parameter_t key) const
+    {
+      size_t index = get_bucket_index(key);
+
+      bucket_t* pbucket = pbuckets + index;
+      bucket_t& bucket = *pbucket;
+
+      // Is the bucket not empty?
+      if (!bucket.empty())
+      {
+        // Step though the list until we find the end or an equivalent key.
+        local_iterator inode = bucket.begin();
+        local_iterator iend = bucket.end();
+
+        while (inode != iend)
+        {
+          // Do we have this one?
+          if (key_equal_function(key, inode->key_value_pair.first))
+          {
+            return const_iterator((pbuckets + number_of_buckets), pbucket, inode);
+          }
+
+          ++inode;
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Returns a range containing all elements with key key in the container.
+    /// The range is defined by two iterators, the first pointing to the first
+    /// element of the wanted range and the second pointing past the last
+    /// element of the range.
+    ///\param key The key to search for.
+    ///\return An iterator pair to the range of elements if the key exists, otherwise end().
+    //*********************************************************************
+    std::pair<iterator, iterator> equal_range(key_parameter_t key)
+    {
+      iterator f = find(key);
+      iterator l = f;
+
+      if (l != end())
+      {
+        ++l;
+
+        while ((l != end()) && (key == l->first))
+        {
+          ++l;
+        }
+      }
+
+      return std::pair<iterator, iterator>(f, l);
+    }
+
+    //*********************************************************************
+    /// Returns a range containing all elements with key key in the container.
+    /// The range is defined by two iterators, the first pointing to the first
+    /// element of the wanted range and the second pointing past the last
+    /// element of the range.
+    ///\param key The key to search for.
+    ///\return A const iterator pair to the range of elements if the key exists, otherwise end().
+    //*********************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
+    {
+      const_iterator f = find(key);
+      const_iterator l = f;
+
+      if (l != end())
+      {
+        ++l;
+
+        while ((l != end()) && (key == l->first))
+        {
+          ++l;
+        }
+      }
+
+      return std::pair<const_iterator, const_iterator>(f, l);
+    }
+
+    //*************************************************************************
+    /// Gets the size of the unordered_multimap.
+    //*************************************************************************
+    size_type size() const
+    {
+      return pnodepool->size();
+    }
+
+    //*************************************************************************
+    /// Gets the maximum possible size of the unordered_multimap.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return pnodepool->max_size();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the unordered_multimap is empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return pnodepool->empty();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the unordered_multimap is full.
+    //*************************************************************************
+    bool full() const
+    {
+      return pnodepool->full();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return pnodepool->available();
+    }
+
+    //*************************************************************************
+    /// Returns the load factor = size / bucket_count.
+    ///\return The load factor = size / bucket_count.
+    //*************************************************************************
+    float load_factor() const
+    {
+      return static_cast<float>(size()) / static_cast<float>(bucket_count());
+    }
+
+    //*************************************************************************
+    /// Returns the function that hashes the keys.
+    ///\return The function that hashes the keys..
+    //*************************************************************************
+    hasher hash_function() const
+    {
+      return key_hash_function;
+    }
+
+    //*************************************************************************
+    /// Returns the function that compares the keys.
+    ///\return The function that compares the keys..
+    //*************************************************************************
+    key_equal key_eq() const
+    {
+      return key_equal_function;
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    iunordered_multimap& operator = (const iunordered_multimap& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    iunordered_multimap(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_)
+      : pnodepool(&node_pool_),
+        pbuckets(pbuckets_),
+        number_of_buckets(number_of_buckets_)
+    {
+    }
+
+    //*********************************************************************
+    /// Initialise the unordered_multimap.
+    //*********************************************************************
+    void initialise()
+    {
+      if (!empty())
+      {
+        // For each bucket...
+        for (size_t i = 0; i < number_of_buckets; ++i)
+        {
+          bucket_t& bucket = pbuckets[i];
+
+          if (!bucket.empty())
+          {
+            // For each item in the bucket...
+            local_iterator it = bucket.begin();
+
+            while (it != bucket.end())
+            {
+              // Destroy the value contents.
+              it->key_value_pair.~value_type();
+              ++it;
+              --construct_count;
+            }
+
+            // Now it's safe to clear the bucket.
+            bucket.clear();
+          }
+        }
+
+        // Now it's safe to clear the entire pool in one go.
+        pnodepool->release_all();
+      }
+
+      first = pbuckets;
+      last = first;
+    }
+
+  private:
+
+    //*********************************************************************
+    /// Adjust the first and last markers according to the new entry.
+    //*********************************************************************
+    void adjust_first_last_markers(bucket_t* pbucket)
+    {
+      if (pbucket < first)
+      {
+        first = pbucket;
+      }
+      else if (pbucket > last)
+      {
+        last = pbucket;
+      }
+    }
+
+    // Disable copy construction.
+    iunordered_multimap(const iunordered_multimap&);
+
+    /// The pool of data nodes used in the list.
+    pool_t* pnodepool;
+
+    /// The bucket list.
+    bucket_t* pbuckets;
+
+    /// The number of buckets.
+    const size_t number_of_buckets;
+
+    /// The first and last iterators to buckets with values.
+    bucket_t* first;
+    bucket_t* last;
+
+    /// The function that creates the hashes.
+    hasher key_hash_function;
+
+    /// The function that compares the keys for equality.
+    key_equal key_equal_function;
+
+    /// For library debugging purposes only.
+    etl::debug_count construct_count;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first unordered_multimap.
+  ///\param rhs Reference to the second unordered_multimap.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup unordered_multimap
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator ==(const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first unordered_multimap.
+  ///\param rhs Reference to the second unordered_multimap.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup unordered_multimap
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator !=(const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //*************************************************************************
+  /// A templated unordered_multimap implementation that uses a fixed size buffer.
+  //*************************************************************************
+  template <typename TKey, typename TValue, const size_t MAX_SIZE_, const size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+  class unordered_multimap : public etl::iunordered_multimap<TKey, TValue, THash, TKeyEqual>
+  {
+  private:
+
+    typedef etl::iunordered_multimap<TKey, TValue, THash, TKeyEqual> base;
+
+  public:
+
+    static const size_t MAX_SIZE    = MAX_SIZE_;
+    static const size_t MAX_BUCKETS = MAX_BUCKETS_;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    unordered_multimap()
+      : base(node_pool, buckets, MAX_BUCKETS)
+    {
+      base::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    unordered_multimap(const unordered_multimap& other)
+      : base(node_pool, buckets, MAX_BUCKETS)
+    {
+      base::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    unordered_multimap(TIterator first_, TIterator last_)
+      : base(node_pool, buckets, MAX_BUCKETS)
+    {
+      base::assign(first_, last_);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~unordered_multimap()
+    {
+      base::initialise();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    unordered_multimap& operator = (const unordered_multimap& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        base::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    /// The pool of nodes used for the unordered_multimap.
+    etl::pool<typename base::node_t, MAX_SIZE> node_pool;
+
+    /// The buckets of node lists.
+    etl::intrusive_forward_list<typename base::node_t> buckets[MAX_BUCKETS_];
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/unordered_multiset.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1300 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_UNORDERED_MULTISET__
+#define __ETL_UNORDERED_MULTISET__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+#include <iterator>
+#include <algorithm>
+#include <utility>
+
+#include "platform.h"
+#include "container.h"
+#include "pool.h"
+#include "vector.h"
+#include "intrusive_forward_list.h"
+#include "hash.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "nullptr.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "debug_count.h"
+
+#undef ETL_FILE
+#define ETL_FILE "26"
+
+//*****************************************************************************
+///\defgroup unordered_multiset unordered_multiset
+/// A unordered_multiset with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the unordered_multiset.
+  ///\ingroup unordered_multiset
+  //***************************************************************************
+  class unordered_multiset_exception : public etl::exception
+  {
+  public:
+
+    unordered_multiset_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Full exception for the unordered_multiset.
+  ///\ingroup unordered_multiset
+  //***************************************************************************
+  class unordered_multiset_full : public etl::unordered_multiset_exception
+  {
+  public:
+
+    unordered_multiset_full(string_type file_name_, numeric_type line_number_)
+      : etl::unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Out of range exception for the unordered_multiset.
+  ///\ingroup unordered_multiset
+  //***************************************************************************
+  class unordered_multiset_out_of_range : public etl::unordered_multiset_exception
+  {
+  public:
+
+    unordered_multiset_out_of_range(string_type file_name_, numeric_type line_number_)
+      : etl::unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:range", ETL_FILE"B"), file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the unordered_multiset.
+  ///\ingroup unordered_multiset
+  //***************************************************************************
+  class unordered_multiset_iterator : public etl::unordered_multiset_exception
+  {
+  public:
+
+    unordered_multiset_iterator(string_type file_name_, numeric_type line_number_)
+      : etl::unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:iterator", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for specifically sized unordered_multiset.
+  /// Can be used as a reference type for all unordered_multiset containing a specific type.
+  ///\ingroup unordered_multiset
+  //***************************************************************************
+  template <typename TKey, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+  class iunordered_multiset
+  {
+  public:
+
+    typedef TKey              value_type;
+    typedef TKey              key_type;
+    typedef THash             hasher;
+    typedef TKeyEqual         key_equal;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef size_t            size_type;
+
+    typedef typename etl::parameter_type<TKey>::type key_parameter_t;
+
+    typedef etl::forward_link<0> link_t;
+
+    // The nodes that store the elements.
+    struct node_t : public link_t
+    {
+      node_t(const value_type& key_)
+        : key(key_)
+      {
+      }
+
+      value_type key;
+    };
+
+  private:
+
+    typedef etl::intrusive_forward_list<node_t, link_t> bucket_t;
+    typedef etl::ipool pool_t;
+
+  public:
+
+    // Local iterators iterate over one bucket.
+    typedef typename bucket_t::iterator       local_iterator;
+    typedef typename bucket_t::const_iterator local_const_iterator;
+
+    //*********************************************************************
+    class iterator : public std::iterator<std::forward_iterator_tag, TKey>
+    {
+    public:
+
+      typedef typename iunordered_multiset::value_type      value_type;
+      typedef typename iunordered_multiset::key_type        key_type;
+      typedef typename iunordered_multiset::hasher          hasher;
+      typedef typename iunordered_multiset::key_equal       key_equal;
+      typedef typename iunordered_multiset::reference       reference;
+      typedef typename iunordered_multiset::const_reference const_reference;
+      typedef typename iunordered_multiset::pointer         pointer;
+      typedef typename iunordered_multiset::const_pointer   const_pointer;
+      typedef typename iunordered_multiset::size_type       size_type;
+
+      friend class iunordered_multiset;
+
+      //*********************************
+      iterator()
+      {
+      }
+
+      //*********************************
+      iterator(const iterator& other)
+        : pbuckets_end(other.pbuckets_end),
+        pbucket(other.pbucket),
+        inode(other.inode)
+      {
+      }
+
+      //*********************************
+      iterator& operator ++()
+      {
+        ++inode;
+
+        // The end of this node list?
+        if (inode == pbucket->end())
+        {
+          // Search for the next non-empty bucket.
+          ++pbucket;
+          while ((pbucket != pbuckets_end) && (pbucket->empty()))
+          {
+            ++pbucket;
+          }
+
+          // If not past the end, get the first node in the bucket.
+          if (pbucket != pbuckets_end)
+          {
+            inode = pbucket->begin();
+          }
+        }
+
+        return *this;
+      }
+
+      //*********************************
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        operator++();
+        return temp;
+      }
+
+      //*********************************
+      iterator operator =(const iterator& other)
+      {
+        pbuckets_end = other.pbuckets_end;
+        pbucket = other.pbucket;
+        inode = other.inode;
+        return *this;
+      }
+
+      //*********************************
+      reference operator *()
+      {
+        return inode->key;
+      }
+
+      //*********************************
+      const_reference operator *() const
+      {
+        return inode->key;
+      }
+
+      //*********************************
+      pointer operator &()
+      {
+        return &(inode->key);
+      }
+
+      //*********************************
+      const_pointer operator &() const
+      {
+        return &(inode->key);
+      }
+
+      //*********************************
+      pointer operator ->()
+      {
+        return &(inode->key);
+      }
+
+      //*********************************
+      const_pointer operator ->() const
+      {
+        return &(inode->key);
+      }
+
+      //*********************************
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.compare(rhs);
+      }
+
+      //*********************************
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      //*********************************
+      iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
+        : pbuckets_end(pbuckets_end_),
+          pbucket(pbucket_),
+          inode(inode_)
+      {
+      }
+
+      //*********************************
+      bool compare(const iterator& rhs) const
+      {
+        return rhs.inode == inode;
+      }
+
+      //*********************************
+      bucket_t& get_bucket()
+      {
+        return *pbucket;
+      }
+
+      //*********************************
+      bucket_t*& get_bucket_list_iterator()
+      {
+        return pbucket;
+      }
+
+      //*********************************
+      local_iterator get_local_iterator()
+      {
+        return inode;
+      }
+
+      bucket_t* pbuckets_end;
+      bucket_t* pbucket;
+      local_iterator inode;
+    };
+
+    //*********************************************************************
+    class const_iterator : public std::iterator<std::forward_iterator_tag, const TKey>
+    {
+    public:
+
+      typedef typename iunordered_multiset::value_type      value_type;
+      typedef typename iunordered_multiset::key_type        key_type;
+      typedef typename iunordered_multiset::hasher          hasher;
+      typedef typename iunordered_multiset::key_equal       key_equal;
+      typedef typename iunordered_multiset::reference       reference;
+      typedef typename iunordered_multiset::const_reference const_reference;
+      typedef typename iunordered_multiset::pointer         pointer;
+      typedef typename iunordered_multiset::const_pointer   const_pointer;
+      typedef typename iunordered_multiset::size_type       size_type;
+
+      friend class iunordered_multiset;
+      friend class iterator;
+
+      //*********************************
+      const_iterator()
+      {
+      }
+
+      //*********************************
+      const_iterator(const typename iunordered_multiset::iterator& other)
+        : pbuckets_end(other.pbuckets_end),
+        pbucket(other.pbucket),
+        inode(other.inode)
+      {
+      }
+
+      //*********************************
+      const_iterator(const const_iterator& other)
+        : pbuckets_end(other.pbuckets_end),
+        pbucket(other.pbucket),
+        inode(other.inode)
+      {
+      }
+
+      //*********************************
+      const_iterator& operator ++()
+      {
+        ++inode;
+
+        // The end of this node list?
+        if (inode == pbucket->end())
+        {
+          // Search for the next non-empty bucket.
+
+          ++pbucket;
+          while ((pbucket != pbuckets_end) && (pbucket->empty()))
+          {
+            ++pbucket;
+          }
+
+          // If not past the end, get the first node in the bucket.
+          if (pbucket != pbuckets_end)
+          {
+            inode = pbucket->begin();
+          }
+        }
+
+        return *this;
+      }
+
+      //*********************************
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        operator++();
+        return temp;
+      }
+
+      //*********************************
+      const_iterator operator =(const const_iterator& other)
+      {
+        pbuckets_end = other.pbuckets_end;
+        pbucket = other.pbucket;
+        inode = other.inode;
+        return *this;
+      }
+
+      //*********************************
+      const_reference operator *() const
+      {
+        return inode->key;
+      }
+
+      //*********************************
+      const_pointer operator &() const
+      {
+        return &(inode->key);
+      }
+
+      //*********************************
+      const_pointer operator ->() const
+      {
+        return &(inode->key);
+      }
+
+      //*********************************
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.compare(rhs);
+      }
+
+      //*********************************
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      //*********************************
+      const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
+        : pbuckets_end(pbuckets_end_),
+          pbucket(pbucket_),
+          inode(inode_)
+      {
+      }
+
+      //*********************************
+      bool compare(const const_iterator& rhs) const
+      {
+        return rhs.inode == inode;
+      }
+
+      //*********************************
+      bucket_t& get_bucket()
+      {
+        return *pbucket;
+      }
+
+      //*********************************
+      bucket_t*& get_bucket_list_iterator()
+      {
+        return pbucket;
+      }
+
+      //*********************************
+      local_iterator get_local_iterator()
+      {
+        return inode;
+      }
+
+      bucket_t* pbuckets_end;
+      bucket_t* pbucket;
+      local_iterator inode;
+    };
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the unordered_multiset.
+    ///\return An iterator to the beginning of the unordered_multiset.
+    //*********************************************************************
+    iterator begin()
+    {
+      return iterator((pbuckets + number_of_buckets), first, first->begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_multiset.
+    ///\return A const iterator to the beginning of the unordered_multiset.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator((pbuckets + number_of_buckets), first, first->begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_multiset.
+    ///\return A const iterator to the beginning of the unordered_multiset.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator((pbuckets + number_of_buckets), first, first->begin());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the unordered_multiset bucket.
+    ///\return An iterator to the beginning of the unordered_multiset bucket.
+    //*********************************************************************
+    local_iterator begin(size_t i)
+    {
+      return pbuckets[i].begin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_multiset bucket.
+    ///\return A const iterator to the beginning of the unordered_multiset bucket.
+    //*********************************************************************
+    local_const_iterator begin(size_t i) const
+    {
+      return pbuckets[i].cbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_multiset bucket.
+    ///\return A const iterator to the beginning of the unordered_multiset bucket.
+    //*********************************************************************
+    local_const_iterator cbegin(size_t i) const
+    {
+      return pbuckets[i].cbegin();
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the unordered_multiset.
+    ///\return An iterator to the end of the unordered_multiset.
+    //*********************************************************************
+    iterator end()
+    {
+      return iterator((pbuckets + number_of_buckets), last, last->end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_multiset.
+    ///\return A const iterator to the end of the unordered_multiset.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return const_iterator((pbuckets + number_of_buckets), last, last->end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_multiset.
+    ///\return A const iterator to the end of the unordered_multiset.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator((pbuckets + number_of_buckets), last, last->end());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the unordered_multiset bucket.
+    ///\return An iterator to the end of the unordered_multiset bucket.
+    //*********************************************************************
+    local_iterator end(size_t i)
+    {
+      return pbuckets[i].end();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_multiset bucket.
+    ///\return A const iterator to the end of the unordered_multiset bucket.
+    //*********************************************************************
+    local_const_iterator end(size_t i) const
+    {
+      return pbuckets[i].cend();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_multiset bucket.
+    ///\return A const iterator to the end of the unordered_multiset bucket.
+    //*********************************************************************
+    local_const_iterator cend(size_t i) const
+    {
+      return pbuckets[i].cend();
+    }
+
+    //*********************************************************************
+    /// Returns the bucket index for the key.
+    ///\return The bucket index for the key.
+    //*********************************************************************
+    size_type get_bucket_index(key_parameter_t key) const
+    {
+      return key_hash_function(key) % number_of_buckets;
+    }
+
+    //*********************************************************************
+    /// Returns the size of the bucket key.
+    ///\return The bucket size of the bucket key.
+    //*********************************************************************
+    size_type bucket_size(key_parameter_t key) const
+    {
+      size_t index = bucket(key);
+
+      return std::distance(pbuckets[index].begin(), pbuckets[index].end());
+    }
+
+    //*********************************************************************
+    /// Returns the maximum number of the buckets the container can hold.
+    ///\return The maximum number of the buckets the container can hold.
+    //*********************************************************************
+    size_type max_bucket_count() const
+    {
+      return number_of_buckets;
+    }
+
+    //*********************************************************************
+    /// Returns the number of the buckets the container holds.
+    ///\return The number of the buckets the container holds.
+    //*********************************************************************
+    size_type bucket_count() const
+    {
+      return number_of_buckets;
+    }
+
+    //*********************************************************************
+    /// Assigns values to the unordered_multiset.
+    /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset does not have enough free space.
+    /// If asserts or exceptions are enabled, emits unordered_multiset_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first_, TIterator last_)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first_, last_);
+      ETL_ASSERT(d >= 0, ETL_ERROR(unordered_multiset_iterator));
+      ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_multiset_full));
+#endif
+
+      clear();
+
+      while (first_ != last_)
+      {
+        insert(*first_++);
+      }
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the unordered_multiset.
+    /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset is already full.
+    ///\param value The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(const value_type& key)
+    {
+      std::pair<iterator, bool> result(end(), false);
+
+      ETL_ASSERT(!full(), ETL_ERROR(unordered_multiset_full));
+
+      // Get the hash index.
+      size_t index = get_bucket_index(key);
+
+      // Get the bucket & bucket iterator.
+      bucket_t* pbucket = pbuckets + index;
+      bucket_t& bucket = *pbucket;
+
+      // The first one in the bucket?
+      if (bucket.empty())
+      {
+        // Get a new node.
+        node_t& node = *pnodepool->allocate<node_t>();
+        ::new (&node.key) value_type(key);
+        ++construct_count;
+
+        // Just add the pointer to the bucket;
+        bucket.insert_after(bucket.before_begin(), node);
+
+        result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin());
+        result.second = true;
+
+        adjust_first_last_markers(pbucket);
+      }
+      else
+      {
+        // Step though the bucket looking for a place to insert.
+        local_iterator inode_previous = bucket.before_begin();
+        local_iterator inode = bucket.begin();
+
+        while (inode != bucket.end())
+        {
+          // Do we already have this key?
+          if (inode->key == key)
+          {
+            break;
+          }
+
+          ++inode_previous;
+          ++inode;
+        }
+
+        // Get a new node.
+        node_t& node = *pnodepool->allocate<node_t>();
+        ::new (&node.key) value_type(key);
+        ++construct_count;
+
+        // Add the node to the end of the bucket;
+        bucket.insert_after(inode_previous, node);
+        ++inode_previous;
+
+        result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous);
+        result.second = true;
+      }
+
+      return result;
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the unordered_multiset.
+    /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset is already full.
+    ///\param position The position to insert at.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(const_iterator position, const value_type& key)
+    {
+      return insert(key).first;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the unordered_multiset.
+    /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first_, TIterator last_)
+    {
+      while (first_ != last_)
+      {
+        insert(*first_++);
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param key The key to erase.
+    ///\return The number of elements erased.
+    //*********************************************************************
+    size_t erase(key_parameter_t key)
+    {
+      size_t n = 0;
+      size_t bucket_id = get_bucket_index(key);
+
+      bucket_t& bucket = pbuckets[bucket_id];
+
+      local_iterator iprevious = bucket.before_begin();
+      local_iterator icurrent = bucket.begin();
+
+      while (icurrent != bucket.end())
+      {
+        if (icurrent->key == key)
+        {
+          bucket.erase_after(iprevious);  // Unlink from the bucket.
+          icurrent->key.~value_type();    // Destroy the value.
+          pnodepool->release(&*icurrent); // Release it back to the pool.
+          ++n;
+          icurrent = iprevious;
+          --construct_count;
+        }
+        else
+        {
+          ++iprevious;
+        }
+
+        ++icurrent;
+      }
+
+      return n;
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param ielement Iterator to the element.
+    //*********************************************************************
+    iterator erase(const_iterator ielement)
+    {
+      // Make a note of the next one.
+      iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
+      ++inext;
+
+      bucket_t&      bucket = ielement.get_bucket();
+      local_iterator iprevious = bucket.before_begin();
+      local_iterator icurrent = ielement.get_local_iterator();
+
+      // Find the node previous to the one we're interested in.
+      while (iprevious->etl_next != &*icurrent)
+      {
+        ++iprevious;
+      }
+
+      bucket.erase_after(iprevious);  // Unlink from the bucket.
+      icurrent->key.~value_type();    // Destroy the value.
+      pnodepool->release(&*icurrent); // Release it back to the pool.
+      --construct_count;
+
+      return inext;
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed to by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    //*********************************************************************
+    iterator erase(const_iterator first_, const_iterator last_)
+    {
+      // Make a note of the last.
+      iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator());
+
+      // Get the starting point.
+      bucket_t*      pbucket   = first_.get_bucket_list_iterator();
+      local_iterator iprevious = pbucket->before_begin();
+      local_iterator icurrent  = first_.get_local_iterator();
+      local_iterator iend      = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent.
+
+                                                       // Find the node previous to the first one.
+      while (iprevious->etl_next != &*icurrent)
+      {
+        ++iprevious;
+      }
+
+      while (icurrent != iend)
+      {
+
+        local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket.
+        icurrent->key.~value_type();    // Destroy the value.
+        pnodepool->release(&*icurrent); // Release it back to the pool.
+        --construct_count;
+
+        icurrent = inext;
+
+        // Are we there yet?
+        if (icurrent != iend)
+        {
+          // At the end of this bucket?
+          if ((icurrent == pbucket->end()))
+          {
+            // Find the next non-empty one.
+            do
+            {
+              ++pbucket;
+            } while (pbucket->empty());
+
+            iprevious = pbucket->before_begin();
+            icurrent = pbucket->begin();
+          }
+        }
+      }
+
+      return result;
+    }
+
+    //*************************************************************************
+    /// Clears the unordered_multiset.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*********************************************************************
+    /// Counts an element.
+    ///\param key The key to search for.
+    ///\return 1 if the key exists, otherwise 0.
+    //*********************************************************************
+    size_t count(key_parameter_t key) const
+    {
+      size_t n = 0;
+      const_iterator f = find(key);
+      const_iterator l = f;
+
+      if (l != end())
+      {
+        ++l;
+        ++n;
+
+        while ((l != end()) && (key == *l))
+        {
+          ++l;
+          ++n;
+        }
+      }
+
+      return n;
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator to the element if the key exists, otherwise end().
+    //*********************************************************************
+    iterator find(key_parameter_t key)
+    {
+      size_t index = get_bucket_index(key);
+
+      bucket_t* pbucket = pbuckets + index;
+      bucket_t& bucket = *pbucket;
+
+      // Is the bucket not empty?
+      if (!bucket.empty())
+      {
+        // Step though the list until we find the end or an equivalent key.
+        local_iterator inode = bucket.begin();
+        local_iterator iend = bucket.end();
+
+        while (inode != iend)
+        {
+          // Do we have this one?
+          if (key_equal_function(key, inode->key))
+          {
+            return iterator((pbuckets + number_of_buckets), pbucket, inode);
+          }
+
+          ++inode;
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator to the element if the key exists, otherwise end().
+    //*********************************************************************
+    const_iterator find(key_parameter_t key) const
+    {
+      size_t index = get_bucket_index(key);
+
+      bucket_t* pbucket = pbuckets + index;
+      bucket_t& bucket = *pbucket;
+
+      // Is the bucket not empty?
+      if (!bucket.empty())
+      {
+        // Step though the list until we find the end or an equivalent key.
+        local_iterator inode = bucket.begin();
+        local_iterator iend = bucket.end();
+
+        while (inode != iend)
+        {
+          // Do we have this one?
+          if (key_equal_function(key, inode->key))
+          {
+            return iterator((pbuckets + number_of_buckets), pbucket, inode);
+          }
+
+          ++inode;
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Returns a range containing all elements with key key in the container.
+    /// The range is defined by two iterators, the first pointing to the first
+    /// element of the wanted range and the second pointing past the last
+    /// element of the range.
+    ///\param key The key to search for.
+    ///\return An iterator pair to the range of elements if the key exists, otherwise end().
+    //*********************************************************************
+    std::pair<iterator, iterator> equal_range(key_parameter_t key)
+    {
+      iterator f = find(key);
+      iterator l = f;
+
+      if (l != end())
+      {
+        ++l;
+
+        while ((l != end()) && (key == *l))
+        {
+          ++l;
+        }
+      }
+
+      return std::pair<iterator, iterator>(f, l);
+    }
+
+    //*********************************************************************
+    /// Returns a range containing all elements with key key in the container.
+    /// The range is defined by two iterators, the first pointing to the first
+    /// element of the wanted range and the second pointing past the last
+    /// element of the range.
+    ///\param key The key to search for.
+    ///\return A const iterator pair to the range of elements if the key exists, otherwise end().
+    //*********************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
+    {
+      const_iterator f = find(key);
+      const_iterator l = f;
+
+      if (l != end())
+      {
+        ++l;
+
+        while ((l != end()) && (key == *l))
+        {
+          ++l;
+        }
+      }
+
+      return std::pair<const_iterator, const_iterator>(f, l);
+    }
+
+    //*************************************************************************
+    /// Gets the size of the unordered_multiset.
+    //*************************************************************************
+    size_type size() const
+    {
+      return pnodepool->size();
+    }
+
+    //*************************************************************************
+    /// Gets the maximum possible size of the unordered_multiset.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return pnodepool->max_size();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the unordered_multiset is empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return pnodepool->empty();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the unordered_multiset is full.
+    //*************************************************************************
+    bool full() const
+    {
+      return pnodepool->full();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return pnodepool->available();
+    }
+
+    //*************************************************************************
+    /// Returns the load factor = size / bucket_count.
+    ///\return The load factor = size / bucket_count.
+    //*************************************************************************
+    float load_factor() const
+    {
+      return static_cast<float>(size()) / static_cast<float>(bucket_count());
+    }
+
+    //*************************************************************************
+    /// Returns the function that hashes the keys.
+    ///\return The function that hashes the keys..
+    //*************************************************************************
+    hasher hash_function() const
+    {
+      return key_hash_function;
+    }
+
+    //*************************************************************************
+    /// Returns the function that compares the keys.
+    ///\return The function that compares the keys..
+    //*************************************************************************
+    key_equal key_eq() const
+    {
+      return key_equal_function;
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    iunordered_multiset& operator = (const iunordered_multiset& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    iunordered_multiset(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_)
+      : pnodepool(&node_pool_),
+        pbuckets(pbuckets_),
+        number_of_buckets(number_of_buckets_)
+    {
+    }
+
+    //*********************************************************************
+    /// Initialise the unordered_multiset.
+    //*********************************************************************
+    void initialise()
+    {
+      if (!empty())
+      {
+        // For each bucket...
+        for (size_t i = 0; i < number_of_buckets; ++i)
+        {
+          bucket_t& bucket = pbuckets[i];
+
+          if (!bucket.empty())
+          {
+            // For each item in the bucket...
+            local_iterator it = bucket.begin();
+
+            while (it != bucket.end())
+            {
+              // Destroy the value contents.
+              it->key.~value_type();
+              ++it;
+              --construct_count;
+            }
+
+            // Now it's safe to clear the bucket.
+            bucket.clear();
+          }
+        }
+
+        // Now it's safe to clear the entire pool in one go.
+        pnodepool->release_all();
+      }
+
+      first = pbuckets;
+      last = first;
+    }
+
+  private:
+
+    //*********************************************************************
+    /// Adjust the first and last markers according to the new entry.
+    //*********************************************************************
+    void adjust_first_last_markers(bucket_t* pbucket)
+    {
+      if (pbucket < first)
+      {
+        first = pbucket;
+      }
+      else if (pbucket > last)
+      {
+        last = pbucket;
+      }
+    }
+
+    // Disable copy construction.
+    iunordered_multiset(const iunordered_multiset&);
+
+    /// The pool of data nodes used in the list.
+    pool_t* pnodepool;
+
+    /// The bucket list.
+    bucket_t* pbuckets;
+
+    /// The number of buckets.
+    const size_t number_of_buckets;
+
+    /// The first and last iterators to buckets with values.
+    bucket_t* first;
+    bucket_t* last;
+
+    /// The function that creates the hashes.
+    hasher key_hash_function;
+
+    /// The function that compares the keys for equality.
+    key_equal key_equal_function;
+
+    /// For library debugging purposes only.
+    etl::debug_count construct_count;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first unordered_multiset.
+  ///\param rhs Reference to the second unordered_multiset.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup unordered_multiset
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator ==(const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first unordered_multiset.
+  ///\param rhs Reference to the second unordered_multiset.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup unordered_multiset
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator !=(const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //*************************************************************************
+  /// A templated unordered_multiset implementation that uses a fixed size buffer.
+  //*************************************************************************
+  template <typename TKey, const size_t MAX_SIZE_, size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+  class unordered_multiset : public etl::iunordered_multiset<TKey, THash, TKeyEqual>
+  {
+  private:
+
+    typedef etl::iunordered_multiset<TKey, THash, TKeyEqual> base;
+
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+    static const size_t MAX_BUCKETS = MAX_BUCKETS_;
+
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    unordered_multiset()
+      : base(node_pool, buckets, MAX_BUCKETS)
+    {
+      base::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    unordered_multiset(const unordered_multiset& other)
+      : base(node_pool, buckets, MAX_BUCKETS)
+    {
+      base::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    unordered_multiset(TIterator first_, TIterator last_)
+      : base(node_pool, buckets, MAX_BUCKETS)
+    {
+      base::assign(first_, last_);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~unordered_multiset()
+    {
+      base::initialise();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    unordered_multiset& operator = (const unordered_multiset& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        base::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    /// The pool of nodes used for the unordered_multiset.
+    etl::pool<typename base::node_t, MAX_SIZE> node_pool;
+
+    /// The buckets of node lists.
+    etl::intrusive_forward_list<typename base::node_t> buckets[MAX_BUCKETS_];
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/unordered_set.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1276 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_UNORDERED_SET__
+#define __ETL_UNORDERED_SET__
+
+#include <stddef.h>
+#include <iterator>
+#include <functional>
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+#include "platform.h"
+#include "container.h"
+#include "pool.h"
+#include "vector.h"
+#include "intrusive_forward_list.h"
+#include "hash.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "nullptr.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "error_handler.h"
+#include "debug_count.h"
+
+#undef ETL_FILE
+#define ETL_FILE "23"
+
+//*****************************************************************************
+///\defgroup unordered_set unordered_set
+/// A unordered_set with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// Exception for the unordered_set.
+  ///\ingroup unordered_set
+  //***************************************************************************
+  class unordered_set_exception : public etl::exception
+  {
+  public:
+
+    unordered_set_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : etl::exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Full exception for the unordered_set.
+  ///\ingroup unordered_set
+  //***************************************************************************
+  class unordered_set_full : public etl::unordered_set_exception
+  {
+  public:
+
+    unordered_set_full(string_type file_name_, numeric_type line_number_)
+      : etl::unordered_set_exception(ETL_ERROR_TEXT("unordered_set:full", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Out of range exception for the unordered_set.
+  ///\ingroup unordered_set
+  //***************************************************************************
+  class unordered_set_out_of_range : public etl::unordered_set_exception
+  {
+  public:
+
+    unordered_set_out_of_range(string_type file_name_, numeric_type line_number_)
+      : etl::unordered_set_exception(ETL_ERROR_TEXT("unordered_set:range", ETL_FILE"B"), file_name_, line_number_)
+    {}
+  };
+
+  //***************************************************************************
+  /// Iterator exception for the unordered_set.
+  ///\ingroup unordered_set
+  //***************************************************************************
+  class unordered_set_iterator : public etl::unordered_set_exception
+  {
+  public:
+
+    unordered_set_iterator(string_type file_name_, numeric_type line_number_)
+      : etl::unordered_set_exception(ETL_ERROR_TEXT("unordered_set:iterator", ETL_FILE"C"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// The base class for specifically sized unordered_set.
+  /// Can be used as a reference type for all unordered_set containing a specific type.
+  ///\ingroup unordered_set
+  //***************************************************************************
+  template <typename TKey, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+  class iunordered_set
+  {
+  public:
+
+    typedef TKey              value_type;
+    typedef TKey              key_type;
+    typedef THash             hasher;
+    typedef TKeyEqual         key_equal;
+    typedef value_type&       reference;
+    typedef const value_type& const_reference;
+    typedef value_type*       pointer;
+    typedef const value_type* const_pointer;
+    typedef size_t            size_type;
+
+    typedef typename etl::parameter_type<TKey>::type key_parameter_t;
+
+    typedef etl::forward_link<0> link_t;
+
+    // The nodes that store the elements.
+    struct node_t : public link_t
+    {
+      node_t(const value_type& key_)
+        : key(key_)
+      {
+      }
+
+      value_type key;
+    };
+
+  private:
+
+    typedef etl::intrusive_forward_list<node_t, link_t> bucket_t;
+    typedef etl::ipool pool_t;
+
+  public:
+
+    // Local iterators iterate over one bucket.
+    typedef typename bucket_t::iterator       local_iterator;
+    typedef typename bucket_t::const_iterator local_const_iterator;
+
+    //*********************************************************************
+    class iterator : public std::iterator<std::forward_iterator_tag, TKey>
+    {
+    public:
+
+      typedef typename iunordered_set::value_type      value_type;
+      typedef typename iunordered_set::key_type        key_type;
+      typedef typename iunordered_set::hasher          hasher;
+      typedef typename iunordered_set::key_equal       key_equal;
+      typedef typename iunordered_set::reference       reference;
+      typedef typename iunordered_set::const_reference const_reference;
+      typedef typename iunordered_set::pointer         pointer;
+      typedef typename iunordered_set::const_pointer   const_pointer;
+      typedef typename iunordered_set::size_type       size_type;
+
+      friend class iunordered_set;
+
+      //*********************************
+      iterator()
+      {
+      }
+
+      //*********************************
+      iterator(const iterator& other)
+        : pbuckets_end(other.pbuckets_end),
+        pbucket(other.pbucket),
+        inode(other.inode)
+      {
+      }
+
+      //*********************************
+      iterator& operator ++()
+      {
+        ++inode;
+
+        // The end of this node list?
+        if (inode == pbucket->end())
+        {
+          // Search for the next non-empty bucket.
+          ++pbucket;
+          while ((pbucket != pbuckets_end) && (pbucket->empty()))
+          {
+            ++pbucket;
+          }
+
+          // If not past the end, get the first node in the bucket.
+          if (pbucket != pbuckets_end)
+          {
+            inode = pbucket->begin();
+          }
+        }
+
+        return *this;
+      }
+
+      //*********************************
+      iterator operator ++(int)
+      {
+        iterator temp(*this);
+        operator++();
+        return temp;
+      }
+
+      //*********************************
+      iterator operator =(const iterator& other)
+      {
+        pbuckets_end = other.pbuckets_end;
+        pbucket = other.pbucket;
+        inode = other.inode;
+        return *this;
+      }
+
+      //*********************************
+      reference operator *()
+      {
+        return inode->key;
+      }
+
+      //*********************************
+      const_reference operator *() const
+      {
+        return inode->key;
+      }
+
+      //*********************************
+      pointer operator &()
+      {
+        return &(inode->key);
+      }
+
+      //*********************************
+      const_pointer operator &() const
+      {
+        return &(inode->key);
+      }
+
+      //*********************************
+      pointer operator ->()
+      {
+        return &(inode->key);
+      }
+
+      //*********************************
+      const_pointer operator ->() const
+      {
+        return &(inode->key);
+      }
+
+      //*********************************
+      friend bool operator == (const iterator& lhs, const iterator& rhs)
+      {
+        return lhs.compare(rhs);
+      }
+
+      //*********************************
+      friend bool operator != (const iterator& lhs, const iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      //*********************************
+      iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
+        : pbuckets_end(pbuckets_end_),
+          pbucket(pbucket_),
+          inode(inode_)
+      {
+      }
+
+      //*********************************
+      bool compare(const iterator& rhs) const
+      {
+        return rhs.inode == inode;
+      }
+
+      //*********************************
+      bucket_t& get_bucket()
+      {
+        return *pbucket;
+      }
+
+      //*********************************
+      bucket_t*& get_bucket_list_iterator()
+      {
+        return pbucket;
+      }
+
+      //*********************************
+      local_iterator get_local_iterator()
+      {
+        return inode;
+      }
+
+      bucket_t* pbuckets_end;
+      bucket_t* pbucket;
+      local_iterator       inode;
+    };
+
+    //*********************************************************************
+    class const_iterator : public std::iterator<std::forward_iterator_tag, const TKey>
+    {
+    public:
+
+      typedef typename iunordered_set::value_type      value_type;
+      typedef typename iunordered_set::key_type        key_type;
+      typedef typename iunordered_set::hasher          hasher;
+      typedef typename iunordered_set::key_equal       key_equal;
+      typedef typename iunordered_set::reference       reference;
+      typedef typename iunordered_set::const_reference const_reference;
+      typedef typename iunordered_set::pointer         pointer;
+      typedef typename iunordered_set::const_pointer   const_pointer;
+      typedef typename iunordered_set::size_type       size_type;
+
+      friend class iunordered_set;
+      friend class iterator;
+
+      //*********************************
+      const_iterator()
+      {
+      }
+
+      //*********************************
+      const_iterator(const typename iunordered_set::iterator& other)
+        : pbuckets_end(other.pbuckets_end),
+        pbucket(other.pbucket),
+        inode(other.inode)
+      {
+      }
+
+      //*********************************
+      const_iterator(const const_iterator& other)
+        : pbuckets_end(other.pbuckets_end),
+        pbucket(other.pbucket),
+        inode(other.inode)
+      {
+      }
+
+      //*********************************
+      const_iterator& operator ++()
+      {
+        ++inode;
+
+        // The end of this node list?
+        if (inode == pbucket->end())
+        {
+          // Search for the next non-empty bucket.
+
+          ++pbucket;
+          while ((pbucket != pbuckets_end) && (pbucket->empty()))
+          {
+            ++pbucket;
+          }
+
+          // If not past the end, get the first node in the bucket.
+          if (pbucket != pbuckets_end)
+          {
+            inode = pbucket->begin();
+          }
+        }
+
+        return *this;
+      }
+
+      //*********************************
+      const_iterator operator ++(int)
+      {
+        const_iterator temp(*this);
+        operator++();
+        return temp;
+      }
+
+      //*********************************
+      const_iterator operator =(const const_iterator& other)
+      {
+        pbuckets_end = other.pbuckets_end;
+        pbucket = other.pbucket;
+        inode = other.inode;
+        return *this;
+      }
+
+      //*********************************
+      const_reference operator *() const
+      {
+        return inode->key;
+      }
+
+      //*********************************
+      const_pointer operator &() const
+      {
+        return &(inode->key);
+      }
+
+      //*********************************
+      const_pointer operator ->() const
+      {
+        return &(inode->key);
+      }
+
+      //*********************************
+      friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return lhs.compare(rhs);
+      }
+
+      //*********************************
+      friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
+      {
+        return !(lhs == rhs);
+      }
+
+    private:
+
+      //*********************************
+      const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_)
+        : pbuckets_end(pbuckets_end_),
+          pbucket(pbucket_),
+          inode(inode_)
+      {
+      }
+
+      //*********************************
+      bool compare(const const_iterator& rhs) const
+      {
+        return rhs.inode == inode;
+      }
+
+      //*********************************
+      bucket_t& get_bucket()
+      {
+        return *pbucket;
+      }
+
+      //*********************************
+      bucket_t*& get_bucket_list_iterator()
+      {
+        return pbucket;
+      }
+
+      //*********************************
+      local_iterator get_local_iterator()
+      {
+        return inode;
+      }
+
+      bucket_t* pbuckets_end;
+      bucket_t* pbucket;
+      local_iterator       inode;
+    };
+
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the unordered_set.
+    ///\return An iterator to the beginning of the unordered_set.
+    //*********************************************************************
+    iterator begin()
+    {
+      return iterator(pbuckets + number_of_buckets, first, first->begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_set.
+    ///\return A const iterator to the beginning of the unordered_set.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return const_iterator(pbuckets + number_of_buckets, first, first->begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_set.
+    ///\return A const iterator to the beginning of the unordered_set.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return const_iterator(pbuckets + number_of_buckets, first, first->begin());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the unordered_set bucket.
+    ///\return An iterator to the beginning of the unordered_set bucket.
+    //*********************************************************************
+    local_iterator begin(size_t i)
+    {
+      return pbuckets[i].begin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_set bucket.
+    ///\return A const iterator to the beginning of the unordered_set bucket.
+    //*********************************************************************
+    local_const_iterator begin(size_t i) const
+    {
+      return pbuckets[i].cbegin();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the unordered_set bucket.
+    ///\return A const iterator to the beginning of the unordered_set bucket.
+    //*********************************************************************
+    local_const_iterator cbegin(size_t i) const
+    {
+      return pbuckets[i].cbegin();
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the unordered_set.
+    ///\return An iterator to the end of the unordered_set.
+    //*********************************************************************
+    iterator end()
+    {
+      return iterator(pbuckets + number_of_buckets, last, last->end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_set.
+    ///\return A const iterator to the end of the unordered_set.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return const_iterator(pbuckets + number_of_buckets, last, last->end());
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_set.
+    ///\return A const iterator to the end of the unordered_set.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return const_iterator(pbuckets + number_of_buckets, last, last->end());
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the unordered_set bucket.
+    ///\return An iterator to the end of the unordered_set bucket.
+    //*********************************************************************
+    local_iterator end(size_t i)
+    {
+      return pbuckets[i].end();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_set bucket.
+    ///\return A const iterator to the end of the unordered_set bucket.
+    //*********************************************************************
+    local_const_iterator end(size_t i) const
+    {
+      return pbuckets[i].cend();
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the unordered_set bucket.
+    ///\return A const iterator to the end of the unordered_set bucket.
+    //*********************************************************************
+    local_const_iterator cend(size_t i) const
+    {
+      return pbuckets[i].cend();
+    }
+
+    //*********************************************************************
+    /// Returns the bucket index for the key.
+    ///\return The bucket index for the key.
+    //*********************************************************************
+    size_type get_bucket_index(key_parameter_t key) const
+    {
+      return key_hash_function(key) % number_of_buckets;
+    }
+
+    //*********************************************************************
+    /// Returns the size of the bucket key.
+    ///\return The bucket size of the bucket key.
+    //*********************************************************************
+    size_type bucket_size(key_parameter_t key) const
+    {
+      size_t index = bucket(key);
+
+      return std::distance(pbuckets[index].begin(), pbuckets[index].end());
+    }
+
+    //*********************************************************************
+    /// Returns the maximum number of the buckets the container can hold.
+    ///\return The maximum number of the buckets the container can hold.
+    //*********************************************************************
+    size_type max_bucket_count() const
+    {
+      return number_of_buckets;
+    }
+
+    //*********************************************************************
+    /// Returns the number of the buckets the container holds.
+    ///\return The number of the buckets the container holds.
+    //*********************************************************************
+    size_type bucket_count() const
+    {
+      return number_of_buckets;
+    }
+
+    //*********************************************************************
+    /// Assigns values to the unordered_set.
+    /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set does not have enough free space.
+    /// If asserts or exceptions are enabled, emits unordered_set_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first_, TIterator last_)
+    {
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first_, last_);
+      ETL_ASSERT(d >= 0, ETL_ERROR(unordered_set_iterator));
+      ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_set_full));
+#endif
+
+      clear();
+
+      while (first_ != last_)
+      {
+        insert(*first_++);
+      }
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the unordered_set.
+    /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set is already full.
+    ///\param value The value to insert.
+    //*********************************************************************
+    std::pair<iterator, bool> insert(const value_type& key)
+    {
+      std::pair<iterator, bool> result(end(), false);
+
+      ETL_ASSERT(!full(), ETL_ERROR(unordered_set_full));
+
+      // Get the hash index.
+      size_t index = get_bucket_index(key);
+
+      // Get the bucket & bucket iterator.
+      bucket_t* pbucket = pbuckets + index;
+      bucket_t& bucket = *pbucket;
+
+      // The first one in the bucket?
+      if (bucket.empty())
+      {
+        // Get a new node.
+        node_t& node = *pnodepool->allocate<node_t>();
+        ::new (&node.key) value_type(key);
+        ++construct_count;
+
+        // Just add the pointer to the bucket;
+        bucket.insert_after(bucket.before_begin(), node);
+
+        result.first = iterator(pbuckets + number_of_buckets, pbucket, pbucket->begin());
+        result.second = true;
+
+        adjust_first_last_markers(pbucket);
+      }
+      else
+      {
+        // Step though the bucket looking for a place to insert.
+        local_iterator inode_previous = bucket.before_begin();
+        local_iterator inode = bucket.begin();
+
+        while (inode != bucket.end())
+        {
+          // Do we already have this key?
+          if (inode->key == key)
+          {
+            break;
+          }
+
+          ++inode_previous;
+          ++inode;
+        }
+
+        // Not already there?
+        if (inode == bucket.end())
+        {
+          // Get a new node.
+          node_t& node = *pnodepool->allocate<node_t>();
+          ::new (&node.key) value_type(key);
+          ++construct_count;
+
+          // Add the node to the end of the bucket;
+          bucket.insert_after(inode_previous, node);
+          ++inode_previous;
+
+          result.first = iterator(pbuckets + number_of_buckets, pbucket, inode_previous);
+          result.second = true;
+        }
+      }
+
+      return result;
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the unordered_set.
+    /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set is already full.
+    ///\param position The position to insert at.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(const_iterator position, const value_type& key)
+    {
+      return insert(key).first;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the unordered_set.
+    /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set does not have enough free space.
+    ///\param position The position to insert at.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(TIterator first_, TIterator last_)
+    {
+      while (first_ != last_)
+      {
+        insert(*first_++);
+      }
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param key The key to erase.
+    ///\return The number of elements erased. 0 or 1.
+    //*********************************************************************
+    size_t erase(key_parameter_t key)
+    {
+      size_t n = 0;
+      size_t index = get_bucket_index(key);
+
+      bucket_t& bucket = pbuckets[index];
+
+      local_iterator iprevious = bucket.before_begin();
+      local_iterator icurrent = bucket.begin();
+
+      // Search for the key, if we have it.
+      while ((icurrent != bucket.end()) && (icurrent->key != key))
+      {
+        ++iprevious;
+        ++icurrent;
+      }
+
+      // Did we find it?
+      if (icurrent != bucket.end())
+      {
+        bucket.erase_after(iprevious);  // Unlink from the bucket.
+        icurrent->key.~value_type();    // Destroy the value.
+        pnodepool->release(&*icurrent); // Release it back to the pool.
+        n = 1;
+        --construct_count;
+      }
+
+      return n;
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param ielement Iterator to the element.
+    //*********************************************************************
+    iterator erase(const_iterator ielement)
+    {
+      // Make a note of the next one.
+      iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator());
+      ++inext;
+
+      bucket_t&      bucket = ielement.get_bucket();
+      local_iterator iprevious = bucket.before_begin();
+      local_iterator icurrent = ielement.get_local_iterator();
+
+      // Find the node previous to the one we're interested in.
+      while (iprevious->etl_next != &*icurrent)
+      {
+        ++iprevious;
+      }
+
+      bucket.erase_after(iprevious);  // Unlink from the bucket.
+      icurrent->key.~value_type();    // Destroy the value.
+      pnodepool->release(&*icurrent); // Release it back to the pool.
+      --construct_count;
+
+      return inext;
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed to by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    //*********************************************************************
+    iterator erase(const_iterator first_, const_iterator last_)
+    {
+      // Make a note of the last.
+      iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator());
+
+      // Get the starting point.
+      bucket_t*      pbucket   = first_.get_bucket_list_iterator();
+      local_iterator iprevious = pbucket->before_begin();
+      local_iterator icurrent  = first_.get_local_iterator();
+      local_iterator iend      = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent.
+
+                                                       // Find the node previous to the first one.
+      while (iprevious->etl_next != &*icurrent)
+      {
+        ++iprevious;
+      }
+
+      while (icurrent != iend)
+      {
+
+        local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket.
+        icurrent->key.~value_type();    // Destroy the value.
+        pnodepool->release(&*icurrent); // Release it back to the pool.
+        --construct_count;
+
+        icurrent = inext;
+
+        // Are we there yet?
+        if (icurrent != iend)
+        {
+          // At the end of this bucket?
+          if ((icurrent == pbucket->end()))
+          {
+            // Find the next non-empty one.
+            do
+            {
+              ++pbucket;
+            } while (pbucket->empty());
+
+            iprevious = pbucket->before_begin();
+            icurrent = pbucket->begin();
+          }
+        }
+      }
+
+      return result;
+    }
+
+    //*************************************************************************
+    /// Clears the unordered_set.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*********************************************************************
+    /// Counts an element.
+    ///\param key The key to search for.
+    ///\return 1 if the key exists, otherwise 0.
+    //*********************************************************************
+    size_t count(key_parameter_t key) const
+    {
+      return (find(key) == end()) ? 0 : 1;
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator to the element if the key exists, otherwise end().
+    //*********************************************************************
+    iterator find(key_parameter_t key)
+    {
+      size_t index = get_bucket_index(key);
+
+      bucket_t* pbucket = pbuckets + index;
+      bucket_t& bucket = *pbucket;
+
+      // Is the bucket not empty?
+      if (!bucket.empty())
+      {
+        // Step though the list until we find the end or an equivalent key.
+        local_iterator inode = bucket.begin();
+        local_iterator iend = bucket.end();
+
+        while (inode != iend)
+        {
+          // Do we have this one?
+          if (key_equal_function(key, inode->key))
+          {
+            return iterator(pbuckets + number_of_buckets, pbucket, inode);
+          }
+
+          ++inode;
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Finds an element.
+    ///\param key The key to search for.
+    ///\return An iterator to the element if the key exists, otherwise end().
+    //*********************************************************************
+    const_iterator find(key_parameter_t key) const
+    {
+      size_t index = get_bucket_index(key);
+
+      bucket_t* pbucket = pbuckets + index;
+      bucket_t& bucket = *pbucket;
+
+      // Is the bucket not empty?
+      if (!bucket.empty())
+      {
+        // Step though the list until we find the end or an equivalent key.
+        local_iterator inode = bucket.begin();
+        local_iterator iend = bucket.end();
+
+        while (inode != iend)
+        {
+          // Do we have this one?
+          if (key_equal_function(key, inode->key))
+          {
+            return iterator(pbuckets + number_of_buckets, pbucket, inode);
+          }
+
+          ++inode;
+        }
+      }
+
+      return end();
+    }
+
+    //*********************************************************************
+    /// Returns a range containing all elements with key 'key' in the container.
+    /// The range is defined by two iterators, the first pointing to the first
+    /// element of the wanted range and the second pointing past the last
+    /// element of the range.
+    ///\param key The key to search for.
+    ///\return An iterator pair to the range of elements if the key exists, otherwise end().
+    //*********************************************************************
+    std::pair<iterator, iterator> equal_range(key_parameter_t key)
+    {
+      iterator f = find(key);
+      iterator l = f;
+
+      if (l != end())
+      {
+        ++l;
+      }
+
+      return std::pair<iterator, iterator>(f, l);
+    }
+
+    //*********************************************************************
+    /// Returns a range containing all elements with key 'key' in the container.
+    /// The range is defined by two iterators, the first pointing to the first
+    /// element of the wanted range and the second pointing past the last
+    /// element of the range.
+    ///\param key The key to search for.
+    ///\return A const iterator pair to the range of elements if the key exists, otherwise end().
+    //*********************************************************************
+    std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
+    {
+      const_iterator f = find(key);
+      const_iterator l = f;
+
+      if (l != end())
+      {
+        ++l;
+      }
+
+      return std::pair<const_iterator, const_iterator>(f, l);
+    }
+
+    //*************************************************************************
+    /// Gets the size of the unordered_set.
+    //*************************************************************************
+    size_type size() const
+    {
+      return pnodepool->size();
+    }
+
+    //*************************************************************************
+    /// Gets the maximum possible size of the unordered_set.
+    //*************************************************************************
+    size_type max_size() const
+    {
+      return pnodepool->max_size();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the unordered_set is empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return pnodepool->empty();
+    }
+
+    //*************************************************************************
+    /// Checks to see if the unordered_set is full.
+    //*************************************************************************
+    bool full() const
+    {
+      return pnodepool->full();
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return pnodepool->available();
+    }
+
+    //*************************************************************************
+    /// Returns the load factor = size / bucket_count.
+    ///\return The load factor = size / bucket_count.
+    //*************************************************************************
+    float load_factor() const
+    {
+      return static_cast<float>(size()) / static_cast<float>(bucket_count());
+    }
+
+    //*************************************************************************
+    /// Returns the function that hashes the keys.
+    ///\return The function that hashes the keys..
+    //*************************************************************************
+    hasher hash_function() const
+    {
+      return key_hash_function;
+    }
+
+    //*************************************************************************
+    /// Returns the function that compares the keys.
+    ///\return The function that compares the keys..
+    //*************************************************************************
+    key_equal key_eq() const
+    {
+      return key_equal_function;
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    iunordered_set& operator = (const iunordered_set& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    iunordered_set(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_)
+      : pnodepool(&node_pool_),
+        pbuckets(pbuckets_),
+        number_of_buckets(number_of_buckets_)
+    {
+    }
+
+    //*********************************************************************
+    /// Initialise the unordered_set.
+    //*********************************************************************
+    void initialise()
+    {
+      if (!empty())
+      {
+        // For each bucket...
+        for (size_t i = 0; i < number_of_buckets; ++i)
+        {
+          bucket_t& bucket = pbuckets[i];
+
+          if (!bucket.empty())
+          {
+            // For each item in the bucket...
+            local_iterator it = bucket.begin();
+
+            while (it != bucket.end())
+            {
+              // Destroy the value contents.
+              it->key.~value_type();
+              ++it;
+              --construct_count;
+            }
+
+            // Now it's safe to clear the bucket.
+            bucket.clear();
+          }
+        }
+
+        // Now it's safe to clear the entire pool in one go.
+        pnodepool->release_all();
+      }
+
+      first = pbuckets;
+      last = first;
+    }
+
+  private:
+
+    //*********************************************************************
+    /// Adjust the first and last markers according to the new entry.
+    //*********************************************************************
+    void adjust_first_last_markers(bucket_t* pbucket)
+    {
+      if (pbucket < first)
+      {
+        first = pbucket;
+      }
+      else if (pbucket > last)
+      {
+        last = pbucket;
+      }
+    }
+
+    // Disable copy construction.
+    iunordered_set(const iunordered_set&);
+
+    /// The pool of data nodes used in the list.
+    pool_t* pnodepool;
+
+    /// The bucket list.
+    bucket_t* pbuckets;
+
+    /// The number of buckets.
+    const size_t number_of_buckets;
+
+    /// The first and last iterators to buckets with values.
+    bucket_t* first;
+    bucket_t* last;
+
+    /// The function that creates the hashes.
+    hasher key_hash_function;
+
+    /// The function that compares the keys for equality.
+    key_equal key_equal_function;
+
+    /// For library debugging purposes only.
+    etl::debug_count construct_count;
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first unordered_set.
+  ///\param rhs Reference to the second unordered_set.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup unordered_set
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator ==(const etl::iunordered_set<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_set<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first unordered_set.
+  ///\param rhs Reference to the second unordered_set.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup unordered_set
+  //***************************************************************************
+  template <typename TKey, typename TMapped, typename TKeyCompare>
+  bool operator !=(const etl::iunordered_set<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_set<TKey, TMapped, TKeyCompare>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //*************************************************************************
+  /// A templated unordered_set implementation that uses a fixed size buffer.
+  //*************************************************************************
+  template <typename TKey, const size_t MAX_SIZE_, size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> >
+  class unordered_set : public etl::iunordered_set<TKey, THash, TKeyEqual>
+  {
+  private:
+
+    typedef etl::iunordered_set<TKey, THash, TKeyEqual> base;
+
+  public:
+
+    static const size_t MAX_SIZE    = MAX_SIZE_;
+    static const size_t MAX_BUCKETS = MAX_BUCKETS_;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    unordered_set()
+      : base(node_pool, buckets, MAX_BUCKETS)
+    {
+      base::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    unordered_set(const unordered_set& other)
+      : base(node_pool, buckets, MAX_BUCKETS)
+    {
+      base::assign(other.cbegin(), other.cend());
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    unordered_set(TIterator first_, TIterator last_)
+      : base(node_pool, buckets, MAX_BUCKETS)
+    {
+      base::assign(first_, last_);
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~unordered_set()
+    {
+      base::initialise();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    unordered_set& operator = (const unordered_set& rhs)
+    {
+      // Skip if doing self assignment
+      if (this != &rhs)
+      {
+        base::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+  private:
+
+    /// The pool of nodes used for the unordered_set.
+    etl::pool<typename base::node_t, MAX_SIZE> node_pool;
+
+    /// The buckets of node lists.
+    etl::intrusive_forward_list<typename base::node_t> buckets[MAX_BUCKETS_];
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/user_type.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,126 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_USER_TYPE__
+#define __ETL_USER_TYPE__
+
+#include "platform.h"
+
+///\defgroup user_type user_type
+/// Smart enumerations.<br>
+/// A method of declaring a user type that also contains a set of constants,
+/// but are not constrained to just those values.
+/// This contrasts with 'enum_type', where the values are expected to <b>only</b> contain
+/// those defined as constants.
+/// <b>Declaring the enumeration.</b>
+///\code
+///   ETL_DECLARE_USER_TYPE(CompassDirection, int)
+///   ETL_USER_TYPE(North, 0)
+///   ETL_USER_TYPE(South, 180)
+///   ETL_USER_TYPE(East,  90)
+///   ETL_USER_TYPE(West,  270)
+///   ETL_END_USER_TYPE(CompassDirection)
+///\endcode
+/// <b>Using the enumeration.</b>
+///\code
+/// CompassDirection direction;          // Default construction.
+///
+/// direction = CompassDirection::North; // Assignment from an enumeration constant;
+///
+/// int value = int(direction);          // Explicit conversion to 'int'.
+/// int value = direction.get();
+///
+/// int& value = direction.get();        // Bind to internal value.
+/// const int& value = direction.get();
+///
+/// direction = CompassDirection(value); // Explicit conversion from 'int'.
+///
+/// direction = CompassDirection(3);     // Explicit conversion from a value.
+///
+/// ++direction;                         // Manipulate the value;
+/// direction -= CompassDirection(20);
+///
+/// direction = value;                   // Implicit conversion from 'int'. **** Compilation error ****
+///
+///\endcode
+///\ingroup utilities
+
+//*****************************************************************************
+// The declaration of the structure.
+//*****************************************************************************
+#define ETL_DECLARE_USER_TYPE(TypeName, ValueType) \
+  struct TypeName \
+  { \
+    /* Non-volatile definitions.*/ \
+    typedef ValueType value_type; \
+    TypeName() {} \
+    TypeName(const TypeName &other) : value(other.value) {} \
+    TypeName& operator=(const TypeName &other) { value = other.value; return *this; } \
+    explicit TypeName(ValueType value_) : value(value_) {} \
+    operator ValueType() const { return value; } \
+    ValueType& get() { return value; } \
+    const ValueType& get() const { return value; } \
+    TypeName& operator ++() { ++value; return *this; } \
+    TypeName operator ++(int) { TypeName temp(*this); TypeName::operator ++(); return temp; } \
+    TypeName& operator --() { --value; return *this; } \
+    TypeName operator --(int) { TypeName temp(*this); TypeName::operator --(); return temp; } \
+    TypeName& operator +=(const ValueType& rhs) { value += rhs; return *this; } \
+    TypeName& operator -=(const ValueType& rhs) { value -= rhs; return *this; } \
+    TypeName& operator *=(const ValueType& rhs) { value *= rhs; return *this; } \
+    TypeName& operator /=(const ValueType& rhs) { value /= rhs; return *this; } \
+    TypeName& operator %=(const ValueType& rhs) { value %= rhs; return *this; } \
+    TypeName& operator &=(const ValueType& rhs) { value &= rhs; return *this; } \
+    TypeName& operator |=(const ValueType& rhs) { value |= rhs; return *this; } \
+    TypeName& operator ^=(const ValueType& rhs) { value ^= rhs; return *this; } \
+    TypeName& operator <<=(ValueType distance) { value <<= distance; return *this; } \
+    TypeName& operator >>=(ValueType distance) { value >>= distance; return *this; } \
+  private: \
+    ValueType value; \
+  public: \
+    enum enum_type \
+    {
+
+//*****************************************************************************
+// The predefined constants.
+//*****************************************************************************
+#define ETL_USER_TYPE(enum_name, value) \
+      enum_name = value,
+
+//*****************************************************************************
+// The final section of the structure.
+//*****************************************************************************
+#define ETL_END_USER_TYPE(TypeName) \
+    }; \
+    TypeName(enum_type value_) : value(static_cast<value_type>(value_)) {} \
+  };
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,76 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_UTILITY__
+#define __ETL_UTILITY__
+
+#include "platform.h"
+#include "type_traits.h"
+
+///\defgroup utility utility
+///\ingroup utilities
+
+namespace etl
+{
+  //***************************************************************************
+  /// exchange
+  //***************************************************************************
+  template <typename T, typename U = T>
+  T exchange(T& object, U& new_value)
+  {
+    T old_value = object;
+    object = new_value;
+    return old_value;
+  }
+
+  //***************************************************************************
+  /// exchange (const)
+  //***************************************************************************
+  template <typename T, typename U = T>
+  T exchange(T& object, const U& new_value)
+  {
+    T old_value = object;
+    object = new_value;
+    return old_value;
+  }
+
+  //***************************************************************************
+  /// as_const
+  //***************************************************************************
+  template <typename T>
+  typename etl::add_const<T>::type& as_const(T& t)
+  {
+    return t;
+  }
+}
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/variant.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,941 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_VARIANT__
+#define __ETL_VARIANT__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "array.h"
+#include "largest.h"
+#include "exception.h"
+#include "type_traits.h"
+#include "integral_limits.h"
+#include "static_assert.h"
+#include "alignment.h"
+#include "error_handler.h"
+
+#if defined(ETL_COMPILER_KEIL)
+  #pragma diag_suppress 940
+  #pragma diag_suppress 111
+#endif
+
+#undef ETL_FILE
+#define ETL_FILE "24"
+
+//*****************************************************************************
+///\defgroup variant variant
+/// A class that can contain one a several specified types in a type safe manner.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  namespace __private_variant__
+  {
+    //*************************************************************************
+    /// Placeholder for unused template parameters.
+    /// This class is never instantiated.
+    //*************************************************************************
+    template <const size_t ID>
+    struct no_type
+    {
+    };
+  }
+
+  //***************************************************************************
+  /// Base exception for the variant class.
+  ///\ingroup variant
+  //***************************************************************************
+  class variant_exception : public exception
+  {
+  public:
+    variant_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// 'Unsupported type' exception for the variant class.
+  ///\ingroup variant
+  //***************************************************************************
+  class variant_incorrect_type_exception : public variant_exception
+  {
+  public:
+    variant_incorrect_type_exception(string_type file_name_, numeric_type line_number_)
+      : variant_exception(ETL_ERROR_TEXT("variant: unsupported type", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// A template class that can store any of the types defined in the template parameter list.
+  /// Supports up to 8 types.
+  ///\ingroup variant
+  //***************************************************************************
+  template <typename T1,
+            typename T2 = __private_variant__::no_type<2>,
+            typename T3 = __private_variant__::no_type<3>,
+            typename T4 = __private_variant__::no_type<4>,
+            typename T5 = __private_variant__::no_type<5>,
+            typename T6 = __private_variant__::no_type<6>,
+            typename T7 = __private_variant__::no_type<7>,
+            typename T8 = __private_variant__::no_type<8> >
+  class variant
+  {
+  private:
+
+    // All types of variant are friends.
+    template <typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7, typename U8>
+    friend class variant;
+
+    //***************************************************************************
+    /// The largest type.
+    //***************************************************************************
+    typedef typename largest_type<T1, T2, T3, T4, T5, T6, T7, T8>::type largest_t;
+
+    //***************************************************************************
+    /// The largest size.
+    //***************************************************************************
+    static const size_t SIZE = sizeof(largest_t);
+
+    //***************************************************************************
+    /// The largest alignment.
+    //***************************************************************************
+    static const size_t ALIGNMENT = etl::largest_alignment<T1, T2, T3, T4, T5, T6, T7, T8>::value;
+
+    //***************************************************************************
+    /// The type used for ids.
+    //***************************************************************************
+    typedef uint_least8_t type_id_t;
+
+    //***************************************************************************
+    /// The id a unsupported types.
+    //***************************************************************************
+    static const type_id_t UNSUPPORTED_TYPE_ID = integral_limits<type_id_t>::max;
+
+    //***************************************************************************
+    /// Short form of no_type placeholders.
+    //***************************************************************************
+    typedef __private_variant__::no_type<2> no_type2;
+    typedef __private_variant__::no_type<3> no_type3;
+    typedef __private_variant__::no_type<4> no_type4;
+    typedef __private_variant__::no_type<5> no_type5;
+    typedef __private_variant__::no_type<6> no_type6;
+    typedef __private_variant__::no_type<7> no_type7;
+    typedef __private_variant__::no_type<8> no_type8;
+
+    //***************************************************************************
+    /// Lookup the id of type.
+    //***************************************************************************
+    template <typename T>
+    struct Type_Id_Lookup
+    {
+      static const uint_least8_t type_id = etl::is_same<T, T1>::value ? 0 :
+                                           etl::is_same<T, T2>::value ? 1 :
+                                           etl::is_same<T, T3>::value ? 2 :
+                                           etl::is_same<T, T4>::value ? 3 :
+                                           etl::is_same<T, T5>::value ? 4 :
+                                           etl::is_same<T, T6>::value ? 5 :
+                                           etl::is_same<T, T7>::value ? 6 :
+                                           etl::is_same<T, T8>::value ? 7 :
+                                           UNSUPPORTED_TYPE_ID;
+    };
+
+    //***************************************************************************
+    /// Lookup for the id of type.
+    //***************************************************************************
+    template <typename T>
+    struct Type_Is_Supported : public integral_constant<bool,
+                                                       is_same<T, T1>::value ||
+                                                       is_same<T, T2>::value ||
+                                                       is_same<T, T3>::value ||
+                                                       is_same<T, T4>::value ||
+                                                       is_same<T, T5>::value ||
+                                                       is_same<T, T6>::value ||
+                                                       is_same<T, T7>::value ||
+                                                       is_same<T, T8>::value>
+    {
+    };
+
+  public:
+
+    //***************************************************************************
+    /// Destructor.
+    //***************************************************************************
+    ~variant()
+    {
+      destruct_current();
+    }
+
+    //*************************************************************************
+    //**** Reader types *******************************************************
+    //*************************************************************************
+
+    //*************************************************************************
+    /// Base reader type functor class.
+    /// Allows for typesafe access to the stored value types.
+    /// Define the reader type for 8 types.
+    //*************************************************************************
+    template <typename R1, typename R2 = no_type2, typename R3 = no_type3, typename R4 = no_type4, typename R5 = no_type5, typename R6 = no_type6, typename R7 = no_type7, typename R8 = no_type8>
+    class reader_type
+    {
+    public:
+
+      friend class variant;
+
+      virtual void read(typename etl::parameter_type<R1>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R2>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R3>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R4>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R5>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R6>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R7>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R8>::type value) = 0;
+    };
+
+    //*************************************************************************
+    /// Define the reader type for 7 types.
+    //*************************************************************************
+    template <typename R1, typename R2, typename R3, typename R4, typename R5, typename R6, typename R7>
+    class reader_type<R1, R2, R3, R4, R5, R6, R7, no_type8>
+    {
+    public:
+
+      friend class variant;
+
+      virtual void read(typename etl::parameter_type<R1>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R2>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R3>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R4>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R5>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R6>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R7>::type value) = 0;
+
+    private:
+
+      void read(no_type8&) {};
+    };
+
+    //*************************************************************************
+    /// Define the reader type for 6 types.
+    //*************************************************************************
+    template <typename R1, typename R2, typename R3, typename R4, typename R5, typename R6>
+    class reader_type<R1, R2, R3, R4, R5, R6, no_type7, no_type8>
+    {
+    public:
+
+      friend class variant;
+
+      virtual void read(typename etl::parameter_type<R1>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R2>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R3>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R4>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R5>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R6>::type value) = 0;
+
+    private:
+
+      void read(no_type7&) {};
+      void read(no_type8&) {};
+    };
+
+    //*************************************************************************
+    /// Define the reader type for 5 types.
+    //*************************************************************************
+    template <typename R1, typename R2, typename R3, typename R4, typename R5>
+    class reader_type<R1, R2, R3, R4, R5, no_type6, no_type7, no_type8>
+    {
+    public:
+
+      friend class variant;
+
+      virtual void read(typename etl::parameter_type<R1>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R2>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R3>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R4>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R5>::type value) = 0;
+
+    private:
+
+      void read(no_type6&) {};
+      void read(no_type7&) {};
+      void read(no_type8&) {};
+    };
+
+    //*************************************************************************
+    /// Define the reader type for 4 types.
+    //*************************************************************************
+    template <typename R1, typename R2, typename R3, typename R4>
+    class reader_type<R1, R2, R3, R4, no_type5, no_type6, no_type7, no_type8>
+    {
+    public:
+
+      friend class variant;
+
+      virtual void read(typename etl::parameter_type<R1>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R2>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R3>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R4>::type value) = 0;
+
+    private:
+
+      void read(no_type5&) {};
+      void read(no_type6&) {};
+      void read(no_type7&) {};
+      void read(no_type8&) {};
+    };
+
+    //*************************************************************************
+    /// Define the reader type for 3 types.
+    //*************************************************************************
+    template <typename R1, typename R2, typename R3>
+    class reader_type<R1, R2, R3, no_type4, no_type5, no_type6, no_type7, no_type8>
+    {
+    public:
+
+      friend class variant;
+
+      virtual void read(typename etl::parameter_type<R1>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R2>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R3>::type value) = 0;
+
+    private:
+
+      void read(no_type4&) {};
+      void read(no_type5&) {};
+      void read(no_type6&) {};
+      void read(no_type7&) {};
+      void read(no_type8&) {};
+    };
+
+    //*************************************************************************
+    /// Define the reader type for 2 types.
+    //*************************************************************************
+    template <typename R1, typename R2>
+    class reader_type<R1, R2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8>
+    {
+    public:
+
+      friend class variant;
+
+      virtual void read(typename etl::parameter_type<R1>::type value) = 0;
+      virtual void read(typename etl::parameter_type<R2>::type value) = 0;
+
+    private:
+
+      void read(no_type3&) {};
+      void read(no_type4&) {};
+      void read(no_type5&) {};
+      void read(no_type6&) {};
+      void read(no_type7&) {};
+      void read(no_type8&) {};
+    };
+
+    //*************************************************************************
+    /// Define the reader type for 1 type.
+    //*************************************************************************
+    template <typename R1>
+    class reader_type<R1, no_type2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8>
+    {
+    public:
+
+      friend class variant;
+
+      virtual void read(typename etl::parameter_type<R1>::type value) = 0;
+
+    private:
+
+      void read(no_type2&) {};
+      void read(no_type3&) {};
+      void read(no_type4&) {};
+      void read(no_type5&) {};
+      void read(no_type6&) {};
+      void read(no_type7&) {};
+      void read(no_type8&) {};
+    };
+
+    //*************************************************************************
+    //**** Up-cast functors ***************************************************
+    //*************************************************************************
+
+    //*************************************************************************
+    /// Base upcast_functor for eight types.
+    //*************************************************************************
+    template <typename TBase, typename U1, typename U2 = no_type2, typename U3 = no_type3, typename U4 = no_type4, typename U5 = no_type5, typename U6 = no_type6, typename U7 = no_type7, typename U8 = no_type8>
+    class upcast_functor
+    {
+    public:
+
+      TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId)
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<U1&>(*p_data);
+          case 1: return reinterpret_cast<U2&>(*p_data);
+          case 2: return reinterpret_cast<U3&>(*p_data);
+          case 3: return reinterpret_cast<U4&>(*p_data);
+          case 4: return reinterpret_cast<U5&>(*p_data);
+          case 5: return reinterpret_cast<U6&>(*p_data);
+          case 6: return reinterpret_cast<U7&>(*p_data);
+          case 7: return reinterpret_cast<U8&>(*p_data);
+          default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+        }
+      }
+
+      const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<const U1&>(*p_data);
+          case 1: return reinterpret_cast<const U2&>(*p_data);
+          case 2: return reinterpret_cast<const U3&>(*p_data);
+          case 3: return reinterpret_cast<const U4&>(*p_data);
+          case 4: return reinterpret_cast<const U5&>(*p_data);
+          case 5: return reinterpret_cast<const U6&>(*p_data);
+          case 6: return reinterpret_cast<const U7&>(*p_data);
+          case 7: return reinterpret_cast<const U8&>(*p_data);
+          default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+        }
+      }
+    };
+
+    //*************************************************************************
+    /// Upcast_functor for seven types.
+    //*************************************************************************
+    template <typename TBase, typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7>
+    class upcast_functor<TBase, U1, U2, U3, U4, U5, U6, U7, no_type8>
+    {
+    public:
+
+      TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId)
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<U1&>(*p_data);
+          case 1: return reinterpret_cast<U2&>(*p_data);
+          case 2: return reinterpret_cast<U3&>(*p_data);
+          case 3: return reinterpret_cast<U4&>(*p_data);
+          case 4: return reinterpret_cast<U5&>(*p_data);
+          case 5: return reinterpret_cast<U6&>(*p_data);
+          case 6: return reinterpret_cast<U7&>(*p_data);
+          default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+        }
+      }
+
+      const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<const U1&>(*p_data);
+          case 1: return reinterpret_cast<const U2&>(*p_data);
+          case 2: return reinterpret_cast<const U3&>(*p_data);
+          case 3: return reinterpret_cast<const U4&>(*p_data);
+          case 4: return reinterpret_cast<const U5&>(*p_data);
+          case 5: return reinterpret_cast<const U6&>(*p_data);
+          case 6: return reinterpret_cast<const U7&>(*p_data);
+          default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+        }
+      }
+    };
+
+    //*************************************************************************
+    /// Upcast_functor for six types.
+    //*************************************************************************
+    template <typename TBase, typename U1, typename U2, typename U3, typename U4, typename U5, typename U6>
+    class upcast_functor<TBase, U1, U2, U3, U4, U5, U6, no_type7, no_type8>
+    {
+    public:
+
+      TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId)
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<U1&>(*p_data);
+          case 1: return reinterpret_cast<U2&>(*p_data);
+          case 2: return reinterpret_cast<U3&>(*p_data);
+          case 3: return reinterpret_cast<U4&>(*p_data);
+          case 4: return reinterpret_cast<U5&>(*p_data);
+          case 5: return reinterpret_cast<U6&>(*p_data);
+          default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+        }
+      }
+
+      const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<const U1&>(*p_data);
+          case 1: return reinterpret_cast<const U2&>(*p_data);
+          case 2: return reinterpret_cast<const U3&>(*p_data);
+          case 3: return reinterpret_cast<const U4&>(*p_data);
+          case 4: return reinterpret_cast<const U5&>(*p_data);
+          case 5: return reinterpret_cast<const U6&>(*p_data);
+          default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+        }
+      }
+    };
+
+    //*************************************************************************
+    /// Upcast_functor for five types.
+    //*************************************************************************
+    template <typename TBase, typename U1, typename U2, typename U3, typename U4, typename U5>
+    class upcast_functor<TBase, U1, U2, U3, U4, U5, no_type6, no_type7, no_type8>
+    {
+    public:
+
+      TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId)
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<U1&>(*p_data);
+          case 1: return reinterpret_cast<U2&>(*p_data);
+          case 2: return reinterpret_cast<U3&>(*p_data);
+          case 3: return reinterpret_cast<U4&>(*p_data);
+          case 4: return reinterpret_cast<U5&>(*p_data);
+          default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+        }
+      }
+
+      const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<const U1&>(*p_data);
+          case 1: return reinterpret_cast<const U2&>(*p_data);
+          case 2: return reinterpret_cast<const U3&>(*p_data);
+          case 3: return reinterpret_cast<const U4&>(*p_data);
+          case 4: return reinterpret_cast<const U5&>(*p_data);
+          default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+        }
+      }
+    };
+
+    //*************************************************************************
+    /// Upcast_functor for four types.
+    //*************************************************************************
+    template <typename TBase, typename U1, typename U2, typename U3, typename U4>
+    class upcast_functor<TBase, U1, U2, U3, U4, no_type5, no_type6, no_type7, no_type8>
+    {
+    public:
+
+      TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId)
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<U1&>(*p_data);
+          case 1: return reinterpret_cast<U2&>(*p_data);
+          case 2: return reinterpret_cast<U3&>(*p_data);
+          case 3: return reinterpret_cast<U4&>(*p_data);
+          default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+        }
+      }
+
+      const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<const U1&>(*p_data);
+          case 1: return reinterpret_cast<const U2&>(*p_data);
+          case 2: return reinterpret_cast<const U3&>(*p_data);
+          case 3: return reinterpret_cast<const U4&>(*p_data);
+          default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+        }
+      }
+    };
+
+    //*************************************************************************
+    /// Upcast_functor for three types.
+    //*************************************************************************
+    template <typename TBase, typename U1, typename U2, typename U3>
+    class upcast_functor<TBase, U1, U2, U3, no_type4, no_type5, no_type6, no_type7, no_type8>
+    {
+    public:
+
+      TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId)
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<U1&>(*p_data);
+          case 1: return reinterpret_cast<U2&>(*p_data);
+          case 2: return reinterpret_cast<U3&>(*p_data);
+          default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+        }
+      }
+
+      const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<const U1&>(*p_data);
+          case 1: return reinterpret_cast<const U2&>(*p_data);
+          case 2: return reinterpret_cast<const U3&>(*p_data);
+          default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+        }
+      }
+    };
+
+    //*************************************************************************
+    /// Upcast_functor for two types.
+    //*************************************************************************
+    template <typename TBase, typename U1, typename U2>
+    class upcast_functor<TBase, U1, U2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8>
+    {
+    public:
+
+      TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId)
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<U1&>(*p_data);
+          case 1: return reinterpret_cast<U2&>(*p_data);
+          default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0));
+        }
+      }
+
+      const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const
+      {
+        switch (typeId)
+        {
+          case 0: return reinterpret_cast<const U1&>(*p_data);
+          case 1: return reinterpret_cast<const U2&>(*p_data);
+          default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0));
+        }
+      }
+    };
+
+    //*************************************************************************
+    /// Upcast_functor for one type.
+    //*************************************************************************
+    template <typename TBase, typename U1>
+    class upcast_functor<TBase, U1, no_type2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8>
+    {
+    public:
+
+      TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId)
+      {
+        return reinterpret_cast<U1&>(*p_data);
+      }
+
+      const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const
+      {
+        return reinterpret_cast<const U1&>(*p_data);
+      }
+    };
+
+    //***************************************************************************
+    /// The base type for derived readers.
+    //***************************************************************************
+    typedef reader_type<T1, T2, T3, T4, T5, T6, T7, T8> reader;
+
+    //***************************************************************************
+    /// Default constructor.
+    /// Sets the state of the instance to containing no valid data.
+    //***************************************************************************
+    variant()
+      : type_id(UNSUPPORTED_TYPE_ID)
+    {
+    }
+
+    //***************************************************************************
+    /// Constructor that catches any types that are not supported.
+    /// Forces a STATIC_ASSERT.
+    //***************************************************************************
+    template <typename T>
+    variant(const T& value)
+    {
+      STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
+
+      ::new (static_cast<T*>(data)) T(value);
+      type_id = Type_Id_Lookup<T>::type_id;
+    }
+
+    //***************************************************************************
+    /// Copy constructor.
+    ///\param other The other variant object to copy.
+    //***************************************************************************
+    variant(const variant& other)
+    {
+      switch (other.type_id)
+      {
+        case 0:  ::new (static_cast<T1*>(data)) T1(other.get<T1>()); break;
+        case 1:  ::new (static_cast<T2*>(data)) T2(other.get<T2>()); break;
+        case 2:  ::new (static_cast<T3*>(data)) T3(other.get<T3>()); break;
+        case 3:  ::new (static_cast<T4*>(data)) T4(other.get<T4>()); break;
+        case 4:  ::new (static_cast<T5*>(data)) T5(other.get<T5>()); break;
+        case 5:  ::new (static_cast<T6*>(data)) T6(other.get<T6>()); break;
+        case 6:  ::new (static_cast<T7*>(data)) T7(other.get<T7>()); break;
+        case 7:  ::new (static_cast<T8*>(data)) T8(other.get<T8>()); break;
+        default: break;
+      }
+
+      type_id = other.type_id;
+    }
+
+    //***************************************************************************
+    /// Assignment operator for T1 type.
+    ///\param value The value to assign.
+    //***************************************************************************
+    template <typename T>
+    variant& operator =(const T& value)
+    {
+      STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
+
+      destruct_current();
+      ::new (static_cast<T*>(data)) T(value);
+      type_id = Type_Id_Lookup<T>::type_id;
+
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Assignment operator for variant type.
+    ///\param other The variant to assign.
+    //***************************************************************************
+    variant& operator =(const variant& other)
+    {
+      if (this != &other)
+      {
+        destruct_current();
+
+        switch (other.type_id)
+        {
+        case 0:  ::new (static_cast<T1*>(data)) T1(other.get<T1>()); break;
+        case 1:  ::new (static_cast<T2*>(data)) T2(other.get<T2>()); break;
+        case 2:  ::new (static_cast<T3*>(data)) T3(other.get<T3>()); break;
+        case 3:  ::new (static_cast<T4*>(data)) T4(other.get<T4>()); break;
+        case 4:  ::new (static_cast<T5*>(data)) T5(other.get<T5>()); break;
+        case 5:  ::new (static_cast<T6*>(data)) T6(other.get<T6>()); break;
+        case 6:  ::new (static_cast<T7*>(data)) T7(other.get<T7>()); break;
+        case 7:  ::new (static_cast<T8*>(data)) T8(other.get<T8>()); break;
+        default: break;
+        }
+
+        type_id = other.type_id;
+      }
+
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Checks if the type is the same as the current stored type.
+    /// For variants with the same type declarations.
+    ///\return <b>true</b> if the types are the same, otherwise <b>false</b>.
+    //***************************************************************************
+    bool is_same_type(const variant& other) const
+    {
+      return type_id == other.type_id;
+    }
+
+    //***************************************************************************
+    /// Checks if the type is the same as the current stored type.
+    /// For variants with differing declarations.
+    ///\return <b>true</b> if the types are the same, otherwise <b>false</b>.
+    //***************************************************************************
+    template <typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7, typename U8>
+    bool is_same_type(const variant<U1, U2, U3, U4, U5, U6, U7, U8>& other) const
+    {
+      bool is_same = false;
+
+      switch (other.type_id)
+      {
+        case 0: is_same = (type_id == Type_Id_Lookup<U1>::type_id); break;
+        case 1: is_same = (type_id == Type_Id_Lookup<U2>::type_id); break;
+        case 2: is_same = (type_id == Type_Id_Lookup<U3>::type_id); break;
+        case 3: is_same = (type_id == Type_Id_Lookup<U4>::type_id); break;
+        case 4: is_same = (type_id == Type_Id_Lookup<U5>::type_id); break;
+        case 5: is_same = (type_id == Type_Id_Lookup<U6>::type_id); break;
+        case 6: is_same = (type_id == Type_Id_Lookup<U7>::type_id); break;
+        case 7: is_same = (type_id == Type_Id_Lookup<U8>::type_id); break;
+        default: break;
+      }
+
+      return is_same;
+    }
+
+    //***************************************************************************
+    /// Calls the supplied reader instance.
+    /// The 'read' function appropriate to the current type is called with the stored value.
+    //***************************************************************************
+    void call(reader& reader)
+    {
+      switch (type_id)
+      {
+        case 0: reader.read(static_cast<T1&>(data)); break;
+        case 1: reader.read(static_cast<T2&>(data)); break;
+        case 2: reader.read(static_cast<T3&>(data)); break;
+        case 3: reader.read(static_cast<T4&>(data)); break;
+        case 4: reader.read(static_cast<T5&>(data)); break;
+        case 5: reader.read(static_cast<T6&>(data)); break;
+        case 6: reader.read(static_cast<T7&>(data)); break;
+        case 7: reader.read(static_cast<T8&>(data)); break;
+        default: break;
+      }
+    }
+
+    //***************************************************************************
+    /// Checks whether a valid value is currently stored.
+    ///\return <b>true</b> if the value is valid, otherwise <b>false</b>.
+    //***************************************************************************
+    bool is_valid() const
+    {
+      return type_id != UNSUPPORTED_TYPE_ID;
+    }
+
+    //***************************************************************************
+    /// Checks to see if the type currently stored is the same as that specified in the template parameter.
+    ///\return <b>true</b> if it is the specified type, otherwise <b>false</b>.
+    //***************************************************************************
+    template <typename T>
+    bool is_type() const
+    {
+      return type_id == Type_Id_Lookup<T>::type_id;
+    }
+
+    //***************************************************************************
+    /// Clears the value to 'no valid stored value'.
+    //***************************************************************************
+    void clear()
+    {
+      destruct_current();
+    }
+
+    //***************************************************************************
+    /// Gets the value stored as the specified template type.
+    /// Throws a variant_incorrect_type_exception if the actual type is not that specified.
+    ///\return A reference to the value.
+    //***************************************************************************
+    template <typename T>
+    T& get()
+    {
+      STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
+      ETL_ASSERT(is_type<T>(), ETL_ERROR(variant_incorrect_type_exception));
+
+      return static_cast<T&>(data);
+    }
+
+    //***************************************************************************
+    /// Gets the value stored as the specified template type.
+    /// Throws a variant_incorrect_type_exception if the actual type is not that specified.
+    ///\return A const reference to the value.
+    //***************************************************************************
+    template <typename T>
+    const T& get() const
+    {
+      STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
+      ETL_ASSERT(is_type<T>(), ETL_ERROR(variant_incorrect_type_exception));
+
+      return static_cast<const T&>(data);
+    }
+
+    //***************************************************************************
+    /// Gets the value stored as the specified template type.
+    ///\return A reference to the value.
+    //***************************************************************************
+    template <typename TBase>
+    TBase& upcast()
+    {
+      return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(data, type_id);
+    }
+
+    //***************************************************************************
+    /// Gets the value stored as the specified template type.
+    ///\return A const reference to the value.
+    //***************************************************************************
+    template <typename TBase>
+    const TBase& upcast() const
+    {
+      return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(data, type_id);
+    }
+
+    //***************************************************************************
+    /// Conversion operators for each type.
+    //***************************************************************************
+    operator T1&() { return get<T1>(); }
+    operator T2&() { return get<T2>(); }
+    operator T3&() { return get<T3>(); }
+    operator T4&() { return get<T4>(); }
+    operator T5&() { return get<T5>(); }
+    operator T6&() { return get<T6>(); }
+    operator T7&() { return get<T7>(); }
+    operator T8&() { return get<T8>(); }
+
+    //***************************************************************************
+    /// Checks if the template type is supported by the implementation of variant..
+    ///\return <b>true</b> if the type is supported, otherwise <b>false</b>.
+    //***************************************************************************
+    template <typename T>
+    static bool is_supported_type()
+    {
+      return Type_Is_Supported<T>::value;
+    }
+
+  private:
+
+    //***************************************************************************
+    /// Destruct the current occupant of the variant.
+    //***************************************************************************
+    void destruct_current()
+    {
+      switch (type_id)
+      {
+        case 0: { static_cast<T1*>(data)->~T1(); break; }
+        case 1: { static_cast<T2*>(data)->~T2(); break; }
+        case 2: { static_cast<T3*>(data)->~T3(); break; }
+        case 3: { static_cast<T4*>(data)->~T4(); break; }
+        case 4: { static_cast<T5*>(data)->~T5(); break; }
+        case 5: { static_cast<T6*>(data)->~T6(); break; }
+        case 6: { static_cast<T7*>(data)->~T7(); break; }
+        case 7: { static_cast<T8*>(data)->~T8(); break; }
+        default: { break; }
+      }
+
+      type_id = UNSUPPORTED_TYPE_ID;
+    }
+
+    //***************************************************************************
+    /// The internal storage.
+    /// Aligned on a suitable boundary, which should be good for all types.
+    //***************************************************************************
+    typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+
+    //***************************************************************************
+    /// The id of the current stored type.
+    //***************************************************************************
+    type_id_t type_id;
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/variant_pool.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,375 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+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 __ETL_VARIANT_POOL__
+#define __ETL_VARIANT_POOL__
+
+#include <stdint.h>
+#include <utility>
+
+#include "platform.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "largest.h"
+#include "type_traits.h"
+#include "alignment.h"
+#include "static_assert.h"
+#include "type_lookup.h"
+#include <pool.h>
+
+#undef ETL_FILE
+#define ETL_FILE "40"
+
+namespace etl
+{
+  //***************************************************************************
+  class variant_pool_exception : public etl::exception
+  {
+  public:
+
+    variant_pool_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  class variant_pool_cannot_create : public etl::variant_pool_exception
+  {
+  public:
+
+    variant_pool_cannot_create(string_type file_name_, numeric_type line_number_)
+      : variant_pool_exception(ETL_ERROR_TEXT("variant_pool:cannot create", ETL_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  class variant_pool_did_not_create : public etl::variant_pool_exception
+  {
+  public:
+
+    variant_pool_did_not_create(string_type file_name_, numeric_type line_number_)
+      : variant_pool_exception(ETL_ERROR_TEXT("variant_pool:did not create", ETL_FILE"B"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  template <const size_t MAX_SIZE_,
+            typename T1,
+            typename T2  = void,
+            typename T3  = void,
+            typename T4  = void,
+            typename T5  = void,
+            typename T6  = void,
+            typename T7  = void,
+            typename T8  = void,
+            typename T9  = void,
+            typename T10 = void,
+            typename T11 = void,
+            typename T12 = void,
+            typename T13 = void,
+            typename T14 = void,
+            typename T15 = void,
+            typename T16 = void>
+  class variant_pool
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Default constructor.
+    //*************************************************************************
+    variant_pool()
+    {
+    }
+
+#if !ETL_CPP11_SUPPORTED
+    //*************************************************************************
+    /// Creates the object. Default constructor.
+    //*************************************************************************
+    template <typename T>
+    T* create()
+    {
+      STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type");
+
+      T* p = std::nullptr;
+
+      if (pool.full())
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create));
+      }
+      else
+      {
+        p = pool.template allocate<T>();
+
+        if (p != std::nullptr)
+        {
+          new (p) T();
+        }
+      }
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Creates the object. One parameter constructor.
+    //*************************************************************************
+    template <typename T, typename TP1>
+    T* create(const TP1& p1)
+    {
+      STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type");
+
+      T* p = std::nullptr;
+
+      if (pool.full())
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create));
+      }
+      else
+      {
+        p = pool.template allocate<T>();
+
+        if (p != std::nullptr)
+        {
+          new (p) T(p1);
+        }
+      }
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Creates the object. Two parameter constructor.
+    //*************************************************************************
+    template <typename T, typename TP1, typename TP2>
+    T* create(const TP1& p1, const TP2& p2)
+    {
+      STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type");
+
+      T* p = std::nullptr;
+
+      if (pool.full())
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create));
+      }
+      else
+      {
+        p = pool.template allocate<T>();
+
+        if (p != std::nullptr)
+        {
+          new (p) T(p1, p2);
+        }
+      }
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Creates the object. Three parameter constructor.
+    //*************************************************************************
+    template <typename T, typename TP1, typename TP2, typename TP3>
+    T* create(const TP1& p1, const TP2& p2, const TP3& p3)
+    {
+      STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type");
+
+      T* p = std::nullptr;
+
+      if (pool.full())
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create));
+      }
+      else
+      {
+        p = pool.template allocate<T>();
+
+        if (p != std::nullptr)
+        {
+          new (p) T(p1, p2, p3);
+        }
+      }
+
+      return p;
+    }
+
+    //*************************************************************************
+    /// Creates the object. Four parameter constructor.
+    //*************************************************************************
+    template <typename T, typename TP1, typename TP2, typename TP3, typename TP4>
+    T* create(const TP1& p1, const TP2& p2, const TP3& p3, const TP4& p4)
+    {
+      STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type");
+
+      T* p = std::nullptr;
+
+      if (pool.full())
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create));
+      }
+      else
+      {
+        p = pool.template allocate<T>();
+
+        if (p != std::nullptr)
+        {
+          new (p) T(p1, p2, p3, p4);
+        }
+      }
+
+      return p;
+    }
+#else
+    //*************************************************************************
+    /// Creates the object from a type. Variadic parameter constructor.
+    //*************************************************************************
+    template <typename T, typename... Args>
+    T* create(Args&&... args)
+    {
+      STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type");
+
+      T* p = std::nullptr;
+
+      if (pool.full())
+      {
+        ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create));
+      }
+      else
+      {
+        p = pool.template allocate<T>();
+
+        if (p != std::nullptr)
+        {
+          new (p) T(std::forward<Args>(args)...);
+        }
+      }
+
+      return p;
+    }
+#endif
+
+    //*************************************************************************
+    /// Destroys the object.
+    //*************************************************************************
+    template <typename T>
+    bool destroy(const T* const p)
+    {
+      STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value ||
+                     etl::is_base_of<T, T1>::value  ||
+                     etl::is_base_of<T, T2>::value  ||
+                     etl::is_base_of<T, T3>::value  ||
+                     etl::is_base_of<T, T4>::value  ||
+                     etl::is_base_of<T, T5>::value  ||
+                     etl::is_base_of<T, T6>::value  ||
+                     etl::is_base_of<T, T7>::value  ||
+                     etl::is_base_of<T, T8>::value  ||
+                     etl::is_base_of<T, T9>::value  ||
+                     etl::is_base_of<T, T10>::value ||
+                     etl::is_base_of<T, T11>::value ||
+                     etl::is_base_of<T, T12>::value ||
+                     etl::is_base_of<T, T13>::value ||
+                     etl::is_base_of<T, T14>::value ||
+                     etl::is_base_of<T, T15>::value ||
+                     etl::is_base_of<T, T16>::value), "Invalid type");
+
+      p->~T();
+
+      void* vp = reinterpret_cast<char*>(const_cast<T*>(p));
+
+      if (pool.is_in_pool(vp))
+      {
+        pool.release(vp);
+        return true;
+      }
+      else
+      {
+        ETL_ASSERT(false, ETL_ERROR(variant_pool_did_not_create));
+        return false;
+      }
+    }
+
+    //*************************************************************************
+    /// Returns the maximum number of items in the variant_pool.
+    //*************************************************************************
+    size_t max_size() const
+    {
+      return MAX_SIZE;
+    }
+
+    //*************************************************************************
+    /// Returns the number of free items in the variant_pool.
+    //*************************************************************************
+    size_t available() const
+    {
+      return pool.available();
+    }
+
+    //*************************************************************************
+    /// Returns the number of allocated items in the variant_pool.
+    //*************************************************************************
+    size_t size() const
+    {
+      return pool.size();
+    }
+
+    //*************************************************************************
+    /// Checks to see if there are no allocated items in the variant_pool.
+    /// \return <b>true</b> if there are none allocated.
+    //*************************************************************************
+    bool empty() const
+    {
+      return pool.empty();
+    }
+
+    //*************************************************************************
+    /// Checks to see if there are no free items in the variant_pool.
+    /// \return <b>true</b> if there are none free.
+    //*************************************************************************
+    bool full() const
+    {
+      return pool.full();
+    }
+
+  private:
+
+    variant_pool(const variant_pool&);
+    variant_pool& operator =(const variant_pool&);
+
+    // The pool.
+    etl::generic_pool<etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::size,
+                      etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::alignment,
+                      MAX_SIZE> pool;
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vector.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,1242 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_VECTOR__
+#define __ETL_VECTOR__
+
+#define __ETL_IN_VECTOR_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <stddef.h>
+
+#include "platform.h"
+#include "algorithm.h"
+#include "type_traits.h"
+#include "parameter_type.h"
+#include "error_handler.h"
+#include "memory.h"
+#include "container.h"
+#include "alignment.h"
+#include "array.h"
+#include "exception.h"
+#include "debug_count.h"
+#include "private/vector_base.h"
+
+#ifdef ETL_COMPILER_GCC
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#endif
+
+//*****************************************************************************
+///\defgroup vector vector
+/// A vector with the capacity defined at compile time.
+///\ingroup containers
+//*****************************************************************************
+
+namespace etl
+{
+  //***************************************************************************
+  /// The base class for specifically sized vectors.
+  /// Can be used as a reference type for all vectors containing a specific type.
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  class ivector : public etl::vector_base
+  {
+  public:
+
+    typedef T                                     value_type;
+    typedef T&                                    reference;
+    typedef const T&                              const_reference;
+    typedef T*                                    pointer;
+    typedef const T*                              const_pointer;
+    typedef T*                                    iterator;
+    typedef const T*                              const_iterator;
+    typedef std::reverse_iterator<iterator>       reverse_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef size_t                                size_type;
+    typedef typename std::iterator_traits<iterator>::difference_type difference_type;
+
+  protected:
+
+    typedef typename etl::parameter_type<T>::type parameter_t;
+
+  public:
+
+    //*********************************************************************
+    /// Returns an iterator to the beginning of the vector.
+    ///\return An iterator to the beginning of the vector.
+    //*********************************************************************
+    iterator begin()
+    {
+      return p_buffer;
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the vector.
+    ///\return A const iterator to the beginning of the vector.
+    //*********************************************************************
+    const_iterator begin() const
+    {
+      return p_buffer;
+    }
+
+    //*********************************************************************
+    /// Returns an iterator to the end of the vector.
+    ///\return An iterator to the end of the vector.
+    //*********************************************************************
+    iterator end()
+    {
+      return p_end;
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the vector.
+    ///\return A const iterator to the end of the vector.
+    //*********************************************************************
+    const_iterator end() const
+    {
+      return p_end;
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the beginning of the vector.
+    ///\return A const iterator to the beginning of the vector.
+    //*********************************************************************
+    const_iterator cbegin() const
+    {
+      return p_buffer;
+    }
+
+    //*********************************************************************
+    /// Returns a const_iterator to the end of the vector.
+    ///\return A const iterator to the end of the vector.
+    //*********************************************************************
+    const_iterator cend() const
+    {
+      return p_end;
+    }
+
+    //*********************************************************************
+    /// Returns an reverse iterator to the reverse beginning of the vector.
+    ///\return Iterator to the reverse beginning of the vector.
+    //*********************************************************************
+    reverse_iterator rbegin()
+    {
+      return reverse_iterator(end());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the vector.
+    ///\return Const iterator to the reverse beginning of the vector.
+    //*********************************************************************
+    const_reverse_iterator rbegin() const
+    {
+      return const_reverse_iterator(end());
+    }
+
+    //*********************************************************************
+    /// Returns a reverse iterator to the end + 1 of the vector.
+    ///\return Reverse iterator to the end + 1 of the vector.
+    //*********************************************************************
+    reverse_iterator rend()
+    {
+      return reverse_iterator(begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the vector.
+    ///\return Const reverse iterator to the end + 1 of the vector.
+    //*********************************************************************
+    const_reverse_iterator rend() const
+    {
+      return const_reverse_iterator(begin());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the reverse beginning of the vector.
+    ///\return Const reverse iterator to the reverse beginning of the vector.
+    //*********************************************************************
+    const_reverse_iterator crbegin() const
+    {
+      return const_reverse_iterator(cend());
+    }
+
+    //*********************************************************************
+    /// Returns a const reverse iterator to the end + 1 of the vector.
+    ///\return Const reverse iterator to the end + 1 of the vector.
+    //*********************************************************************
+    const_reverse_iterator crend() const
+    {
+      return const_reverse_iterator(cbegin());
+    }
+
+    //*********************************************************************
+    /// Resizes the vector.
+    /// If asserts or exceptions are enabled and the new size is larger than the
+    /// maximum then a vector_full is thrown.
+    ///\param new_size The new size.
+    //*********************************************************************
+    void resize(size_t new_size)
+    {
+      resize(new_size, T());
+    }
+
+    //*********************************************************************
+    /// Resizes the vector.
+    /// If asserts or exceptions are enabled and the new size is larger than the
+    /// maximum then a vector_full is thrown.
+    ///\param new_size The new size.
+    ///\param value   The value to fill new elements with. Default = default constructed value.
+    //*********************************************************************
+    void resize(size_t new_size, T value)
+    {
+      ETL_ASSERT(new_size <= CAPACITY, ETL_ERROR(vector_full));
+
+      const size_t current_size = size();
+      size_t delta = (current_size < new_size) ? new_size - current_size : current_size - new_size;
+
+      if (current_size < new_size)
+      {
+        etl::uninitialized_fill_n(p_end, delta, value);
+#if defined(ETL_DEBUG)
+        construct_count += delta;
+#endif
+      }
+      else
+      {
+        etl::destroy_n(p_end - delta, delta);
+#if defined(ETL_DEBUG)
+        construct_count -= delta;
+#endif
+      }
+
+      p_end = p_buffer + new_size;
+    }
+
+    //*********************************************************************
+    /// Does nothing.
+    //*********************************************************************
+    void reserve(size_t)
+    {
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'i'
+    ///\param i The index.
+    ///\return A reference to the value at index 'i'
+    //*********************************************************************
+    reference operator [](size_t i)
+    {
+      return p_buffer[i];
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'i'
+    ///\param i The index.
+    ///\return A const reference to the value at index 'i'
+    //*********************************************************************
+    const_reference operator [](size_t i) const
+    {
+      return p_buffer[i];
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the value at index 'i'
+    /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range.
+    ///\param i The index.
+    ///\return A reference to the value at index 'i'
+    //*********************************************************************
+    reference at(size_t i)
+    {
+      ETL_ASSERT(i < size(), ETL_ERROR(vector_out_of_bounds));
+      return p_buffer[i];
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the value at index 'i'
+    /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range.
+    ///\param i The index.
+    ///\return A const reference to the value at index 'i'
+    //*********************************************************************
+    const_reference at(size_t i) const
+    {
+      ETL_ASSERT(i < size(), ETL_ERROR(vector_out_of_bounds));
+      return p_buffer[i];
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the first element.
+    ///\return A reference to the first element.
+    //*********************************************************************
+    reference front()
+    {
+      return *p_buffer;
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the first element.
+    ///\return A const reference to the first element.
+    //*********************************************************************
+    const_reference front() const
+    {
+      return *p_buffer;
+    }
+
+    //*********************************************************************
+    /// Returns a reference to the last element.
+    ///\return A reference to the last element.
+    //*********************************************************************
+    reference back()
+    {
+      return *(p_end - 1);
+    }
+
+    //*********************************************************************
+    /// Returns a const reference to the last element.
+    ///\return A const reference to the last element.
+    //*********************************************************************
+    const_reference back() const
+    {
+      return *(p_end - 1);
+    }
+
+    //*********************************************************************
+    /// Returns a pointer to the beginning of the vector data.
+    ///\return A pointer to the beginning of the vector data.
+    //*********************************************************************
+    pointer data()
+    {
+      return p_buffer;
+    }
+
+    //*********************************************************************
+    /// Returns a const pointer to the beginning of the vector data.
+    ///\return A const pointer to the beginning of the vector data.
+    //*********************************************************************
+    const_pointer data() const
+    {
+      return p_buffer;
+    }
+
+    //*********************************************************************
+    /// Assigns values to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+    /// If asserts or exceptions are enabled, emits vector_iterator if the iterators are reversed.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*********************************************************************
+    template <typename TIterator>
+    void assign(TIterator first, TIterator last)
+    {
+      STATIC_ASSERT((etl::is_same<typename etl::remove_cv<T>::type, typename etl::remove_cv<typename std::iterator_traits<TIterator>::value_type>::type>::value), "Iterator type does not match container type");
+
+#if defined(ETL_DEBUG)
+      difference_type d = std::distance(first, last);
+      ETL_ASSERT(static_cast<size_t>(d) <= CAPACITY, ETL_ERROR(vector_full));
+#endif
+
+      initialise();
+
+#if defined(ETL_DEBUG)
+      p_end = etl::uninitialized_copy(first, last, p_buffer, construct_count);
+#else
+      p_end = etl::uninitialized_copy(first, last, p_buffer);
+#endif
+    }
+
+    //*********************************************************************
+    /// Assigns values to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+    ///\param n     The number of elements to add.
+    ///\param value The value to insert for each element.
+    //*********************************************************************
+    void assign(size_t n, parameter_t value)
+    {
+      ETL_ASSERT(n <= CAPACITY, ETL_ERROR(vector_full));
+
+      initialise();
+
+#if defined(ETL_DEBUG)
+      p_end = etl::uninitialized_fill_n(p_buffer, n, value, construct_count);
+#else
+      p_end = etl::uninitialized_fill_n(p_buffer, n, value);
+#endif
+    }
+
+    //*************************************************************************
+    /// Clears the vector.
+    //*************************************************************************
+    void clear()
+    {
+      initialise();
+    }
+
+    //*************************************************************************
+    /// Increases the size of the vector by one, but does not initialise the new element.
+    /// If asserts or exceptions are enabled, throws a vector_full if the vector is already full.
+    //*************************************************************************
+    void push_back()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full));
+#endif
+
+      create_back();
+    }
+
+    //*********************************************************************
+    /// Inserts a value at the end of the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+    ///\param value The value to add.
+    //*********************************************************************
+    void push_back(parameter_t value)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full));
+#endif
+      create_back(value);
+    }
+
+    //*********************************************************************
+    /// Constructs a value at the end of the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+    ///\param value The value to add.
+    //*********************************************************************
+    template <typename T1>
+    void emplace_back(const T1& value1)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full));
+#endif
+      ::new (p_end) T(value1);
+      ++p_end;
+      ++construct_count;
+    }
+
+    //*********************************************************************
+    /// Constructs a value at the end of the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+    ///\param value The value to add.
+    //*********************************************************************
+    template <typename T1, typename T2>
+    void emplace_back(const T1& value1, const T2& value2)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full));
+#endif
+      ::new (p_end) T(value1, value2);
+      ++p_end;
+      ++construct_count;
+    }
+
+    //*********************************************************************
+    /// Constructs a value at the end of the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+    ///\param value The value to add.
+    //*********************************************************************
+    template <typename T1, typename T2, typename T3>
+    void emplace_back(const T1& value1, const T2& value2, const T3& value3)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full));
+#endif
+      ::new (p_end) T(value1, value2, value3);
+      ++p_end;
+      ++construct_count;
+    }
+
+    //*********************************************************************
+    /// Constructs a value at the end of the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+    ///\param value The value to add.
+    //*********************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    void emplace_back(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full));
+#endif
+      ::new (p_end) T(value1, value2, value3, value4);
+      ++p_end;
+      ++construct_count;
+    }
+
+    //*************************************************************************
+    /// Removes an element from the end of the vector.
+    /// Does nothing if the vector is empty.
+    //*************************************************************************
+    void pop_back()
+    {
+#if defined(ETL_CHECK_PUSH_POP)
+      ETL_ASSERT(size() > 0, ETL_ERROR(vector_empty));
+#endif
+      destroy_back();
+    }
+
+    //*********************************************************************
+    /// Inserts a value to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector is already full.
+    ///\param position The position to insert before.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    iterator insert(iterator position, parameter_t value)
+    {
+      ETL_ASSERT(size() + 1 <= CAPACITY, ETL_ERROR(vector_full));
+
+      if (position == end())
+      {
+        create_back(value);
+      }
+      else
+      {
+        create_back(back());
+        std::copy_backward(position, p_end - 1, p_end);
+        *position = value;
+      }
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the vextor at the specified position.
+    //*************************************************************************
+    template <typename T1>
+    iterator emplace(iterator position, const T1& value1)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(vector_full));
+
+      void* p;
+
+      if (position == end())
+      {
+        p = p_end++;
+        ++construct_count;
+      }
+      else
+      {
+        p = etl::addressof(*position);
+        create_back(back());
+        std::copy_backward(position, p_end - 1, p_end);
+        (*position).~T();
+      }
+
+      ::new (p) T(value1);
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the vextor at the specified position.
+    //*************************************************************************
+    template <typename T1, typename T2>
+    iterator emplace(iterator position, const T1& value1, const T2& value2)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(vector_full));
+
+      void* p;
+
+      if (position == end())
+      {
+        p = p_end++;
+        ++construct_count;
+      }
+      else
+      {
+        p = etl::addressof(*position);
+        create_back(back());
+        std::copy_backward(position, p_end - 1, p_end);
+        (*position).~T();
+      }
+
+      ::new (p) T(value1, value2);
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the vextor at the specified position.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3>
+    iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(vector_full));
+
+      void* p;
+
+      if (position == end())
+      {
+        p = p_end++;
+        ++construct_count;
+      }
+      else
+      {
+        p = etl::addressof(*position);
+        create_back(back());
+        std::copy_backward(position, p_end - 1, p_end);
+        (*position).~T();
+      }
+
+      ::new (p) T(value1, value2, value3);
+
+      return position;
+    }
+
+    //*************************************************************************
+    /// Emplaces a value to the vextor at the specified position.
+    //*************************************************************************
+    template <typename T1, typename T2, typename T3, typename T4>
+    iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3, const T4& value4)
+    {
+      ETL_ASSERT(!full(), ETL_ERROR(vector_full));
+
+      void* p;
+
+      if (position == end())
+      {
+        p = p_end++;
+        ++construct_count;
+      }
+      else
+      {
+        p = etl::addressof(*position);
+        create_back(back());
+        std::copy_backward(position, p_end - 1, p_end);
+        (*position).~T();
+      }
+
+      ::new (p) T(value1, value2, value3, value4);
+
+      return position;
+    }
+
+    //*********************************************************************
+    /// Inserts 'n' values to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+    ///\param position The position to insert before.
+    ///\param n        The number of elements to add.
+    ///\param value    The value to insert.
+    //*********************************************************************
+    void insert(iterator position, size_t n, parameter_t value)
+    {
+      ETL_ASSERT((size() + n) <= CAPACITY, ETL_ERROR(vector_full));
+
+      size_t insert_n = n;
+      size_t insert_begin = std::distance(begin(), position);
+      size_t insert_end = insert_begin + insert_n;
+
+      // Copy old data.
+      size_t copy_old_n;
+      size_t construct_old_n;
+      iterator p_construct_old;
+
+      if (insert_end > size())
+      {
+        copy_old_n = 0;
+        construct_old_n = size() - insert_begin;
+        p_construct_old = p_buffer + insert_end;
+      }
+      else
+      {
+        copy_old_n = size() - insert_begin - insert_n;
+        construct_old_n = insert_n;
+        p_construct_old = p_end;
+      }
+
+      size_t copy_new_n = construct_old_n;
+      size_t construct_new_n = insert_n - copy_new_n;
+
+#if defined(ETL_DEBUG)
+      // Construct old.
+      etl::uninitialized_copy_n(p_end - construct_old_n, construct_old_n, p_construct_old, construct_count);
+
+      // Copy old.
+      etl::copy_n(p_buffer + insert_begin, copy_old_n, p_buffer + insert_end);
+
+      // Construct new.
+      etl::uninitialized_fill_n(p_end, construct_new_n, value, construct_count);
+
+      // Copy new.
+      std::fill_n(p_buffer + insert_begin, copy_new_n, value);
+#else
+      // Construct old.
+      etl::uninitialized_copy_n(p_end - construct_old_n, construct_old_n, p_construct_old);
+
+      // Copy old.
+      etl::copy_n(p_buffer + insert_begin, copy_old_n, p_buffer + insert_end);
+
+      // Construct new.
+      etl::uninitialized_fill_n(p_end, construct_new_n, value);
+
+      // Copy new.
+      std::fill_n(p_buffer + insert_begin, copy_new_n, value);
+#endif
+
+      p_end += n;
+    }
+
+    //*********************************************************************
+    /// Inserts a range of values to the vector.
+    /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
+    /// For fundamental and pointer types.
+    ///\param position The position to insert before.
+    ///\param first    The first element to add.
+    ///\param last     The last + 1 element to add.
+    //*********************************************************************
+    template <class TIterator>
+    void insert(iterator position, TIterator first, TIterator last)
+    {
+      size_t count = std::distance(first, last);
+
+      ETL_ASSERT((size() + count) <= CAPACITY, ETL_ERROR(vector_full));
+
+      size_t insert_n = count;
+      size_t insert_begin = std::distance(begin(), position);
+      size_t insert_end = insert_begin + insert_n;
+
+      // Copy old data.
+      size_t copy_old_n;
+      size_t construct_old_n;
+      iterator p_construct_old;
+
+      if (insert_end > size())
+      {
+        copy_old_n = 0;
+        construct_old_n = size() - insert_begin;
+        p_construct_old = p_buffer + insert_end;
+      }
+      else
+      {
+        copy_old_n = size() - insert_begin - insert_n;
+        construct_old_n = insert_n;
+        p_construct_old = p_end;
+      }
+
+      size_t copy_new_n = construct_old_n;
+      size_t construct_new_n = insert_n - copy_new_n;
+
+#if defined(ETL_DEBUG)
+      // Construct old.
+      etl::uninitialized_copy_n(p_end - construct_old_n, construct_old_n, p_construct_old, construct_count);
+
+      // Copy old.
+      etl::copy_n(p_buffer + insert_begin, copy_old_n, p_buffer + insert_end);
+
+      // Construct new.
+      etl::uninitialized_copy_n(first + copy_new_n, construct_new_n, p_end, construct_count);
+
+      // Copy new.
+      etl::copy_n(first, copy_new_n, p_buffer + insert_begin);
+#else
+      // Construct old.
+      etl::uninitialized_copy_n(p_end - construct_old_n, construct_old_n, p_construct_old);
+
+      // Copy old.
+      etl::copy_n(p_buffer + insert_begin, copy_old_n, p_buffer + insert_end);
+
+      // Construct new.
+      etl::uninitialized_copy_n(first + copy_new_n, construct_new_n, p_end);
+
+      // Copy new.
+      etl::copy_n(first, copy_new_n, p_buffer + insert_begin);
+#endif
+
+      p_end += count;
+    }
+
+    //*********************************************************************
+    /// Erases an element.
+    ///\param i_element Iterator to the element.
+    ///\return An iterator pointing to the element that followed the erased element.
+    //*********************************************************************
+    iterator erase(iterator i_element)
+    {
+      std::copy(i_element + 1, end(), i_element);
+      destroy_back();
+
+      return i_element;
+    }
+
+    //*********************************************************************
+    /// Erases a range of elements.
+    /// The range includes all the elements between first and last, including the
+    /// element pointed by first, but not the one pointed by last.
+    ///\param first Iterator to the first element.
+    ///\param last  Iterator to the last element.
+    ///\return An iterator pointing to the element that followed the erased element.
+    //*********************************************************************
+    iterator erase(iterator first, iterator last)
+    {
+      if (first == begin() && last == end())
+      {
+        clear();
+      }
+      else
+      {
+        std::copy(last, end(), first);
+        size_t n_delete = std::distance(first, last);
+
+        // Destroy the elements left over at the end.
+#if defined(ETL_DEBUG)
+        etl::destroy(p_end - n_delete, p_end, construct_count);
+#else
+        etl::destroy(p_end - n_delete, p_end);
+#endif
+        p_end -= n_delete;
+      }
+
+      return first;
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    ivector& operator = (const ivector& rhs)
+    {
+      if (&rhs != this)
+      {
+        assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Gets the current size of the vector.
+    ///\return The current size of the vector.
+    //*************************************************************************
+    size_type size() const
+    {
+      return size_t(p_end - p_buffer);
+    }
+
+    //*************************************************************************
+    /// Checks the 'empty' state of the vector.
+    ///\return <b>true</b> if empty.
+    //*************************************************************************
+    bool empty() const
+    {
+      return (p_end == p_buffer);
+    }
+
+    //*************************************************************************
+    /// Checks the 'full' state of the vector.
+    ///\return <b>true</b> if full.
+    //*************************************************************************
+    bool full() const
+    {
+      return size() == CAPACITY;
+    }
+
+    //*************************************************************************
+    /// Returns the remaining capacity.
+    ///\return The remaining capacity.
+    //*************************************************************************
+    size_t available() const
+    {
+      return max_size() - size();
+    }
+
+#ifdef ETL_IVECTOR_REPAIR_ENABLE
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    virtual void repair() = 0;
+#endif
+
+  protected:
+
+    //*********************************************************************
+    /// Constructor.
+    //*********************************************************************
+    ivector(T* p_buffer_, size_t MAX_SIZE)
+      : vector_base(MAX_SIZE),
+      p_buffer(p_buffer_),
+      p_end(p_buffer_)
+    {
+    }
+
+    //*********************************************************************
+    /// Initialise the vector.
+    //*********************************************************************
+    void initialise()
+    {
+#if defined(ETL_DEBUG)
+      etl::destroy(p_buffer, p_end, construct_count);
+#else
+      etl::destroy(p_buffer, p_end);
+#endif
+
+      p_end = p_buffer;
+    }
+
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    void repair(T* p_buffer_)
+    {
+      uintptr_t length = p_end - p_buffer;
+      p_buffer = p_buffer_;
+      p_end    = p_buffer_ + length;
+    }
+
+  private:
+
+    pointer p_buffer; ///< Pointer to the start of the buffer.
+    pointer p_end;    ///< Pointer to one past the last element in the buffer.
+
+    //*********************************************************************
+    /// Create a new element with a default value at the back.
+    //*********************************************************************
+    inline void create_back()
+    {
+#if defined(ETL_DEBUG)
+      etl::create_value_at(p_end, construct_count);
+#else
+      etl::create_value_at(p_end);
+#endif
+      ++p_end;
+    }
+
+    //*********************************************************************
+    /// Create a new element with a value at the back
+    //*********************************************************************
+    inline void create_back(parameter_t value)
+    {
+#if defined(ETL_DEBUG)
+      etl::create_copy_at(p_end, value, construct_count);
+#else
+      etl::create_copy_at(p_end, value);
+#endif
+      ++p_end;
+    }
+
+    //*********************************************************************
+    /// Destroy an element at the back.
+    //*********************************************************************
+    inline void destroy_back()
+    {
+      --p_end;
+
+#if defined(ETL_DEBUG)
+      etl::destroy_at(p_end, construct_count);
+#else
+      etl::destroy_at(p_end);
+#endif
+    }
+
+    // Disable copy construction.
+    ivector(const ivector&);
+  };
+
+  //***************************************************************************
+  /// Equal operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  bool operator ==(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs)
+  {
+    return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+  }
+
+  //***************************************************************************
+  /// Not equal operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  bool operator !=(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs)
+  {
+    return !(lhs == rhs);
+  }
+
+  //***************************************************************************
+  /// Less than operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the first vector is lexicographically less than the second, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  bool operator <(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs)
+  {
+    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+  }
+
+  //***************************************************************************
+  /// Greater than operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the first vector is lexicographically greater than the second, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  bool operator >(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs)
+  {
+    return (rhs < lhs);
+  }
+
+  //***************************************************************************
+  /// Less than or equal operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the first vector is lexicographically less than or equal to the second, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  bool operator <=(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs)
+  {
+    return !(lhs > rhs);
+  }
+
+  //***************************************************************************
+  /// Greater than or equal operator.
+  ///\param lhs Reference to the first vector.
+  ///\param rhs Reference to the second vector.
+  ///\return <b>true</b> if the first vector is lexicographically greater than or equal to the second, otherwise <b>false</b>
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T>
+  bool operator >=(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs)
+  {
+    return !(lhs < rhs);
+  }
+
+  //***************************************************************************
+  /// A vector implementation that uses a fixed size buffer.
+  ///\tparam T The element type.
+  ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T, const size_t MAX_SIZE_>
+  class vector : public etl::ivector<T>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    vector()
+      : etl::ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+    {
+      etl::ivector<T>::initialise();
+    }
+
+    //*************************************************************************
+    /// Constructor, with size.
+    ///\param initial_size The initial size of the vector.
+    //*************************************************************************
+    explicit vector(size_t initial_size)
+      : etl::ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+    {
+      etl::ivector<T>::initialise();
+      etl::ivector<T>::resize(initial_size);
+    }
+
+    //*************************************************************************
+    /// Constructor, from initial size and value.
+    ///\param initial_size  The initial size of the vector.
+    ///\param value        The value to fill the vector with.
+    //*************************************************************************
+    vector(size_t initial_size, typename etl::ivector<T>::parameter_t value)
+      : etl::ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+    {
+      etl::ivector<T>::initialise();
+      etl::ivector<T>::resize(initial_size, value);
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    vector(TIterator first, TIterator last)
+      : etl::ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+    {
+      etl::ivector<T>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    vector(const vector& other)
+      : etl::ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE)
+    {
+      etl::ivector<T>::assign(other.begin(), other.end());
+    }
+
+    //*************************************************************************
+    /// Destructor.
+    //*************************************************************************
+    ~vector()
+    {
+      etl::ivector<T>::clear();
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    vector& operator = (const vector& rhs)
+    {
+      if (&rhs != this)
+      {
+        etl::ivector<T>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    void repair()
+    {
+      #if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED
+      ETL_ASSERT(std::is_trivially_copyable<T>::value, ETL_ERROR(etl::vector_incompatible_type));
+      #endif
+
+      etl::ivector<T>::repair(buffer);
+    }
+
+  private:
+
+    typename etl::aligned_storage<sizeof(T) * MAX_SIZE, etl::alignment_of<T>::value>::type buffer;
+  };
+
+  //***************************************************************************
+  /// A vector implementation that uses a fixed size buffer.
+  ///\tparam T The element type.
+  ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+  ///\ingroup vector
+  //***************************************************************************
+  template <typename T, const size_t MAX_SIZE_>
+  class vector<T*, MAX_SIZE_> : public etl::ivector<T*>
+  {
+  public:
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    vector()
+      : etl::ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE)
+    {
+      etl::ivector<T*>::initialise();
+    }
+
+    //*************************************************************************
+    /// Constructor, with size.
+    ///\param initial_size The initial size of the vector.
+    //*************************************************************************
+    explicit vector(size_t initial_size)
+      : etl::ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE)
+    {
+      etl::ivector<T*>::initialise();
+      etl::ivector<T*>::resize(initial_size);
+    }
+
+    //*************************************************************************
+    /// Constructor, from initial size and value.
+    ///\param initial_size  The initial size of the vector.
+    ///\param value        The value to fill the vector with.
+    //*************************************************************************
+    vector(size_t initial_size, typename etl::ivector<T*>::parameter_t value)
+      : etl::ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE)
+    {
+      etl::ivector<T*>::initialise();
+      etl::ivector<T*>::resize(initial_size, value);
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    vector(TIterator first, TIterator last)
+      : etl::ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE)
+    {
+      etl::ivector<T*>::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    //*************************************************************************
+    vector(const vector& other)
+      : etl::ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE)
+    {
+      etl::ivector<T*>::assign(other.begin(), other.end());
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    vector& operator = (const vector& rhs)
+    {
+      if (&rhs != this)
+      {
+        etl::ivector<T*>::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    void repair()
+    {
+      etl::ivector<T*>::repair(buffer);
+    }
+
+  private:
+
+    typename etl::aligned_storage<sizeof(T*) * MAX_SIZE, etl::alignment_of<T*>::value>::type buffer;
+  };
+}
+
+#include "private/ivectorpointer.h"
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visitor.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,465 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2014 jwellbelove
+
+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 __ETL_VISITOR__
+#define __ETL_VISITOR__
+
+#include "platform.h"
+
+//*****************************************************************************
+///\defgroup visitor visitor
+/// A set of template classes for easy implementation of the visitor pattern.<br>
+/// The visitor design pattern is a way of separating an algorithm from an object
+/// structure on which it operates. A practical result of this separation is the
+/// ability to add new operations to existing object structures without modifying
+/// those structures. It is one way to easily follow the open/closed principle.
+/// In essence, the visitor allows one to add new virtual functions to a family 
+/// of classes without modifying the classes themselves; instead, one creates a 
+/// visitor class that implements all of the appropriate specialisations of the
+/// virtual function. The visitor takes the instance as input, and implements 
+/// the goal through double dispatch.<br>
+/// \ingroup patterns
+//*****************************************************************************
+
+namespace etl
+{
+  //*****************************************************************
+  /// The visitable base class for four visitor types.
+  /// Derive visitable classes from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void>
+  class visitable
+  {
+  public:
+
+    virtual void accept(T1&) = 0;
+    virtual void accept(T2&) = 0;
+    virtual void accept(T3&) = 0;
+    virtual void accept(T4&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitable base class for three visitor types.
+  /// Derive visitable classes from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2, typename T3>
+  class visitable<T1, T2, T3>
+  {
+  public:
+
+    virtual void accept(T1&) = 0;
+    virtual void accept(T2&) = 0;
+    virtual void accept(T3&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitable base class for two visitor types.
+  /// Derive visitable classes from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2>
+  class visitable<T1, T2>
+  {
+  public:
+
+    virtual void accept(T1&) = 0;
+    virtual void accept(T2&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitable base class for one visitor type.
+  /// Derive visitable classes from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1>
+  class visitable<T1>
+  {
+  public:
+
+    virtual void accept(T1&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for sixteen types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1,         typename T2  = void, typename T3  = void, typename T4  = void,
+            typename T5  = void, typename T6  = void, typename T7  = void, typename T8  = void,
+            typename T9  = void, typename T10 = void, typename T11 = void, typename T12 = void, 
+            typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
+  class visitor
+  {
+  public:
+
+    virtual void visit(T1&) = 0;
+    virtual void visit(T2&) = 0;
+    virtual void visit(T3&) = 0;
+    virtual void visit(T4&) = 0;
+    virtual void visit(T5&) = 0;
+    virtual void visit(T6&) = 0;
+    virtual void visit(T7&) = 0;
+    virtual void visit(T8&) = 0;
+    virtual void visit(T9&) = 0;
+    virtual void visit(T10&) = 0;
+    virtual void visit(T11&) = 0;
+    virtual void visit(T12&) = 0;
+    virtual void visit(T13&) = 0;
+    virtual void visit(T14&) = 0;
+    virtual void visit(T15&) = 0;
+    virtual void visit(T16&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for fifteen types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1,  typename T2,  typename T3,  typename T4,
+            typename T5,  typename T6,  typename T7,  typename T8,
+            typename T9,  typename T10, typename T11, typename T12,
+            typename T13, typename T14, typename T15>
+  class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>
+  {
+  public:
+
+    virtual void visit(T1&) = 0;
+    virtual void visit(T2&) = 0;
+    virtual void visit(T3&) = 0;
+    virtual void visit(T4&) = 0;
+    virtual void visit(T5&) = 0;
+    virtual void visit(T6&) = 0;
+    virtual void visit(T7&) = 0;
+    virtual void visit(T8&) = 0;
+    virtual void visit(T9&) = 0;
+    virtual void visit(T10&) = 0;
+    virtual void visit(T11&) = 0;
+    virtual void visit(T12&) = 0;
+    virtual void visit(T13&) = 0;
+    virtual void visit(T14&) = 0;
+    virtual void visit(T15&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for fourteen types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1,  typename T2,  typename T3,  typename T4,
+            typename T5,  typename T6,  typename T7,  typename T8,
+            typename T9,  typename T10, typename T11, typename T12,
+            typename T13, typename T14>
+  class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>
+  {
+  public:
+
+    virtual void visit(T1&) = 0;
+    virtual void visit(T2&) = 0;
+    virtual void visit(T3&) = 0;
+    virtual void visit(T4&) = 0;
+    virtual void visit(T5&) = 0;
+    virtual void visit(T6&) = 0;
+    virtual void visit(T7&) = 0;
+    virtual void visit(T8&) = 0;
+    virtual void visit(T9&) = 0;
+    virtual void visit(T10&) = 0;
+    virtual void visit(T11&) = 0;
+    virtual void visit(T12&) = 0;
+    virtual void visit(T13&) = 0;
+    virtual void visit(T14&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for thirteen types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2,  typename T3,  typename T4,
+            typename T5, typename T6,  typename T7,  typename T8,
+            typename T9, typename T10, typename T11, typename T12,
+            typename T13>
+  class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>
+  {
+  public:
+
+    virtual void visit(T1&) = 0;
+    virtual void visit(T2&) = 0;
+    virtual void visit(T3&) = 0;
+    virtual void visit(T4&) = 0;
+    virtual void visit(T5&) = 0;
+    virtual void visit(T6&) = 0;
+    virtual void visit(T7&) = 0;
+    virtual void visit(T8&) = 0;
+    virtual void visit(T9&) = 0;
+    virtual void visit(T10&) = 0;
+    virtual void visit(T11&) = 0;
+    virtual void visit(T12&) = 0;
+    virtual void visit(T13&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for twelve types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2,  typename T3,  typename T4,
+            typename T5, typename T6,  typename T7,  typename T8,
+            typename T9, typename T10, typename T11, typename T12>
+  class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>
+  {
+  public:
+
+    virtual void visit(T1&) = 0;
+    virtual void visit(T2&) = 0;
+    virtual void visit(T3&) = 0;
+    virtual void visit(T4&) = 0;
+    virtual void visit(T5&) = 0;
+    virtual void visit(T6&) = 0;
+    virtual void visit(T7&) = 0;
+    virtual void visit(T8&) = 0;
+    virtual void visit(T9&) = 0;
+    virtual void visit(T10&) = 0;
+    virtual void visit(T11&) = 0;
+    virtual void visit(T12&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for eleven types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2,  typename T3, typename T4,
+            typename T5, typename T6,  typename T7, typename T8,
+            typename T9, typename T10, typename T11>
+  class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>
+  {
+  public:
+
+    virtual void visit(T1&) = 0;
+    virtual void visit(T2&) = 0;
+    virtual void visit(T3&) = 0;
+    virtual void visit(T4&) = 0;
+    virtual void visit(T5&) = 0;
+    virtual void visit(T6&) = 0;
+    virtual void visit(T7&) = 0;
+    virtual void visit(T8&) = 0;
+    virtual void visit(T9&) = 0;
+    virtual void visit(T10&) = 0;
+    virtual void visit(T11&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for ten types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2, typename T3, typename T4,
+            typename T5, typename T6, typename T7, typename T8,
+            typename T9, typename T10>
+  class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
+  {
+  public:
+
+    virtual void visit(T1&) = 0;
+    virtual void visit(T2&) = 0;
+    virtual void visit(T3&) = 0;
+    virtual void visit(T4&) = 0;
+    virtual void visit(T5&) = 0;
+    virtual void visit(T6&) = 0;
+    virtual void visit(T7&) = 0;
+    virtual void visit(T8&) = 0;
+    virtual void visit(T9&) = 0;
+    virtual void visit(T10&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for nine types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2, typename T3, typename T4,
+            typename T5, typename T6, typename T7, typename T8,
+            typename T9>
+  class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9>
+  {
+  public:
+
+    virtual void visit(T1&) = 0;
+    virtual void visit(T2&) = 0;
+    virtual void visit(T3&) = 0;
+    virtual void visit(T4&) = 0;
+    virtual void visit(T5&) = 0;
+    virtual void visit(T6&) = 0;
+    virtual void visit(T7&) = 0;
+    virtual void visit(T8&) = 0;
+    virtual void visit(T9&) = 0;
+  };
+  
+  //*****************************************************************
+  /// The visitor base class for eight types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2, typename T3, typename T4,
+            typename T5, typename T6, typename T7, typename T8>
+  class visitor<T1, T2, T3, T4, T5, T6, T7, T8>
+  {
+  public:
+
+    virtual void visit(T1&) = 0;
+    virtual void visit(T2&) = 0;
+    virtual void visit(T3&) = 0;
+    virtual void visit(T4&) = 0;
+    virtual void visit(T5&) = 0;
+    virtual void visit(T6&) = 0;
+    virtual void visit(T7&) = 0;
+    virtual void visit(T8&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for seven types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2, typename T3, typename T4,
+            typename T5, typename T6, typename T7>
+  class visitor<T1, T2, T3, T4, T5, T6, T7>
+  {
+  public:
+
+      virtual void visit(T1&) = 0;
+      virtual void visit(T2&) = 0;
+      virtual void visit(T3&) = 0;
+      virtual void visit(T4&) = 0;
+      virtual void visit(T5&) = 0;
+      virtual void visit(T6&) = 0;
+      virtual void visit(T7&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for six types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2, typename T3, typename T4,
+            typename T5, typename T6>
+  class visitor<T1, T2, T3, T4, T5, T6>
+  {
+  public:
+
+      virtual void visit(T1&) = 0;
+      virtual void visit(T2&) = 0;
+      virtual void visit(T3&) = 0;
+      virtual void visit(T4&) = 0;
+      virtual void visit(T5&) = 0;
+      virtual void visit(T6&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for five types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2, typename T3, typename T4,
+            typename T5>
+  class visitor<T1, T2, T3, T4, T5>
+  {
+  public:
+
+      virtual void visit(T1&) = 0;
+      virtual void visit(T2&) = 0;
+      virtual void visit(T3&) = 0;
+      virtual void visit(T4&) = 0;
+      virtual void visit(T5&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for four types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2, typename T3, typename T4>
+  class visitor<T1, T2, T3, T4>
+  {
+  public:
+
+      virtual void visit(T1&) = 0;
+      virtual void visit(T2&) = 0;
+      virtual void visit(T3&) = 0;
+      virtual void visit(T4&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for three types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2, typename T3>
+  class visitor<T1, T2, T3>
+  {
+  public:
+
+      virtual void visit(T1&) = 0;
+      virtual void visit(T2&) = 0;
+      virtual void visit(T3&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for two types.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1, typename T2>
+  class visitor<T1, T2>
+  {
+  public:
+
+      virtual void visit(T1&) = 0;
+      virtual void visit(T2&) = 0;
+  };
+
+  //*****************************************************************
+  /// The visitor base class for one type.
+  /// Derive visitors from this.
+  ///\ingroup visitor
+  //*****************************************************************
+  template <typename T1>
+  class visitor<T1>
+  {
+  public:
+
+      virtual void visit(T1&) = 0;
+  };
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wstring.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,225 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2016 jwellbelove
+
+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 __ETL_WSTRING__
+#define __ETL_WSTRING__
+
+#include "platform.h"
+#include "basic_string.h"
+#include "hash.h"
+
+#if defined(ETL_COMPILER_MICROSOFT)
+  #undef min
+#endif
+
+namespace etl
+{
+  typedef ibasic_string<wchar_t> iwstring;
+
+  //***************************************************************************
+  /// A wstring implementation that uses a fixed size buffer.
+  ///\tparam MAX_SIZE_ The maximum number of elements that can be stored.
+  ///\ingroup wstring
+  //***************************************************************************
+  template <const size_t MAX_SIZE_>
+  class wstring : public iwstring
+  {
+  public:
+
+    typedef iwstring::value_type value_type;
+
+    static const size_t MAX_SIZE = MAX_SIZE_;
+
+    //*************************************************************************
+    /// Constructor.
+    //*************************************************************************
+    wstring()
+      : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iwstring::initialise();
+    }
+
+    //*************************************************************************
+    /// Copy constructor.
+    ///\param other The other string.
+    //*************************************************************************
+    wstring(const etl::wstring<MAX_SIZE_>& other)
+      : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      wstring::initialise();
+      wstring::assign(other.begin(), other.end());
+    }
+
+
+    //*************************************************************************
+    /// From other string, position, length.
+    ///\param other The other string.
+    ///\param position The position of the first character.
+    ///\param length   The number of characters. Default = npos.
+    //*************************************************************************
+    wstring(const etl::wstring<MAX_SIZE_>& other, size_t position, size_t length_ = npos)
+      : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds));
+
+      // Set the length to the exact amount.
+      length_ = (length_ > MAX_SIZE_) ? MAX_SIZE_ : length_;
+
+      iwstring::initialise();
+      iwstring::assign(other.begin() + position, other.begin() + position + length_);
+    }
+
+    //*************************************************************************
+    /// Constructor, from null terminated text.
+    ///\param text The initial text of the wstring.
+    //*************************************************************************
+    wstring(const value_type* text)
+      : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iwstring::initialise();
+      iwstring::assign(text, text + etl::char_traits<value_type>::length(text));
+    }
+
+    //*************************************************************************
+    /// Constructor, from null terminated text and count.
+    ///\param text  The initial text of the wstring.
+    ///\param count The number of characters to copy.
+    //*************************************************************************
+    wstring(const value_type* text, size_t count)
+      : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iwstring::initialise();
+      iwstring::assign(text, text + count);
+    }
+
+    //*************************************************************************
+    /// Constructor, from initial size and value.
+    ///\param initialSize  The initial size of the wstring.
+    ///\param value        The value to fill the wstring with.
+    //*************************************************************************
+    wstring(size_t count, value_type c)
+      : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iwstring::initialise();
+      iwstring::resize(count, c);
+    }
+
+    //*************************************************************************
+    /// Constructor, from an iterator range.
+    ///\tparam TIterator The iterator type.
+    ///\param first The iterator to the first element.
+    ///\param last  The iterator to the last element + 1.
+    //*************************************************************************
+    template <typename TIterator>
+    wstring(TIterator first, TIterator last)
+      : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE)
+    {
+      iwstring::assign(first, last);
+    }
+
+    //*************************************************************************
+    /// Returns a sub-string.
+    ///\param position The position of the first character. Default = 0.
+    ///\param length   The number of characters. Default = npos.
+    //*************************************************************************
+    etl::wstring<MAX_SIZE_> substr(size_t position = 0, size_t length_ = npos) const
+    {
+      etl::wstring<MAX_SIZE_> new_string;
+
+      if (position != size())
+      {
+        ETL_ASSERT(position < size(), ETL_ERROR(string_out_of_bounds));
+
+        length_ = std::min(length_, size() - position);
+
+        new_string.assign(buffer + position, buffer + position + length_);
+      }
+
+      return new_string;
+    }
+
+    //*************************************************************************
+    /// Assignment operator.
+    //*************************************************************************
+    wstring& operator = (const wstring& rhs)
+    {
+      if (&rhs != this)
+      {
+        iwstring::assign(rhs.cbegin(), rhs.cend());
+      }
+
+      return *this;
+    }
+
+    //*************************************************************************
+    /// Fix the internal pointers after a low level memory copy.
+    //*************************************************************************
+    void repair()
+    {
+      etl::iwstring::repair(buffer);
+    }
+
+  private:
+
+    value_type buffer[MAX_SIZE + 1];
+  };
+
+  //*************************************************************************
+  /// Hash function.
+  //*************************************************************************
+#if ETL_8BIT_SUPPORT
+  template <>
+  struct hash<etl::iwstring>
+  {
+    size_t operator()(const etl::iwstring& text) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]),
+                                                         reinterpret_cast<const uint8_t*>(&text[text.size()]));
+    }
+  };
+
+  template <const size_t SIZE>
+  struct hash<etl::wstring<SIZE> >
+  {
+    size_t operator()(const etl::wstring<SIZE>& text) const
+    {
+      return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]),
+                                                         reinterpret_cast<const uint8_t*>(&text[text.size()]));
+    }
+  };
+#endif
+}
+
+#if defined(ETL_COMPILER_MICROSOFT)
+  #define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#endif
+