diff --git a/include/utl/container/array.h b/include/utl/container/array.h
new file mode 100644
index 0000000..55513b5
--- /dev/null
+++ b/include/utl/container/array.h
@@ -0,0 +1,240 @@
+/*!
+ * \file utl/containers/array.h
+ * \brief An std::array equivalent implementation
+ *
+ * Copyright (C) 2018 Christos Choutouridis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ */
+#ifndef __utl_container_array_h__
+#define __utl_container_array_h__
+
+#include
+#include
+
+namespace utl {
+
+ /*!
+ * \ingroup containers
+ * \brief
+ * array container traits helper
+ */
+ //! @{
+ template
+ struct array_traits {
+ typedef _Tp type[_Nm];
+
+ static constexpr _Tp& Ref (const type& t, size_t n) noexcept {
+ return const_cast<_Tp&>(t[n]);
+ }
+
+ static constexpr _Tp* Ptr(const type& t) noexcept {
+ return const_cast<_Tp*>(t);
+ }
+ };
+
+ template
+ struct array_traits<_Tp, 0> {
+ struct type { };
+
+ static constexpr _Tp& Ref(const type&, size_t) noexcept {
+ return *static_cast<_Tp*>(nullptr);
+ }
+
+ static constexpr _Tp* Ptr(const type&) noexcept {
+ return nullptr;
+ }
+ };
+ //! @}
+
+ /*!
+ * \ingroup containers
+ * \brief
+ * A standard container for storing a fixed size sequence of elements.
+ *
+ * Meets the requirements of:
+ * container,
+ * reversible container,
+ * sequence.
+ * Sets support random access iterators.
+ *
+ * \tparam _Tp type of element. Required to be a complete type.
+ * \tparam _Nm Number of elements.
+ */
+ template
+ struct array {
+ using value_type = _Tp;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using iterator = value_type*;
+ using const_iterator = const value_type*;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using reverse_iterator = std::reverse_iterator ;
+ using const_reverse_iterator
+ = std::reverse_iterator ;
+
+ // type and data
+ //using empty_t = array_traits<_Tp, 0>;
+ using array_t = array_traits<_Tp, _Nm>;
+ typename array_t::type _data;
+
+ // No explicit construct/copy/destroy for aggregate type.
+
+ // DR 776.
+ void fill (const value_type& v) { std::fill_n (begin(), size(), v); }
+
+ void swap (array& other) noexcept {
+ std::swap_ranges (begin(), end(), other.begin());
+ }
+
+ //! \name Iterators.
+ //!@{
+ iterator begin() noexcept { return iterator (data()); }
+ const_iterator begin() const noexcept { return const_iterator (data()); }
+ iterator end() noexcept { return iterator (data() + _Nm); }
+ const_iterator end() const noexcept { return const_iterator (data() + _Nm); }
+ const_iterator cbegin() const noexcept { return const_iterator (data()); }
+ const_iterator cend() const noexcept { return const_iterator (data() + _Nm); }
+
+ reverse_iterator rbegin() noexcept { return reverse_iterator (end()); }
+ reverse_iterator rend() noexcept { return reverse_iterator (begin()); }
+ const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator (end()); }
+ const_reverse_iterator rend() const noexcept { return const_reverse_iterator (begin()); }
+ const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator (end()); }
+ const_reverse_iterator crend() const noexcept { return const_reverse_iterator (begin()); }
+ //!@{
+ //! \name Capacity.
+ //!@{
+ constexpr size_type size() const noexcept { return _Nm; }
+ constexpr size_type max_size() const noexcept { return _Nm; }
+ constexpr bool empty() const noexcept { return size() == 0; }
+ //!@{
+
+ //! \name Element access.
+ //!@{
+
+ //! Operator []
+ reference operator[] (size_type n) noexcept {
+ return array_t::Ref(_data, n);
+ }
+ //! Operator [] for const
+ constexpr const_reference operator[](size_type n) const noexcept {
+ return array_t::Ref(_data, n);
+ }
+
+ /*!
+ * Boundary check dereference operator.
+ * If out of bounds, abort (for now)
+ */
+ reference at (size_type n) noexcept {
+ if (n < _Nm)
+ return array_t::Ref(_data, n);
+ else
+ abort (); //XXX: Throw here
+ }
+ //! Compile time boundary check dereference operator.
+ constexpr const_reference at (size_type n) const noexcept {
+ static_assert ((n < _Nm), "array::at: out of range");
+ return array_t::Ref(_data, n);
+ }
+ // first item
+ reference front () noexcept {
+ return *begin ();
+ }
+ constexpr const_reference front() const noexcept {
+ return array_t::Ref(_data, 0);
+ }
+
+ // Last item
+ reference back () noexcept {
+ return _Nm ? *(end() - 1) : *end();
+ }
+ constexpr const_reference back () const noexcept {
+ return _Nm ? array_t::Ref(_data, _Nm - 1)
+ : array_t::Ref(_data, 0);
+ }
+
+ // Pointer to data
+ pointer data () noexcept { return array_t::Ptr(_data); }
+ const_pointer data () const noexcept { return array_t::Ptr(_data); }
+ //!<@}
+ };
+
+ //! \name Array comparisons.
+ //!@{
+ template
+ inline bool operator== (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
+ return std::equal (lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ template
+ inline bool operator!= (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
+ return !(lhs == rhs);
+ }
+
+ template
+ inline bool operator< (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
+ return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+ }
+
+ template
+ inline bool operator> (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
+ return rhs < lhs;
+ }
+
+ template
+ inline bool operator<= (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
+ return !(lhs > rhs);
+ }
+
+ template
+ inline bool
+ operator>= (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
+ return !(lhs < rhs);
+ }
+ //!@}
+
+ // Specialized algorithms.
+ template
+ inline void swap (array<_Tp, _Nm>& lhs, array<_Tp, _Nm>& rhs)
+ noexcept (noexcept (lhs.swap(rhs))) {
+ lhs.swap (rhs);
+ }
+
+ template
+ constexpr _Tp& get (array<_Tp, _Nm>& arr) noexcept {
+ static_assert(_Int < _Nm, "Index is out of bounds");
+ return array_traits<_Tp, _Nm>::Ref(arr._data, _Int);
+ }
+
+ template
+ constexpr _Tp&& get (array<_Tp, _Nm>&& arr) noexcept {
+ static_assert(_Int < _Nm, "Index is out of bounds");
+ return std::move(std::get<_Int>(arr));
+ }
+
+ template
+ constexpr const _Tp& get (const array<_Tp, _Nm>& arr) noexcept {
+ static_assert(_Int < _Nm, "Index is out of bounds");
+ return array_traits<_Tp, _Nm>::Ref(arr._data, _Int);
+ }
+
+} // namespace utl
+
+
+#endif /* __utl_continer_array_h__ */