diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 2b416081..04a7cc1c 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -41,16 +41,10 @@ There are currently two files which need to be edited:
 
 2. [`test/src/unit.cpp`](https://github.com/nlohmann/json/blob/master/test/unit.cpp) - This contains the [Catch](https://github.com/philsquared/Catch) unit tests which currently cover [100 %](https://coveralls.io/github/nlohmann/json) of the library's code.
 
-   If you add or change a feature, please also add a unit test to this file. The unit tests can be compiled with
+   If you add or change a feature, please also add a unit test to this file. The unit tests can be compiled and executed with
 
    ```sh
-   make
-   ```
-
-   and can be executed with
-
-   ```sh
-   ./json_unit
+   make check
    ```
 
    The test cases are also executed with several different compilers on [Travis](https://travis-ci.org/nlohmann/json) once you open a pull request.
diff --git a/README.md b/README.md
index bf127638..5b0c9652 100644
--- a/README.md
+++ b/README.md
@@ -492,6 +492,8 @@ I deeply appreciate the help of the following people.
 - [Mário Feroldi](https://github.com/thelostt) fixed a small typo.
 - [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release.
 - [Damien](https://github.com/dtoma) fixed one of the last conversion warnings.
+- [Thomas Braun](https://github.com/t-b) fixed a warning in a test case.
+- [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290).
 
 Thanks a lot for helping out!
 
@@ -510,7 +512,7 @@ To compile and run the tests, you need to execute
 $ make check
 
 ===============================================================================
-All tests passed (8905099 assertions in 32 test cases)
+All tests passed (8905154 assertions in 35 test cases)
 ```
 
 For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).
diff --git a/doc/examples/parse__array__parser_callback_t.cpp b/doc/examples/parse__array__parser_callback_t.cpp
new file mode 100644
index 00000000..8e086d20
--- /dev/null
+++ b/doc/examples/parse__array__parser_callback_t.cpp
@@ -0,0 +1,28 @@
+#include <json.hpp>
+
+using json = nlohmann::json;
+
+int main()
+{
+    // a JSON text
+    char text[] = R"(
+    {
+        "Image": {
+            "Width":  800,
+            "Height": 600,
+            "Title":  "View from 15th Floor",
+            "Thumbnail": {
+                "Url":    "http://www.example.com/image/481989943",
+                "Height": 125,
+                "Width":  100
+            },
+            "Animated" : false,
+            "IDs": [116, 943, 234, 38793]
+        }
+    }
+    )";
+
+    // parse and serialize JSON
+    json j_complete = json::parse(text);
+    std::cout << std::setw(4) << j_complete << "\n\n";
+}
diff --git a/doc/examples/parse__array__parser_callback_t.link b/doc/examples/parse__array__parser_callback_t.link
new file mode 100644
index 00000000..3389916f
--- /dev/null
+++ b/doc/examples/parse__array__parser_callback_t.link
@@ -0,0 +1 @@
+<a target="_blank" href="http://melpon.org/wandbox/permlink/CwZnqGqte14SYJ5s"><b>online</b></a>
\ No newline at end of file
diff --git a/doc/examples/parse__array__parser_callback_t.output b/doc/examples/parse__array__parser_callback_t.output
new file mode 100644
index 00000000..62bb8586
--- /dev/null
+++ b/doc/examples/parse__array__parser_callback_t.output
@@ -0,0 +1,20 @@
+{
+    "Image": {
+        "Animated": false,
+        "Height": 600,
+        "IDs": [
+            116,
+            943,
+            234,
+            38793
+        ],
+        "Thumbnail": {
+            "Height": 125,
+            "Url": "http://www.example.com/image/481989943",
+            "Width": 100
+        },
+        "Title": "View from 15th Floor",
+        "Width": 800
+    }
+}
+
diff --git a/doc/examples/parse__contiguouscontainer__parser_callback_t.cpp b/doc/examples/parse__contiguouscontainer__parser_callback_t.cpp
new file mode 100644
index 00000000..5a339079
--- /dev/null
+++ b/doc/examples/parse__contiguouscontainer__parser_callback_t.cpp
@@ -0,0 +1,13 @@
+#include <json.hpp>
+
+using json = nlohmann::json;
+
+int main()
+{
+    // a JSON text given as std::vector
+    std::vector<uint8_t> text = {'[', '1', ',', '2', ',', '3', ']', '\0'};
+
+    // parse and serialize JSON
+    json j_complete = json::parse(text);
+    std::cout << std::setw(4) << j_complete << "\n\n";
+}
diff --git a/doc/examples/parse__contiguouscontainer__parser_callback_t.link b/doc/examples/parse__contiguouscontainer__parser_callback_t.link
new file mode 100644
index 00000000..57d6dc3a
--- /dev/null
+++ b/doc/examples/parse__contiguouscontainer__parser_callback_t.link
@@ -0,0 +1 @@
+<a target="_blank" href="http://melpon.org/wandbox/permlink/F8VaVFyys87qQRt5"><b>online</b></a>
\ No newline at end of file
diff --git a/doc/examples/parse__contiguouscontainer__parser_callback_t.output b/doc/examples/parse__contiguouscontainer__parser_callback_t.output
new file mode 100644
index 00000000..74633e80
--- /dev/null
+++ b/doc/examples/parse__contiguouscontainer__parser_callback_t.output
@@ -0,0 +1,6 @@
+[
+    1,
+    2,
+    3
+]
+
diff --git a/doc/examples/parse__iteratortype__parser_callback_t.cpp b/doc/examples/parse__iteratortype__parser_callback_t.cpp
new file mode 100644
index 00000000..3f723c5f
--- /dev/null
+++ b/doc/examples/parse__iteratortype__parser_callback_t.cpp
@@ -0,0 +1,13 @@
+#include <json.hpp>
+
+using json = nlohmann::json;
+
+int main()
+{
+    // a JSON text given as std::vector
+    std::vector<uint8_t> text = {'[', '1', ',', '2', ',', '3', ']', '\0'};
+
+    // parse and serialize JSON
+    json j_complete = json::parse(text.begin(), text.end());
+    std::cout << std::setw(4) << j_complete << "\n\n";
+}
diff --git a/doc/examples/parse__iteratortype__parser_callback_t.link b/doc/examples/parse__iteratortype__parser_callback_t.link
new file mode 100644
index 00000000..63f58fe6
--- /dev/null
+++ b/doc/examples/parse__iteratortype__parser_callback_t.link
@@ -0,0 +1 @@
+<a target="_blank" href="http://melpon.org/wandbox/permlink/ojh4Eeol4G9RgeRV"><b>online</b></a>
\ No newline at end of file
diff --git a/doc/examples/parse__iteratortype__parser_callback_t.output b/doc/examples/parse__iteratortype__parser_callback_t.output
new file mode 100644
index 00000000..74633e80
--- /dev/null
+++ b/doc/examples/parse__iteratortype__parser_callback_t.output
@@ -0,0 +1,6 @@
+[
+    1,
+    2,
+    3
+]
+
diff --git a/doc/examples/parse__string__parser_callback_t.cpp b/doc/examples/parse__string__parser_callback_t.cpp
index 62982ca6..0a4f3b53 100644
--- a/doc/examples/parse__string__parser_callback_t.cpp
+++ b/doc/examples/parse__string__parser_callback_t.cpp
@@ -5,7 +5,7 @@ using json = nlohmann::json;
 int main()
 {
     // a JSON text
-    std::string text = R"(
+    auto text = R"(
     {
         "Image": {
             "Width":  800,
@@ -44,4 +44,4 @@ int main()
     // parse (with callback) and serialize JSON
     json j_filtered = json::parse(text, cb);
     std::cout << std::setw(4) << j_filtered << '\n';
-}
\ No newline at end of file
+}
diff --git a/doc/examples/parse__string__parser_callback_t.link b/doc/examples/parse__string__parser_callback_t.link
index 1ad3b719..292046b6 100644
--- a/doc/examples/parse__string__parser_callback_t.link
+++ b/doc/examples/parse__string__parser_callback_t.link
@@ -1 +1 @@
-<a target="_blank" href="http://melpon.org/wandbox/permlink/SrKpkE9ivmvd2OUy"><b>online</b></a>
\ No newline at end of file
+<a target="_blank" href="http://melpon.org/wandbox/permlink/n888UNQlMFduURhE"><b>online</b></a>
\ No newline at end of file
diff --git a/src/json.hpp b/src/json.hpp
index d755f712..1a07e46c 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -37,6 +37,7 @@ SOFTWARE.
 #include <cstddef>
 #include <cstdint>
 #include <cstdlib>
+#include <cstring>
 #include <functional>
 #include <initializer_list>
 #include <iomanip>
@@ -959,7 +960,7 @@ class basic_json
 
     With a parser callback function, the result of parsing a JSON text can be
     influenced. When passed to @ref parse(std::istream&, const
-    parser_callback_t) or @ref parse(const string_t&, const parser_callback_t),
+    parser_callback_t) or @ref parse(const char*, const parser_callback_t),
     it is called on certain events (passed as @ref parse_event_t via parameter
     @a event) with a set recursion depth @a depth and context JSON value
     @a parsed. The return value of the callback function is a boolean
@@ -1002,7 +1003,7 @@ class basic_json
     skipped completely or replaced by an empty discarded object.
 
     @sa @ref parse(std::istream&, parser_callback_t) or
-    @ref parse(const string_t&, parser_callback_t) for examples
+    @ref parse(const char*, parser_callback_t) for examples
 
     @since version 1.0.0
     */
@@ -1140,11 +1141,9 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class CompatibleObjectType, typename
-              std::enable_if<
-                  std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
-                  std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type
-              = 0>
+    template<class CompatibleObjectType, typename std::enable_if<
+                 std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
+                 std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type = 0>
     basic_json(const CompatibleObjectType& val)
         : m_type(value_t::object)
     {
@@ -1205,16 +1204,14 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class CompatibleArrayType, typename
-              std::enable_if<
-                  not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
-                  not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
-                  not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
-                  not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
-                  not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
-                  not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
-                  std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type
-              = 0>
+    template<class CompatibleArrayType, typename std::enable_if<
+                 not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
+                 std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type = 0>
     basic_json(const CompatibleArrayType& val)
         : m_type(value_t::array)
     {
@@ -1300,10 +1297,8 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class CompatibleStringType, typename
-              std::enable_if<
-                  std::is_constructible<string_t, CompatibleStringType>::value, int>::type
-              = 0>
+    template<class CompatibleStringType, typename std::enable_if<
+                 std::is_constructible<string_t, CompatibleStringType>::value, int>::type = 0>
     basic_json(const CompatibleStringType& val)
         : basic_json(string_t(val))
     {
@@ -1353,12 +1348,9 @@ class basic_json
 
     @since version 1.0.0
     */
-    template<typename T,
-             typename std::enable_if<
-                 not (std::is_same<T, int>::value)
-                 and std::is_same<T, number_integer_t>::value
-                 , int>::type
-             = 0>
+    template<typename T, typename std::enable_if<
+                 not (std::is_same<T, int>::value) and
+                 std::is_same<T, number_integer_t>::value, int>::type = 0>
     basic_json(const number_integer_t val) noexcept
         : m_type(value_t::number_integer), m_value(val)
     {
@@ -1422,13 +1414,11 @@ class basic_json
 
     @since version 1.0.0
     */
-    template<typename CompatibleNumberIntegerType, typename
-             std::enable_if<
+    template<typename CompatibleNumberIntegerType, typename std::enable_if<
                  std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
                  std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
                  std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
-                 CompatibleNumberIntegerType>::type
-             = 0>
+                 CompatibleNumberIntegerType>::type = 0>
     basic_json(const CompatibleNumberIntegerType val) noexcept
         : m_type(value_t::number_integer),
           m_value(static_cast<number_integer_t>(val))
@@ -1453,12 +1443,9 @@ class basic_json
 
     @since version 2.0.0
     */
-    template<typename T,
-             typename std::enable_if<
-                 not (std::is_same<T, int>::value)
-                 and std::is_same<T, number_unsigned_t>::value
-                 , int>::type
-             = 0>
+    template<typename T, typename std::enable_if<
+                 not (std::is_same<T, int>::value) and
+                 std::is_same<T, number_unsigned_t>::value, int>::type = 0>
     basic_json(const number_unsigned_t val) noexcept
         : m_type(value_t::number_unsigned), m_value(val)
     {
@@ -1485,13 +1472,11 @@ class basic_json
 
     @since version 2.0.0
     */
-    template <typename CompatibleNumberUnsignedType, typename
-              std::enable_if <
-                  std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
-                  std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
-                  not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
-                  CompatibleNumberUnsignedType>::type
-              = 0>
+    template<typename CompatibleNumberUnsignedType, typename std::enable_if <
+                 std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
+                 std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
+                 not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
+                 CompatibleNumberUnsignedType>::type = 0>
     basic_json(const CompatibleNumberUnsignedType val) noexcept
         : m_type(value_t::number_unsigned),
           m_value(static_cast<number_unsigned_t>(val))
@@ -1567,11 +1552,9 @@ class basic_json
 
     @since version 1.0.0
     */
-    template<typename CompatibleNumberFloatType, typename = typename
-             std::enable_if<
+    template<typename CompatibleNumberFloatType, typename = typename std::enable_if<
                  std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
-                 std::is_floating_point<CompatibleNumberFloatType>::value>::type
-             >
+                 std::is_floating_point<CompatibleNumberFloatType>::value>::type>
     basic_json(const CompatibleNumberFloatType val) noexcept
         : basic_json(number_float_t(val))
     {
@@ -1838,12 +1821,9 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class InputIT, typename
-              std::enable_if<
-                  std::is_same<InputIT, typename basic_json_t::iterator>::value or
-                  std::is_same<InputIT, typename basic_json_t::const_iterator>::value
-                  , int>::type
-              = 0>
+    template<class InputIT, typename std::enable_if<
+                 std::is_same<InputIT, typename basic_json_t::iterator>::value or
+                 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
     basic_json(InputIT first, InputIT last)
     {
         assert(first.m_object != nullptr);
@@ -2601,11 +2581,9 @@ class basic_json
     //////////////////
 
     /// get an object (explicit)
-    template <class T, typename
-              std::enable_if<
-                  std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
-                  std::is_convertible<basic_json_t, typename T::mapped_type>::value
-                  , int>::type = 0>
+    template<class T, typename std::enable_if<
+                 std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
+                 std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0>
     T get_impl(T*) const
     {
         if (is_object())
@@ -2632,14 +2610,12 @@ class basic_json
     }
 
     /// get an array (explicit)
-    template <class T, typename
-              std::enable_if<
-                  std::is_convertible<basic_json_t, typename T::value_type>::value and
-                  not std::is_same<basic_json_t, typename T::value_type>::value and
-                  not std::is_arithmetic<T>::value and
-                  not std::is_convertible<std::string, T>::value and
-                  not has_mapped_type<T>::value
-                  , int>::type = 0>
+    template<class T, typename std::enable_if<
+                 std::is_convertible<basic_json_t, typename T::value_type>::value and
+                 not std::is_same<basic_json_t, typename T::value_type>::value and
+                 not std::is_arithmetic<T>::value and
+                 not std::is_convertible<std::string, T>::value and
+                 not has_mapped_type<T>::value, int>::type = 0>
     T get_impl(T*) const
     {
         if (is_array())
@@ -2659,11 +2635,9 @@ class basic_json
     }
 
     /// get an array (explicit)
-    template <class T, typename
-              std::enable_if<
-                  std::is_convertible<basic_json_t, T>::value and
-                  not std::is_same<basic_json_t, T>::value
-                  , int>::type = 0>
+    template<class T, typename std::enable_if<
+                 std::is_convertible<basic_json_t, T>::value and
+                 not std::is_same<basic_json_t, T>::value, int>::type = 0>
     std::vector<T> get_impl(std::vector<T>*) const
     {
         if (is_array())
@@ -2684,11 +2658,9 @@ class basic_json
     }
 
     /// get an array (explicit)
-    template <class T, typename
-              std::enable_if<
-                  std::is_same<basic_json, typename T::value_type>::value and
-                  not has_mapped_type<T>::value
-                  , int>::type = 0>
+    template<class T, typename std::enable_if<
+                 std::is_same<basic_json, typename T::value_type>::value and
+                 not has_mapped_type<T>::value, int>::type = 0>
     T get_impl(T*) const
     {
         if (is_array())
@@ -2715,10 +2687,8 @@ class basic_json
     }
 
     /// get a string (explicit)
-    template <typename T, typename
-              std::enable_if<
-                  std::is_convertible<string_t, T>::value
-                  , int>::type = 0>
+    template<typename T, typename std::enable_if<
+                 std::is_convertible<string_t, T>::value, int>::type = 0>
     T get_impl(T*) const
     {
         if (is_string())
@@ -2732,10 +2702,8 @@ class basic_json
     }
 
     /// get a number (explicit)
-    template<typename T, typename
-             std::enable_if<
-                 std::is_arithmetic<T>::value
-                 , int>::type = 0>
+    template<typename T, typename std::enable_if<
+                 std::is_arithmetic<T>::value, int>::type = 0>
     T get_impl(T*) const
     {
         switch (m_type)
@@ -2924,10 +2892,8 @@ class basic_json
 
     @since version 1.0.0
     */
-    template<typename ValueType, typename
-             std::enable_if<
-                 not std::is_pointer<ValueType>::value
-                 , int>::type = 0>
+    template<typename ValueType, typename std::enable_if<
+                 not std::is_pointer<ValueType>::value, int>::type = 0>
     ValueType get() const
     {
         return get_impl(static_cast<ValueType*>(nullptr));
@@ -2960,10 +2926,8 @@ class basic_json
 
     @since version 1.0.0
     */
-    template<typename PointerType, typename
-             std::enable_if<
-                 std::is_pointer<PointerType>::value
-                 , int>::type = 0>
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value, int>::type = 0>
     PointerType get() noexcept
     {
         // delegate the call to get_ptr
@@ -2974,10 +2938,8 @@ class basic_json
     @brief get a pointer value (explicit)
     @copydoc get()
     */
-    template<typename PointerType, typename
-             std::enable_if<
-                 std::is_pointer<PointerType>::value
-                 , int>::type = 0>
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value, int>::type = 0>
     constexpr const PointerType get() const noexcept
     {
         // delegate the call to get_ptr
@@ -3010,10 +2972,8 @@ class basic_json
 
     @since version 1.0.0
     */
-    template<typename PointerType, typename
-             std::enable_if<
-                 std::is_pointer<PointerType>::value
-                 , int>::type = 0>
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value, int>::type = 0>
     PointerType get_ptr() noexcept
     {
         // get the type of the PointerType (remove pointer and const)
@@ -3039,11 +2999,9 @@ class basic_json
     @brief get a pointer value (implicit)
     @copydoc get_ptr()
     */
-    template<typename PointerType, typename
-             std::enable_if<
-                 std::is_pointer<PointerType>::value
-                 and std::is_const<typename std::remove_pointer<PointerType>::type>::value
-                 , int>::type = 0>
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value and
+                 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
     constexpr const PointerType get_ptr() const noexcept
     {
         // get the type of the PointerType (remove pointer and const)
@@ -3091,10 +3049,8 @@ class basic_json
 
     @since version 1.1.0
     */
-    template<typename ReferenceType, typename
-             std::enable_if<
-                 std::is_reference<ReferenceType>::value
-                 , int>::type = 0>
+    template<typename ReferenceType, typename std::enable_if<
+                 std::is_reference<ReferenceType>::value, int>::type = 0>
     ReferenceType get_ref()
     {
         // delegate call to get_ref_impl
@@ -3105,11 +3061,9 @@ class basic_json
     @brief get a reference value (implicit)
     @copydoc get_ref()
     */
-    template<typename ReferenceType, typename
-             std::enable_if<
-                 std::is_reference<ReferenceType>::value
-                 and std::is_const<typename std::remove_reference<ReferenceType>::type>::value
-                 , int>::type = 0>
+    template<typename ReferenceType, typename std::enable_if<
+                 std::is_reference<ReferenceType>::value and
+                 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
     ReferenceType get_ref() const
     {
         // delegate call to get_ref_impl
@@ -3144,10 +3098,9 @@ class basic_json
 
     @since version 1.0.0
     */
-    template < typename ValueType, typename
-               std::enable_if <
-                   not std::is_pointer<ValueType>::value
-                   and not std::is_same<ValueType, typename string_t::value_type>::value
+    template < typename ValueType, typename std::enable_if <
+                   not std::is_pointer<ValueType>::value and
+                   not std::is_same<ValueType, typename string_t::value_type>::value
 #ifndef _MSC_VER  // Fix for issue #167 operator<< abiguity under VS2015
                    and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
 #endif
@@ -3737,10 +3690,8 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class ValueType, typename
-              std::enable_if<
-                  std::is_convertible<basic_json_t, ValueType>::value
-                  , int>::type = 0>
+    template<class ValueType, typename std::enable_if<
+                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
     ValueType value(const typename object_t::key_type& key, ValueType default_value) const
     {
         // at only works for objects
@@ -3813,10 +3764,8 @@ class basic_json
 
     @since version 2.0.2
     */
-    template <class ValueType, typename
-              std::enable_if<
-                  std::is_convertible<basic_json_t, ValueType>::value
-                  , int>::type = 0>
+    template<class ValueType, typename std::enable_if<
+                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
     ValueType value(const json_pointer& ptr, ValueType default_value) const
     {
         // at only works for objects
@@ -3946,7 +3895,7 @@ class basic_json
     @return Iterator following the last removed element. If the iterator @a
     pos refers to the last element, the `end()` iterator is returned.
 
-    @tparam InteratorType an @ref iterator or @ref const_iterator
+    @tparam IteratorType an @ref iterator or @ref const_iterator
 
     @post Invalidates iterators and references at or after the point of the
     erase, including the `end()` iterator.
@@ -3968,7 +3917,7 @@ class basic_json
     @liveexample{The example shows the result of `erase()` for different JSON
     types.,erase__IteratorType}
 
-    @sa @ref erase(InteratorType, InteratorType) -- removes the elements in
+    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
     the given range
     @sa @ref erase(const typename object_t::key_type&) -- removes the element
     from an object at the given key
@@ -3977,13 +3926,11 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class InteratorType, typename
-              std::enable_if<
-                  std::is_same<InteratorType, typename basic_json_t::iterator>::value or
-                  std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
-                  , int>::type
-              = 0>
-    InteratorType erase(InteratorType pos)
+    template<class IteratorType, typename std::enable_if<
+                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
+                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
+             = 0>
+    IteratorType erase(IteratorType pos)
     {
         // make sure iterator fits the current value
         if (this != pos.m_object)
@@ -3991,7 +3938,7 @@ class basic_json
             throw std::domain_error("iterator does not fit current value");
         }
 
-        InteratorType result = end();
+        IteratorType result = end();
 
         switch (m_type)
         {
@@ -4055,7 +4002,7 @@ class basic_json
     @return Iterator following the last removed element. If the iterator @a
     second refers to the last element, the `end()` iterator is returned.
 
-    @tparam InteratorType an @ref iterator or @ref const_iterator
+    @tparam IteratorType an @ref iterator or @ref const_iterator
 
     @post Invalidates iterators and references at or after the point of the
     erase, including the `end()` iterator.
@@ -4078,7 +4025,7 @@ class basic_json
     @liveexample{The example shows the result of `erase()` for different JSON
     types.,erase__IteratorType_IteratorType}
 
-    @sa @ref erase(InteratorType) -- removes the element at a given position
+    @sa @ref erase(IteratorType) -- removes the element at a given position
     @sa @ref erase(const typename object_t::key_type&) -- removes the element
     from an object at the given key
     @sa @ref erase(const size_type) -- removes the element from an array at
@@ -4086,13 +4033,11 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class InteratorType, typename
-              std::enable_if<
-                  std::is_same<InteratorType, typename basic_json_t::iterator>::value or
-                  std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
-                  , int>::type
-              = 0>
-    InteratorType erase(InteratorType first, InteratorType last)
+    template<class IteratorType, typename std::enable_if<
+                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
+                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
+             = 0>
+    IteratorType erase(IteratorType first, IteratorType last)
     {
         // make sure iterator fits the current value
         if (this != first.m_object or this != last.m_object)
@@ -4100,7 +4045,7 @@ class basic_json
             throw std::domain_error("iterators do not fit current value");
         }
 
-        InteratorType result = end();
+        IteratorType result = end();
 
         switch (m_type)
         {
@@ -4172,8 +4117,8 @@ class basic_json
 
     @liveexample{The example shows the effect of `erase()`.,erase__key_type}
 
-    @sa @ref erase(InteratorType) -- removes the element at a given position
-    @sa @ref erase(InteratorType, InteratorType) -- removes the elements in
+    @sa @ref erase(IteratorType) -- removes the element at a given position
+    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
     the given range
     @sa @ref erase(const size_type) -- removes the element from an array at
     the given index
@@ -4209,8 +4154,8 @@ class basic_json
 
     @liveexample{The example shows the effect of `erase()`.,erase__size_type}
 
-    @sa @ref erase(InteratorType) -- removes the element at a given position
-    @sa @ref erase(InteratorType, InteratorType) -- removes the elements in
+    @sa @ref erase(IteratorType) -- removes the element at a given position
+    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
     the given range
     @sa @ref erase(const typename object_t::key_type&) -- removes the element
     from an object at the given key
@@ -5918,10 +5863,16 @@ class basic_json
     /// @{
 
     /*!
-    @brief deserialize from string
+    @brief deserialize from an array
 
-    @param[in] s  string to read a serialized JSON value from
-    @param[in] cb a parser callback function of type @ref parser_callback_t
+    This function reads from an array of 1-byte values.
+
+    @pre Each element of the container has a size of 1 byte. Violating this
+    precondition yields undefined behavior. **This precondition is enforced
+    with a static assertion.**
+
+    @param[in] array  array to read from
+    @param[in] cb  a parser callback function of type @ref parser_callback_t
     which is used to control the deserialization by filtering unwanted values
     (optional)
 
@@ -5933,18 +5884,54 @@ class basic_json
 
     @note A UTF-8 byte order mark is silently ignored.
 
+    @liveexample{The example below demonstrates the `parse()` function reading
+    from an array.,parse__array__parser_callback_t}
+
+    @since version 2.0.3
+    */
+    template<class T, std::size_t N>
+    static basic_json parse(T (&array)[N],
+                            const parser_callback_t cb = nullptr)
+    {
+        // delegate the call to the iterator-range parse overload
+        return parse(std::begin(array), std::end(array), cb);
+    }
+
+    /*!
+    @brief deserialize from string literal
+
+    @tparam CharT character/literal type with size of 1 byte
+    @param[in] s  string literal to read a serialized JSON value from
+    @param[in] cb a parser callback function of type @ref parser_callback_t
+    which is used to control the deserialization by filtering unwanted values
+    (optional)
+
+    @return result of the deserialization
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser. The complexity can be higher if the parser callback function
+    @a cb has a super-linear complexity.
+
+    @note A UTF-8 byte order mark is silently ignored.
+    @note String containers like `std::string` or @ref string_t can be parsed
+          with @ref parse(const ContiguousContainer&, const parser_callback_t)
+
     @liveexample{The example below demonstrates the `parse()` function with
     and without callback function.,parse__string__parser_callback_t}
 
     @sa @ref parse(std::istream&, const parser_callback_t) for a version that
     reads from an input stream
 
-    @since version 1.0.0
+    @since version 1.0.0 (originally for @ref string_t)
     */
-    static basic_json parse(const string_t& s,
+    template<typename CharPT, typename std::enable_if<
+                 std::is_pointer<CharPT>::value and
+                 std::is_integral<typename std::remove_pointer<CharPT>::type>::value and
+                 sizeof(typename std::remove_pointer<CharPT>::type) == 1, int>::type = 0>
+    static basic_json parse(const CharPT s,
                             const parser_callback_t cb = nullptr)
     {
-        return parser(s, cb).parse();
+        return parser(reinterpret_cast<const char*>(s), cb).parse();
     }
 
     /*!
@@ -5966,7 +5953,7 @@ class basic_json
     @liveexample{The example below demonstrates the `parse()` function with
     and without callback function.,parse__istream__parser_callback_t}
 
-    @sa @ref parse(const string_t&, const parser_callback_t) for a version
+    @sa @ref parse(const char*, const parser_callback_t) for a version
     that reads from a string
 
     @since version 1.0.0
@@ -5986,6 +5973,130 @@ class basic_json
         return parser(i, cb).parse();
     }
 
+    /*!
+    @brief deserialize from an iterator range with contiguous storage
+
+    This function reads from an iterator range of a container with contiguous
+    storage of 1-byte values. Compatible container types include
+    `std::vector`, `std::string`, `std::array`, `std::valarray`, and
+    `std::initializer_list`. Furthermore, C-style arrays can be used with
+    `std::begin()`/`std::end()`. User-defined containers can be used as long
+    as they implement random-access iterators and a contiguous storage.
+
+    @pre The iterator range is contiguous. Violating this precondition yields
+    undefined behavior. **This precondition is enforced with an assertion.**
+    @pre Each element in the range has a size of 1 byte. Violating this
+    precondition yields undefined behavior. **This precondition is enforced
+    with a static assertion.**
+
+    @warning There is no way to enforce all preconditions at compile-time. If
+             the function is called with noncompliant iterators and with
+             assertions switched off, the behavior is undefined and will most
+             likely yield segmentation violation.
+
+    @tparam IteratorType iterator of container with contiguous storage
+    @param[in] first  begin of the range to parse (included)
+    @param[in] last  end of the range to parse (excluded)
+    @param[in] cb  a parser callback function of type @ref parser_callback_t
+    which is used to control the deserialization by filtering unwanted values
+    (optional)
+
+    @return result of the deserialization
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser. The complexity can be higher if the parser callback function
+    @a cb has a super-linear complexity.
+
+    @note A UTF-8 byte order mark is silently ignored.
+
+    @liveexample{The example below demonstrates the `parse()` function reading
+    from an iterator range.,parse__iteratortype__parser_callback_t}
+
+    @since version 2.0.3
+    */
+    template<class IteratorType, typename std::enable_if<
+                 std::is_base_of<
+                     std::random_access_iterator_tag,
+                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
+    static basic_json parse(IteratorType first, IteratorType last,
+                            const parser_callback_t cb = nullptr)
+    {
+        // assertion to check that the iterator range is indeed contiguous,
+        // see http://stackoverflow.com/a/35008842/266378 for more discussion
+        assert(std::accumulate(first, last, std::make_pair<bool, int>(true, 0),
+                               [&first](std::pair<bool, int> res, decltype(*first) val)
+        {
+            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
+            return res;
+        }).first);
+
+        // assertion to check that each element is 1 byte long
+        static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
+                      "each element in the iterator range must have the size of 1 byte");
+
+        // if iterator range is empty, create a parser with an empty string
+        // to generate "unexpected EOF" error message
+        if (std::distance(first, last) <= 0)
+        {
+            return parser("").parse();
+        }
+
+        return parser(first, last, cb).parse();
+    }
+
+    /*!
+    @brief deserialize from a container with contiguous storage
+
+    This function reads from a container with contiguous storage of 1-byte
+    values. Compatible container types include `std::vector`, `std::string`,
+    `std::array`, and `std::initializer_list`. User-defined containers can be
+    used as long as they implement random-access iterators and a contiguous
+    storage.
+
+    @pre The container storage is contiguous. Violating this precondition
+    yields undefined behavior. **This precondition is enforced with an
+    assertion.**
+    @pre Each element of the container has a size of 1 byte. Violating this
+    precondition yields undefined behavior. **This precondition is enforced
+    with a static assertion.**
+
+    @warning There is no way to enforce all preconditions at compile-time. If
+             the function is called with a noncompliant container and with
+             assertions switched off, the behavior is undefined and will most
+             likely yield segmentation violation.
+
+    @tparam ContiguousContainer container type with contiguous storage
+    @param[in] c  container to read from
+    @param[in] cb  a parser callback function of type @ref parser_callback_t
+    which is used to control the deserialization by filtering unwanted values
+    (optional)
+
+    @return result of the deserialization
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser. The complexity can be higher if the parser callback function
+    @a cb has a super-linear complexity.
+
+    @note A UTF-8 byte order mark is silently ignored.
+
+    @liveexample{The example below demonstrates the `parse()` function reading
+    from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
+
+    @since version 2.0.3
+    */
+    template<class ContiguousContainer, typename std::enable_if<
+                 not std::is_pointer<ContiguousContainer>::value and
+                 std::is_base_of<
+                     std::random_access_iterator_tag,
+                     typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value
+                 , int>::type = 0>
+    static basic_json parse(const ContiguousContainer& c,
+                            const parser_callback_t cb = nullptr)
+    {
+        // delegate the call to the iterator-range parse overload
+        return parse(std::begin(c), std::end(c), cb);
+    }
+
     /*!
     @brief deserialize from stream
 
@@ -6039,7 +6150,7 @@ class basic_json
     Returns the type name as string to be used in error messages - usually to
     indicate that a function was called on a wrong JSON type.
 
-    @return basically a string representation of a the @ref m_type member
+    @return basically a string representation of a the @a m_type member
 
     @complexity Constant.
 
@@ -7490,32 +7601,25 @@ class basic_json
         /// the char type to use in the lexer
         using lexer_char_t = unsigned char;
 
-        /// constructor with a given buffer
-        explicit lexer(const string_t& s) noexcept
-            : m_stream(nullptr), m_buffer(s)
+        /// a lexer from a buffer with given length
+        lexer(const lexer_char_t* buff, const size_t len) noexcept
+            : m_content(buff)
         {
-            m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
             assert(m_content != nullptr);
             m_start = m_cursor = m_content;
-            m_limit = m_content + s.size();
+            m_limit = m_content + len;
         }
 
-        /// constructor with a given stream
-        explicit lexer(std::istream* s) noexcept
-            : m_stream(s), m_buffer()
+        /// a lexer from an input stream
+        explicit lexer(std::istream& s)
+            : m_stream(&s), m_line_buffer()
         {
-            assert(m_stream != nullptr);
-            std::getline(*m_stream, m_buffer);
-            m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
-            assert(m_content != nullptr);
-            m_start = m_cursor = m_content;
-            m_limit = m_content + m_buffer.size();
+            // fill buffer
+            fill_line_buffer();
         }
 
-        /// default constructor
-        lexer() = default;
-
-        // switch off unwanted functions
+        // switch off unwanted functions (due to pointer members)
+        lexer() = delete;
         lexer(const lexer&) = delete;
         lexer operator=(const lexer&) = delete;
 
@@ -7668,7 +7772,7 @@ class basic_json
         infinite sequence of whitespace or byte-order-marks. This contradicts
         the assumption of finite input, q.e.d.
         */
-        token_type scan() noexcept
+        token_type scan()
         {
             while (true)
             {
@@ -7720,7 +7824,7 @@ class basic_json
                     };
                     if ((m_limit - m_cursor) < 5)
                     {
-                        yyfill();
+                        fill_line_buffer();
                     }
                     yych = *m_cursor;
                     if (yybm[0 + yych] & 32)
@@ -7854,7 +7958,7 @@ basic_json_parser_6:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();
+                        fill_line_buffer();
                     }
                     yych = *m_cursor;
                     if (yybm[0 + yych] & 32)
@@ -7924,7 +8028,7 @@ basic_json_parser_15:
                     m_marker = ++m_cursor;
                     if ((m_limit - m_cursor) < 3)
                     {
-                        yyfill();
+                        fill_line_buffer();
                     }
                     yych = *m_cursor;
                     if (yybm[0 + yych] & 64)
@@ -8017,7 +8121,7 @@ basic_json_parser_31:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();
+                        fill_line_buffer();
                     }
                     yych = *m_cursor;
 basic_json_parser_32:
@@ -8054,7 +8158,7 @@ basic_json_parser_36:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();
+                        fill_line_buffer();
                     }
                     yych = *m_cursor;
                     if (yych <= 'e')
@@ -8198,7 +8302,7 @@ basic_json_parser_43:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();
+                        fill_line_buffer();
                     }
                     yych = *m_cursor;
                     if (yych <= '@')
@@ -8234,7 +8338,7 @@ basic_json_parser_44:
                     m_marker = ++m_cursor;
                     if ((m_limit - m_cursor) < 3)
                     {
-                        yyfill();
+                        fill_line_buffer();
                     }
                     yych = *m_cursor;
                     if (yych <= 'D')
@@ -8275,7 +8379,7 @@ basic_json_parser_47:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();
+                        fill_line_buffer();
                     }
                     yych = *m_cursor;
                     if (yych <= '/')
@@ -8317,7 +8421,7 @@ basic_json_parser_54:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();
+                        fill_line_buffer();
                     }
                     yych = *m_cursor;
                     if (yych <= '@')
@@ -8371,7 +8475,7 @@ basic_json_parser_60:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();
+                        fill_line_buffer();
                     }
                     yych = *m_cursor;
                     if (yych <= '@')
@@ -8412,7 +8516,7 @@ basic_json_parser_63:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();
+                        fill_line_buffer();
                     }
                     yych = *m_cursor;
                     if (yych <= '@')
@@ -8450,30 +8554,76 @@ basic_json_parser_63:
             return last_token_type;
         }
 
-        /// append data from the stream to the internal buffer
-        void yyfill() noexcept
-        {
-            if (m_stream == nullptr or not * m_stream)
-            {
-                return;
-            }
+        /*!
+        @brief append data from the stream to the line buffer
 
+        This function is called by the scan() function when the end of the
+        buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be
+        incremented without leaving the limits of the line buffer. Note re2c
+        decides when to call this function.
+
+        If the lexer reads from contiguous storage, there is no trailing null
+        byte. Therefore, this function must make sure to add these padding
+        null bytes.
+
+        If the lexer reads from an input stream, this function reads the next
+        line of the input.
+
+        @pre
+            p p p p p p u u u u u x . . . . . .
+            ^           ^       ^   ^
+            m_content   m_start |   m_limit
+                                m_cursor
+
+        @post
+            u u u u u x x x x x x x . . . . . .
+            ^       ^               ^
+            |       m_cursor        m_limit
+            m_start
+            m_content
+        */
+        void fill_line_buffer()
+        {
+            // number of processed characters (p)
             const auto offset_start = m_start - m_content;
-            const auto offset_marker = m_marker - m_start;
+            // offset for m_marker wrt. to m_start
+            const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
+            // number of unprocessed characters (u)
             const auto offset_cursor = m_cursor - m_start;
 
-            m_buffer.erase(0, static_cast<size_t>(offset_start));
-            std::string line;
-            assert(m_stream != nullptr);
-            std::getline(*m_stream, line);
-            m_buffer += "\n" + line; // add line with newline symbol
+            // no stream is used or end of file is reached
+            if (m_stream == nullptr or not * m_stream)
+            {
+                // copy unprocessed characters to line buffer
+                m_line_buffer.clear();
+                for (m_cursor = m_start; m_cursor != m_limit; ++m_cursor)
+                {
+                    m_line_buffer.append(1, static_cast<const char>(*m_cursor));
+                }
 
-            m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
+                // append 5 characters (size of longest keyword "false") to
+                // make sure that there is sufficient space between m_cursor
+                // and m_limit
+                m_line_buffer.append(5, '\0');
+            }
+            else
+            {
+                // delete processed characters from line buffer
+                m_line_buffer.erase(0, static_cast<size_t>(offset_start));
+                // read next line from input stream
+                std::string line;
+                std::getline(*m_stream, line);
+                // add line with newline symbol to the line buffer
+                m_line_buffer += "\n" + line;
+            }
+
+            // set pointers
+            m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.c_str());
             assert(m_content != nullptr);
             m_start  = m_content;
             m_marker = m_start + offset_marker;
             m_cursor = m_start + offset_cursor;
-            m_limit  = m_start + m_buffer.size() - 1;
+            m_limit  = m_start + m_line_buffer.size();
         }
 
         /// return string representation of last read token
@@ -8815,8 +8965,8 @@ basic_json_parser_63:
       private:
         /// optional input stream
         std::istream* m_stream = nullptr;
-        /// the buffer
-        string_t m_buffer;
+        /// line buffer buffer for m_stream
+        string_t m_line_buffer {};
         /// the buffer pointer
         const lexer_char_t* m_content = nullptr;
         /// pointer to the beginning of the current symbol
@@ -8839,25 +8989,34 @@ basic_json_parser_63:
     class parser
     {
       public:
-        /// constructor for strings
-        parser(const string_t& s, const parser_callback_t cb = nullptr) noexcept
-            : callback(cb), m_lexer(s)
-        {
-            // read first token
-            get_token();
-        }
+        /// a parser reading from a string literal
+        parser(const char* buff, const parser_callback_t cb = nullptr)
+            : callback(cb),
+              m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), strlen(buff))
+        {}
 
         /// a parser reading from an input stream
-        parser(std::istream& _is, const parser_callback_t cb = nullptr) noexcept
-            : callback(cb), m_lexer(&_is)
-        {
-            // read first token
-            get_token();
-        }
+        parser(std::istream& is, const parser_callback_t cb = nullptr)
+            : callback(cb), m_lexer(is)
+        {}
+
+        /// a parser reading from an iterator range with contiguous storage
+        template<class IteratorType, typename std::enable_if<
+                     std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
+                     , int>::type
+                 = 0>
+        parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr)
+            : callback(cb),
+              m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)),
+                      static_cast<size_t>(std::distance(first, last)))
+        {}
 
         /// public parser interface
         basic_json parse()
         {
+            // read first token
+            get_token();
+
             basic_json result = parse_internal(true);
             result.assert_invariant();
 
@@ -9064,7 +9223,7 @@ basic_json_parser_63:
         }
 
         /// get next token from lexer
-        typename lexer::token_type get_token() noexcept
+        typename lexer::token_type get_token()
         {
             last_token = m_lexer.scan();
             return last_token;
@@ -10362,7 +10521,7 @@ namespace std
 
 @since version 1.0.0
 */
-template <>
+template<>
 inline void swap(nlohmann::json& j1,
                  nlohmann::json& j2) noexcept(
                      is_nothrow_move_constructible<nlohmann::json>::value and
@@ -10373,7 +10532,7 @@ inline void swap(nlohmann::json& j1,
 }
 
 /// hash value for JSON objects
-template <>
+template<>
 struct hash<nlohmann::json>
 {
     /*!
@@ -10404,7 +10563,7 @@ if no parse error occurred.
 */
 inline nlohmann::json operator "" _json(const char* s, std::size_t)
 {
-    return nlohmann::json::parse(reinterpret_cast<const nlohmann::json::string_t::value_type*>(s));
+    return nlohmann::json::parse(s);
 }
 
 /*!
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 75b38d96..300337a2 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -37,6 +37,7 @@ SOFTWARE.
 #include <cstddef>
 #include <cstdint>
 #include <cstdlib>
+#include <cstring>
 #include <functional>
 #include <initializer_list>
 #include <iomanip>
@@ -959,7 +960,7 @@ class basic_json
 
     With a parser callback function, the result of parsing a JSON text can be
     influenced. When passed to @ref parse(std::istream&, const
-    parser_callback_t) or @ref parse(const string_t&, const parser_callback_t),
+    parser_callback_t) or @ref parse(const char*, const parser_callback_t),
     it is called on certain events (passed as @ref parse_event_t via parameter
     @a event) with a set recursion depth @a depth and context JSON value
     @a parsed. The return value of the callback function is a boolean
@@ -1002,7 +1003,7 @@ class basic_json
     skipped completely or replaced by an empty discarded object.
 
     @sa @ref parse(std::istream&, parser_callback_t) or
-    @ref parse(const string_t&, parser_callback_t) for examples
+    @ref parse(const char*, parser_callback_t) for examples
 
     @since version 1.0.0
     */
@@ -1140,11 +1141,9 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class CompatibleObjectType, typename
-              std::enable_if<
-                  std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
-                  std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type
-              = 0>
+    template<class CompatibleObjectType, typename std::enable_if<
+                 std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
+                 std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type = 0>
     basic_json(const CompatibleObjectType& val)
         : m_type(value_t::object)
     {
@@ -1205,16 +1204,14 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class CompatibleArrayType, typename
-              std::enable_if<
-                  not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
-                  not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
-                  not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
-                  not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
-                  not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
-                  not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
-                  std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type
-              = 0>
+    template<class CompatibleArrayType, typename std::enable_if<
+                 not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
+                 std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type = 0>
     basic_json(const CompatibleArrayType& val)
         : m_type(value_t::array)
     {
@@ -1300,10 +1297,8 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class CompatibleStringType, typename
-              std::enable_if<
-                  std::is_constructible<string_t, CompatibleStringType>::value, int>::type
-              = 0>
+    template<class CompatibleStringType, typename std::enable_if<
+                 std::is_constructible<string_t, CompatibleStringType>::value, int>::type = 0>
     basic_json(const CompatibleStringType& val)
         : basic_json(string_t(val))
     {
@@ -1353,12 +1348,9 @@ class basic_json
 
     @since version 1.0.0
     */
-    template<typename T,
-             typename std::enable_if<
-                 not (std::is_same<T, int>::value)
-                 and std::is_same<T, number_integer_t>::value
-                 , int>::type
-             = 0>
+    template<typename T, typename std::enable_if<
+                 not (std::is_same<T, int>::value) and
+                 std::is_same<T, number_integer_t>::value, int>::type = 0>
     basic_json(const number_integer_t val) noexcept
         : m_type(value_t::number_integer), m_value(val)
     {
@@ -1422,13 +1414,11 @@ class basic_json
 
     @since version 1.0.0
     */
-    template<typename CompatibleNumberIntegerType, typename
-             std::enable_if<
+    template<typename CompatibleNumberIntegerType, typename std::enable_if<
                  std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
                  std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
                  std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
-                 CompatibleNumberIntegerType>::type
-             = 0>
+                 CompatibleNumberIntegerType>::type = 0>
     basic_json(const CompatibleNumberIntegerType val) noexcept
         : m_type(value_t::number_integer),
           m_value(static_cast<number_integer_t>(val))
@@ -1453,12 +1443,9 @@ class basic_json
 
     @since version 2.0.0
     */
-    template<typename T,
-             typename std::enable_if<
-                 not (std::is_same<T, int>::value)
-                 and std::is_same<T, number_unsigned_t>::value
-                 , int>::type
-             = 0>
+    template<typename T, typename std::enable_if<
+                 not (std::is_same<T, int>::value) and
+                 std::is_same<T, number_unsigned_t>::value, int>::type = 0>
     basic_json(const number_unsigned_t val) noexcept
         : m_type(value_t::number_unsigned), m_value(val)
     {
@@ -1485,13 +1472,11 @@ class basic_json
 
     @since version 2.0.0
     */
-    template <typename CompatibleNumberUnsignedType, typename
-              std::enable_if <
-                  std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
-                  std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
-                  not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
-                  CompatibleNumberUnsignedType>::type
-              = 0>
+    template<typename CompatibleNumberUnsignedType, typename std::enable_if <
+                 std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
+                 std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
+                 not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
+                 CompatibleNumberUnsignedType>::type = 0>
     basic_json(const CompatibleNumberUnsignedType val) noexcept
         : m_type(value_t::number_unsigned),
           m_value(static_cast<number_unsigned_t>(val))
@@ -1567,11 +1552,9 @@ class basic_json
 
     @since version 1.0.0
     */
-    template<typename CompatibleNumberFloatType, typename = typename
-             std::enable_if<
+    template<typename CompatibleNumberFloatType, typename = typename std::enable_if<
                  std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
-                 std::is_floating_point<CompatibleNumberFloatType>::value>::type
-             >
+                 std::is_floating_point<CompatibleNumberFloatType>::value>::type>
     basic_json(const CompatibleNumberFloatType val) noexcept
         : basic_json(number_float_t(val))
     {
@@ -1838,12 +1821,9 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class InputIT, typename
-              std::enable_if<
-                  std::is_same<InputIT, typename basic_json_t::iterator>::value or
-                  std::is_same<InputIT, typename basic_json_t::const_iterator>::value
-                  , int>::type
-              = 0>
+    template<class InputIT, typename std::enable_if<
+                 std::is_same<InputIT, typename basic_json_t::iterator>::value or
+                 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
     basic_json(InputIT first, InputIT last)
     {
         assert(first.m_object != nullptr);
@@ -2601,11 +2581,9 @@ class basic_json
     //////////////////
 
     /// get an object (explicit)
-    template <class T, typename
-              std::enable_if<
-                  std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
-                  std::is_convertible<basic_json_t, typename T::mapped_type>::value
-                  , int>::type = 0>
+    template<class T, typename std::enable_if<
+                 std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
+                 std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0>
     T get_impl(T*) const
     {
         if (is_object())
@@ -2632,14 +2610,12 @@ class basic_json
     }
 
     /// get an array (explicit)
-    template <class T, typename
-              std::enable_if<
-                  std::is_convertible<basic_json_t, typename T::value_type>::value and
-                  not std::is_same<basic_json_t, typename T::value_type>::value and
-                  not std::is_arithmetic<T>::value and
-                  not std::is_convertible<std::string, T>::value and
-                  not has_mapped_type<T>::value
-                  , int>::type = 0>
+    template<class T, typename std::enable_if<
+                 std::is_convertible<basic_json_t, typename T::value_type>::value and
+                 not std::is_same<basic_json_t, typename T::value_type>::value and
+                 not std::is_arithmetic<T>::value and
+                 not std::is_convertible<std::string, T>::value and
+                 not has_mapped_type<T>::value, int>::type = 0>
     T get_impl(T*) const
     {
         if (is_array())
@@ -2659,11 +2635,9 @@ class basic_json
     }
 
     /// get an array (explicit)
-    template <class T, typename
-              std::enable_if<
-                  std::is_convertible<basic_json_t, T>::value and
-                  not std::is_same<basic_json_t, T>::value
-                  , int>::type = 0>
+    template<class T, typename std::enable_if<
+                 std::is_convertible<basic_json_t, T>::value and
+                 not std::is_same<basic_json_t, T>::value, int>::type = 0>
     std::vector<T> get_impl(std::vector<T>*) const
     {
         if (is_array())
@@ -2684,11 +2658,9 @@ class basic_json
     }
 
     /// get an array (explicit)
-    template <class T, typename
-              std::enable_if<
-                  std::is_same<basic_json, typename T::value_type>::value and
-                  not has_mapped_type<T>::value
-                  , int>::type = 0>
+    template<class T, typename std::enable_if<
+                 std::is_same<basic_json, typename T::value_type>::value and
+                 not has_mapped_type<T>::value, int>::type = 0>
     T get_impl(T*) const
     {
         if (is_array())
@@ -2715,10 +2687,8 @@ class basic_json
     }
 
     /// get a string (explicit)
-    template <typename T, typename
-              std::enable_if<
-                  std::is_convertible<string_t, T>::value
-                  , int>::type = 0>
+    template<typename T, typename std::enable_if<
+                 std::is_convertible<string_t, T>::value, int>::type = 0>
     T get_impl(T*) const
     {
         if (is_string())
@@ -2732,10 +2702,8 @@ class basic_json
     }
 
     /// get a number (explicit)
-    template<typename T, typename
-             std::enable_if<
-                 std::is_arithmetic<T>::value
-                 , int>::type = 0>
+    template<typename T, typename std::enable_if<
+                 std::is_arithmetic<T>::value, int>::type = 0>
     T get_impl(T*) const
     {
         switch (m_type)
@@ -2924,10 +2892,8 @@ class basic_json
 
     @since version 1.0.0
     */
-    template<typename ValueType, typename
-             std::enable_if<
-                 not std::is_pointer<ValueType>::value
-                 , int>::type = 0>
+    template<typename ValueType, typename std::enable_if<
+                 not std::is_pointer<ValueType>::value, int>::type = 0>
     ValueType get() const
     {
         return get_impl(static_cast<ValueType*>(nullptr));
@@ -2960,10 +2926,8 @@ class basic_json
 
     @since version 1.0.0
     */
-    template<typename PointerType, typename
-             std::enable_if<
-                 std::is_pointer<PointerType>::value
-                 , int>::type = 0>
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value, int>::type = 0>
     PointerType get() noexcept
     {
         // delegate the call to get_ptr
@@ -2974,10 +2938,8 @@ class basic_json
     @brief get a pointer value (explicit)
     @copydoc get()
     */
-    template<typename PointerType, typename
-             std::enable_if<
-                 std::is_pointer<PointerType>::value
-                 , int>::type = 0>
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value, int>::type = 0>
     constexpr const PointerType get() const noexcept
     {
         // delegate the call to get_ptr
@@ -3010,10 +2972,8 @@ class basic_json
 
     @since version 1.0.0
     */
-    template<typename PointerType, typename
-             std::enable_if<
-                 std::is_pointer<PointerType>::value
-                 , int>::type = 0>
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value, int>::type = 0>
     PointerType get_ptr() noexcept
     {
         // get the type of the PointerType (remove pointer and const)
@@ -3039,11 +2999,9 @@ class basic_json
     @brief get a pointer value (implicit)
     @copydoc get_ptr()
     */
-    template<typename PointerType, typename
-             std::enable_if<
-                 std::is_pointer<PointerType>::value
-                 and std::is_const<typename std::remove_pointer<PointerType>::type>::value
-                 , int>::type = 0>
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value and
+                 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
     constexpr const PointerType get_ptr() const noexcept
     {
         // get the type of the PointerType (remove pointer and const)
@@ -3091,10 +3049,8 @@ class basic_json
 
     @since version 1.1.0
     */
-    template<typename ReferenceType, typename
-             std::enable_if<
-                 std::is_reference<ReferenceType>::value
-                 , int>::type = 0>
+    template<typename ReferenceType, typename std::enable_if<
+                 std::is_reference<ReferenceType>::value, int>::type = 0>
     ReferenceType get_ref()
     {
         // delegate call to get_ref_impl
@@ -3105,11 +3061,9 @@ class basic_json
     @brief get a reference value (implicit)
     @copydoc get_ref()
     */
-    template<typename ReferenceType, typename
-             std::enable_if<
-                 std::is_reference<ReferenceType>::value
-                 and std::is_const<typename std::remove_reference<ReferenceType>::type>::value
-                 , int>::type = 0>
+    template<typename ReferenceType, typename std::enable_if<
+                 std::is_reference<ReferenceType>::value and
+                 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
     ReferenceType get_ref() const
     {
         // delegate call to get_ref_impl
@@ -3144,10 +3098,9 @@ class basic_json
 
     @since version 1.0.0
     */
-    template < typename ValueType, typename
-               std::enable_if <
-                   not std::is_pointer<ValueType>::value
-                   and not std::is_same<ValueType, typename string_t::value_type>::value
+    template < typename ValueType, typename std::enable_if <
+                   not std::is_pointer<ValueType>::value and
+                   not std::is_same<ValueType, typename string_t::value_type>::value
 #ifndef _MSC_VER  // Fix for issue #167 operator<< abiguity under VS2015
                    and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
 #endif
@@ -3737,10 +3690,8 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class ValueType, typename
-              std::enable_if<
-                  std::is_convertible<basic_json_t, ValueType>::value
-                  , int>::type = 0>
+    template<class ValueType, typename std::enable_if<
+                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
     ValueType value(const typename object_t::key_type& key, ValueType default_value) const
     {
         // at only works for objects
@@ -3813,10 +3764,8 @@ class basic_json
 
     @since version 2.0.2
     */
-    template <class ValueType, typename
-              std::enable_if<
-                  std::is_convertible<basic_json_t, ValueType>::value
-                  , int>::type = 0>
+    template<class ValueType, typename std::enable_if<
+                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
     ValueType value(const json_pointer& ptr, ValueType default_value) const
     {
         // at only works for objects
@@ -3946,7 +3895,7 @@ class basic_json
     @return Iterator following the last removed element. If the iterator @a
     pos refers to the last element, the `end()` iterator is returned.
 
-    @tparam InteratorType an @ref iterator or @ref const_iterator
+    @tparam IteratorType an @ref iterator or @ref const_iterator
 
     @post Invalidates iterators and references at or after the point of the
     erase, including the `end()` iterator.
@@ -3968,7 +3917,7 @@ class basic_json
     @liveexample{The example shows the result of `erase()` for different JSON
     types.,erase__IteratorType}
 
-    @sa @ref erase(InteratorType, InteratorType) -- removes the elements in
+    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
     the given range
     @sa @ref erase(const typename object_t::key_type&) -- removes the element
     from an object at the given key
@@ -3977,13 +3926,11 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class InteratorType, typename
-              std::enable_if<
-                  std::is_same<InteratorType, typename basic_json_t::iterator>::value or
-                  std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
-                  , int>::type
-              = 0>
-    InteratorType erase(InteratorType pos)
+    template<class IteratorType, typename std::enable_if<
+                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
+                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
+             = 0>
+    IteratorType erase(IteratorType pos)
     {
         // make sure iterator fits the current value
         if (this != pos.m_object)
@@ -3991,7 +3938,7 @@ class basic_json
             throw std::domain_error("iterator does not fit current value");
         }
 
-        InteratorType result = end();
+        IteratorType result = end();
 
         switch (m_type)
         {
@@ -4055,7 +4002,7 @@ class basic_json
     @return Iterator following the last removed element. If the iterator @a
     second refers to the last element, the `end()` iterator is returned.
 
-    @tparam InteratorType an @ref iterator or @ref const_iterator
+    @tparam IteratorType an @ref iterator or @ref const_iterator
 
     @post Invalidates iterators and references at or after the point of the
     erase, including the `end()` iterator.
@@ -4078,7 +4025,7 @@ class basic_json
     @liveexample{The example shows the result of `erase()` for different JSON
     types.,erase__IteratorType_IteratorType}
 
-    @sa @ref erase(InteratorType) -- removes the element at a given position
+    @sa @ref erase(IteratorType) -- removes the element at a given position
     @sa @ref erase(const typename object_t::key_type&) -- removes the element
     from an object at the given key
     @sa @ref erase(const size_type) -- removes the element from an array at
@@ -4086,13 +4033,11 @@ class basic_json
 
     @since version 1.0.0
     */
-    template <class InteratorType, typename
-              std::enable_if<
-                  std::is_same<InteratorType, typename basic_json_t::iterator>::value or
-                  std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
-                  , int>::type
-              = 0>
-    InteratorType erase(InteratorType first, InteratorType last)
+    template<class IteratorType, typename std::enable_if<
+                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
+                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
+             = 0>
+    IteratorType erase(IteratorType first, IteratorType last)
     {
         // make sure iterator fits the current value
         if (this != first.m_object or this != last.m_object)
@@ -4100,7 +4045,7 @@ class basic_json
             throw std::domain_error("iterators do not fit current value");
         }
 
-        InteratorType result = end();
+        IteratorType result = end();
 
         switch (m_type)
         {
@@ -4172,8 +4117,8 @@ class basic_json
 
     @liveexample{The example shows the effect of `erase()`.,erase__key_type}
 
-    @sa @ref erase(InteratorType) -- removes the element at a given position
-    @sa @ref erase(InteratorType, InteratorType) -- removes the elements in
+    @sa @ref erase(IteratorType) -- removes the element at a given position
+    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
     the given range
     @sa @ref erase(const size_type) -- removes the element from an array at
     the given index
@@ -4209,8 +4154,8 @@ class basic_json
 
     @liveexample{The example shows the effect of `erase()`.,erase__size_type}
 
-    @sa @ref erase(InteratorType) -- removes the element at a given position
-    @sa @ref erase(InteratorType, InteratorType) -- removes the elements in
+    @sa @ref erase(IteratorType) -- removes the element at a given position
+    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
     the given range
     @sa @ref erase(const typename object_t::key_type&) -- removes the element
     from an object at the given key
@@ -5918,10 +5863,16 @@ class basic_json
     /// @{
 
     /*!
-    @brief deserialize from string
+    @brief deserialize from an array
 
-    @param[in] s  string to read a serialized JSON value from
-    @param[in] cb a parser callback function of type @ref parser_callback_t
+    This function reads from an array of 1-byte values.
+
+    @pre Each element of the container has a size of 1 byte. Violating this
+    precondition yields undefined behavior. **This precondition is enforced
+    with a static assertion.**
+
+    @param[in] array  array to read from
+    @param[in] cb  a parser callback function of type @ref parser_callback_t
     which is used to control the deserialization by filtering unwanted values
     (optional)
 
@@ -5933,18 +5884,54 @@ class basic_json
 
     @note A UTF-8 byte order mark is silently ignored.
 
+    @liveexample{The example below demonstrates the `parse()` function reading
+    from an array.,parse__array__parser_callback_t}
+
+    @since version 2.0.3
+    */
+    template<class T, std::size_t N>
+    static basic_json parse(T (&array)[N],
+                            const parser_callback_t cb = nullptr)
+    {
+        // delegate the call to the iterator-range parse overload
+        return parse(std::begin(array), std::end(array), cb);
+    }
+
+    /*!
+    @brief deserialize from string literal
+
+    @tparam CharT character/literal type with size of 1 byte
+    @param[in] s  string literal to read a serialized JSON value from
+    @param[in] cb a parser callback function of type @ref parser_callback_t
+    which is used to control the deserialization by filtering unwanted values
+    (optional)
+
+    @return result of the deserialization
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser. The complexity can be higher if the parser callback function
+    @a cb has a super-linear complexity.
+
+    @note A UTF-8 byte order mark is silently ignored.
+    @note String containers like `std::string` or @ref string_t can be parsed
+          with @ref parse(const ContiguousContainer&, const parser_callback_t)
+
     @liveexample{The example below demonstrates the `parse()` function with
     and without callback function.,parse__string__parser_callback_t}
 
     @sa @ref parse(std::istream&, const parser_callback_t) for a version that
     reads from an input stream
 
-    @since version 1.0.0
+    @since version 1.0.0 (originally for @ref string_t)
     */
-    static basic_json parse(const string_t& s,
+    template<typename CharPT, typename std::enable_if<
+                 std::is_pointer<CharPT>::value and
+                 std::is_integral<typename std::remove_pointer<CharPT>::type>::value and
+                 sizeof(typename std::remove_pointer<CharPT>::type) == 1, int>::type = 0>
+    static basic_json parse(const CharPT s,
                             const parser_callback_t cb = nullptr)
     {
-        return parser(s, cb).parse();
+        return parser(reinterpret_cast<const char*>(s), cb).parse();
     }
 
     /*!
@@ -5966,7 +5953,7 @@ class basic_json
     @liveexample{The example below demonstrates the `parse()` function with
     and without callback function.,parse__istream__parser_callback_t}
 
-    @sa @ref parse(const string_t&, const parser_callback_t) for a version
+    @sa @ref parse(const char*, const parser_callback_t) for a version
     that reads from a string
 
     @since version 1.0.0
@@ -5986,6 +5973,130 @@ class basic_json
         return parser(i, cb).parse();
     }
 
+    /*!
+    @brief deserialize from an iterator range with contiguous storage
+
+    This function reads from an iterator range of a container with contiguous
+    storage of 1-byte values. Compatible container types include
+    `std::vector`, `std::string`, `std::array`, `std::valarray`, and
+    `std::initializer_list`. Furthermore, C-style arrays can be used with
+    `std::begin()`/`std::end()`. User-defined containers can be used as long
+    as they implement random-access iterators and a contiguous storage.
+
+    @pre The iterator range is contiguous. Violating this precondition yields
+    undefined behavior. **This precondition is enforced with an assertion.**
+    @pre Each element in the range has a size of 1 byte. Violating this
+    precondition yields undefined behavior. **This precondition is enforced
+    with a static assertion.**
+
+    @warning There is no way to enforce all preconditions at compile-time. If
+             the function is called with noncompliant iterators and with
+             assertions switched off, the behavior is undefined and will most
+             likely yield segmentation violation.
+
+    @tparam IteratorType iterator of container with contiguous storage
+    @param[in] first  begin of the range to parse (included)
+    @param[in] last  end of the range to parse (excluded)
+    @param[in] cb  a parser callback function of type @ref parser_callback_t
+    which is used to control the deserialization by filtering unwanted values
+    (optional)
+
+    @return result of the deserialization
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser. The complexity can be higher if the parser callback function
+    @a cb has a super-linear complexity.
+
+    @note A UTF-8 byte order mark is silently ignored.
+
+    @liveexample{The example below demonstrates the `parse()` function reading
+    from an iterator range.,parse__iteratortype__parser_callback_t}
+
+    @since version 2.0.3
+    */
+    template<class IteratorType, typename std::enable_if<
+                 std::is_base_of<
+                     std::random_access_iterator_tag,
+                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
+    static basic_json parse(IteratorType first, IteratorType last,
+                            const parser_callback_t cb = nullptr)
+    {
+        // assertion to check that the iterator range is indeed contiguous,
+        // see http://stackoverflow.com/a/35008842/266378 for more discussion
+        assert(std::accumulate(first, last, std::make_pair<bool, int>(true, 0),
+                               [&first](std::pair<bool, int> res, decltype(*first) val)
+        {
+            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
+            return res;
+        }).first);
+
+        // assertion to check that each element is 1 byte long
+        static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
+                      "each element in the iterator range must have the size of 1 byte");
+
+        // if iterator range is empty, create a parser with an empty string
+        // to generate "unexpected EOF" error message
+        if (std::distance(first, last) <= 0)
+        {
+            return parser("").parse();
+        }
+
+        return parser(first, last, cb).parse();
+    }
+
+    /*!
+    @brief deserialize from a container with contiguous storage
+
+    This function reads from a container with contiguous storage of 1-byte
+    values. Compatible container types include `std::vector`, `std::string`,
+    `std::array`, and `std::initializer_list`. User-defined containers can be
+    used as long as they implement random-access iterators and a contiguous
+    storage.
+
+    @pre The container storage is contiguous. Violating this precondition
+    yields undefined behavior. **This precondition is enforced with an
+    assertion.**
+    @pre Each element of the container has a size of 1 byte. Violating this
+    precondition yields undefined behavior. **This precondition is enforced
+    with a static assertion.**
+
+    @warning There is no way to enforce all preconditions at compile-time. If
+             the function is called with a noncompliant container and with
+             assertions switched off, the behavior is undefined and will most
+             likely yield segmentation violation.
+
+    @tparam ContiguousContainer container type with contiguous storage
+    @param[in] c  container to read from
+    @param[in] cb  a parser callback function of type @ref parser_callback_t
+    which is used to control the deserialization by filtering unwanted values
+    (optional)
+
+    @return result of the deserialization
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser. The complexity can be higher if the parser callback function
+    @a cb has a super-linear complexity.
+
+    @note A UTF-8 byte order mark is silently ignored.
+
+    @liveexample{The example below demonstrates the `parse()` function reading
+    from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
+
+    @since version 2.0.3
+    */
+    template<class ContiguousContainer, typename std::enable_if<
+                 not std::is_pointer<ContiguousContainer>::value and
+                 std::is_base_of<
+                     std::random_access_iterator_tag,
+                     typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value
+                 , int>::type = 0>
+    static basic_json parse(const ContiguousContainer& c,
+                            const parser_callback_t cb = nullptr)
+    {
+        // delegate the call to the iterator-range parse overload
+        return parse(std::begin(c), std::end(c), cb);
+    }
+
     /*!
     @brief deserialize from stream
 
@@ -6039,7 +6150,7 @@ class basic_json
     Returns the type name as string to be used in error messages - usually to
     indicate that a function was called on a wrong JSON type.
 
-    @return basically a string representation of a the @ref m_type member
+    @return basically a string representation of a the @a m_type member
 
     @complexity Constant.
 
@@ -7490,32 +7601,25 @@ class basic_json
         /// the char type to use in the lexer
         using lexer_char_t = unsigned char;
 
-        /// constructor with a given buffer
-        explicit lexer(const string_t& s) noexcept
-            : m_stream(nullptr), m_buffer(s)
+        /// a lexer from a buffer with given length
+        lexer(const lexer_char_t* buff, const size_t len) noexcept
+            : m_content(buff)
         {
-            m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
             assert(m_content != nullptr);
             m_start = m_cursor = m_content;
-            m_limit = m_content + s.size();
+            m_limit = m_content + len;
         }
 
-        /// constructor with a given stream
-        explicit lexer(std::istream* s) noexcept
-            : m_stream(s), m_buffer()
+        /// a lexer from an input stream
+        explicit lexer(std::istream& s)
+            : m_stream(&s), m_line_buffer()
         {
-            assert(m_stream != nullptr);
-            std::getline(*m_stream, m_buffer);
-            m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
-            assert(m_content != nullptr);
-            m_start = m_cursor = m_content;
-            m_limit = m_content + m_buffer.size();
+            // fill buffer
+            fill_line_buffer();
         }
 
-        /// default constructor
-        lexer() = default;
-
-        // switch off unwanted functions
+        // switch off unwanted functions (due to pointer members)
+        lexer() = delete;
         lexer(const lexer&) = delete;
         lexer operator=(const lexer&) = delete;
 
@@ -7668,7 +7772,7 @@ class basic_json
         infinite sequence of whitespace or byte-order-marks. This contradicts
         the assumption of finite input, q.e.d.
         */
-        token_type scan() noexcept
+        token_type scan()
         {
             while (true)
             {
@@ -7684,7 +7788,7 @@ class basic_json
                     re2c:define:YYCURSOR  = m_cursor;
                     re2c:define:YYLIMIT   = m_limit;
                     re2c:define:YYMARKER  = m_marker;
-                    re2c:define:YYFILL    = "yyfill()";
+                    re2c:define:YYFILL    = "fill_line_buffer()";
                     re2c:yyfill:parameter = 0;
                     re2c:indent:string    = "    ";
                     re2c:indent:top       = 1;
@@ -7747,30 +7851,76 @@ class basic_json
             return last_token_type;
         }
 
-        /// append data from the stream to the internal buffer
-        void yyfill() noexcept
-        {
-            if (m_stream == nullptr or not * m_stream)
-            {
-                return;
-            }
+        /*!
+        @brief append data from the stream to the line buffer
 
+        This function is called by the scan() function when the end of the
+        buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be
+        incremented without leaving the limits of the line buffer. Note re2c
+        decides when to call this function.
+
+        If the lexer reads from contiguous storage, there is no trailing null
+        byte. Therefore, this function must make sure to add these padding
+        null bytes.
+
+        If the lexer reads from an input stream, this function reads the next
+        line of the input.
+
+        @pre
+            p p p p p p u u u u u x . . . . . .
+            ^           ^       ^   ^
+            m_content   m_start |   m_limit
+                                m_cursor
+
+        @post
+            u u u u u x x x x x x x . . . . . .
+            ^       ^               ^
+            |       m_cursor        m_limit
+            m_start
+            m_content
+        */
+        void fill_line_buffer()
+        {
+            // number of processed characters (p)
             const auto offset_start = m_start - m_content;
-            const auto offset_marker = m_marker - m_start;
+            // offset for m_marker wrt. to m_start
+            const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
+            // number of unprocessed characters (u)
             const auto offset_cursor = m_cursor - m_start;
 
-            m_buffer.erase(0, static_cast<size_t>(offset_start));
-            std::string line;
-            assert(m_stream != nullptr);
-            std::getline(*m_stream, line);
-            m_buffer += "\n" + line; // add line with newline symbol
+            // no stream is used or end of file is reached
+            if (m_stream == nullptr or not * m_stream)
+            {
+                // copy unprocessed characters to line buffer
+                m_line_buffer.clear();
+                for (m_cursor = m_start; m_cursor != m_limit; ++m_cursor)
+                {
+                    m_line_buffer.append(1, static_cast<const char>(*m_cursor));
+                }
 
-            m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
+                // append 5 characters (size of longest keyword "false") to
+                // make sure that there is sufficient space between m_cursor
+                // and m_limit
+                m_line_buffer.append(5, '\0');
+            }
+            else
+            {
+                // delete processed characters from line buffer
+                m_line_buffer.erase(0, static_cast<size_t>(offset_start));
+                // read next line from input stream
+                std::string line;
+                std::getline(*m_stream, line);
+                // add line with newline symbol to the line buffer
+                m_line_buffer += "\n" + line;
+            }
+
+            // set pointers
+            m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.c_str());
             assert(m_content != nullptr);
             m_start  = m_content;
             m_marker = m_start + offset_marker;
             m_cursor = m_start + offset_cursor;
-            m_limit  = m_start + m_buffer.size() - 1;
+            m_limit  = m_start + m_line_buffer.size();
         }
 
         /// return string representation of last read token
@@ -8112,8 +8262,8 @@ class basic_json
       private:
         /// optional input stream
         std::istream* m_stream = nullptr;
-        /// the buffer
-        string_t m_buffer;
+        /// line buffer buffer for m_stream
+        string_t m_line_buffer {};
         /// the buffer pointer
         const lexer_char_t* m_content = nullptr;
         /// pointer to the beginning of the current symbol
@@ -8136,25 +8286,34 @@ class basic_json
     class parser
     {
       public:
-        /// constructor for strings
-        parser(const string_t& s, const parser_callback_t cb = nullptr) noexcept
-            : callback(cb), m_lexer(s)
-        {
-            // read first token
-            get_token();
-        }
+        /// a parser reading from a string literal
+        parser(const char* buff, const parser_callback_t cb = nullptr)
+            : callback(cb),
+              m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), strlen(buff))
+        {}
 
         /// a parser reading from an input stream
-        parser(std::istream& _is, const parser_callback_t cb = nullptr) noexcept
-            : callback(cb), m_lexer(&_is)
-        {
-            // read first token
-            get_token();
-        }
+        parser(std::istream& is, const parser_callback_t cb = nullptr)
+            : callback(cb), m_lexer(is)
+        {}
+
+        /// a parser reading from an iterator range with contiguous storage
+        template<class IteratorType, typename std::enable_if<
+                     std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
+                     , int>::type
+                 = 0>
+        parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr)
+            : callback(cb),
+              m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)),
+                      static_cast<size_t>(std::distance(first, last)))
+        {}
 
         /// public parser interface
         basic_json parse()
         {
+            // read first token
+            get_token();
+
             basic_json result = parse_internal(true);
             result.assert_invariant();
 
@@ -8361,7 +8520,7 @@ class basic_json
         }
 
         /// get next token from lexer
-        typename lexer::token_type get_token() noexcept
+        typename lexer::token_type get_token()
         {
             last_token = m_lexer.scan();
             return last_token;
@@ -9659,7 +9818,7 @@ namespace std
 
 @since version 1.0.0
 */
-template <>
+template<>
 inline void swap(nlohmann::json& j1,
                  nlohmann::json& j2) noexcept(
                      is_nothrow_move_constructible<nlohmann::json>::value and
@@ -9670,7 +9829,7 @@ inline void swap(nlohmann::json& j1,
 }
 
 /// hash value for JSON objects
-template <>
+template<>
 struct hash<nlohmann::json>
 {
     /*!
@@ -9701,7 +9860,7 @@ if no parse error occurred.
 */
 inline nlohmann::json operator "" _json(const char* s, std::size_t)
 {
-    return nlohmann::json::parse(reinterpret_cast<const nlohmann::json::string_t::value_type*>(s));
+    return nlohmann::json::parse(s);
 }
 
 /*!
diff --git a/test/src/unit-class_lexer.cpp b/test/src/unit-class_lexer.cpp
index 708a8cbf..7cece21c 100644
--- a/test/src/unit-class_lexer.cpp
+++ b/test/src/unit-class_lexer.cpp
@@ -38,43 +38,67 @@ TEST_CASE("lexer class")
     {
         SECTION("structural characters")
         {
-            CHECK(json::lexer("[").scan() == json::lexer::token_type::begin_array);
-            CHECK(json::lexer("]").scan() == json::lexer::token_type::end_array);
-            CHECK(json::lexer("{").scan() == json::lexer::token_type::begin_object);
-            CHECK(json::lexer("}").scan() == json::lexer::token_type::end_object);
-            CHECK(json::lexer(",").scan() == json::lexer::token_type::value_separator);
-            CHECK(json::lexer(":").scan() == json::lexer::token_type::name_separator);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("["),
+                              1).scan() == json::lexer::token_type::begin_array);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("]"),
+                              1).scan() == json::lexer::token_type::end_array);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("{"),
+                              1).scan() == json::lexer::token_type::begin_object);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("}"),
+                              1).scan() == json::lexer::token_type::end_object);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(","),
+                              1).scan() == json::lexer::token_type::value_separator);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(":"),
+                              1).scan() == json::lexer::token_type::name_separator);
         }
 
         SECTION("literal names")
         {
-            CHECK(json::lexer("null").scan() == json::lexer::token_type::literal_null);
-            CHECK(json::lexer("true").scan() == json::lexer::token_type::literal_true);
-            CHECK(json::lexer("false").scan() == json::lexer::token_type::literal_false);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("null"),
+                              4).scan() == json::lexer::token_type::literal_null);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("true"),
+                              4).scan() == json::lexer::token_type::literal_true);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("false"),
+                              5).scan() == json::lexer::token_type::literal_false);
         }
 
         SECTION("numbers")
         {
-            CHECK(json::lexer("0").scan() == json::lexer::token_type::value_number);
-            CHECK(json::lexer("1").scan() == json::lexer::token_type::value_number);
-            CHECK(json::lexer("2").scan() == json::lexer::token_type::value_number);
-            CHECK(json::lexer("3").scan() == json::lexer::token_type::value_number);
-            CHECK(json::lexer("4").scan() == json::lexer::token_type::value_number);
-            CHECK(json::lexer("5").scan() == json::lexer::token_type::value_number);
-            CHECK(json::lexer("6").scan() == json::lexer::token_type::value_number);
-            CHECK(json::lexer("7").scan() == json::lexer::token_type::value_number);
-            CHECK(json::lexer("8").scan() == json::lexer::token_type::value_number);
-            CHECK(json::lexer("9").scan() == json::lexer::token_type::value_number);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("0"),
+                              1).scan() == json::lexer::token_type::value_number);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("1"),
+                              1).scan() == json::lexer::token_type::value_number);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("2"),
+                              1).scan() == json::lexer::token_type::value_number);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("3"),
+                              1).scan() == json::lexer::token_type::value_number);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("4"),
+                              1).scan() == json::lexer::token_type::value_number);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("5"),
+                              1).scan() == json::lexer::token_type::value_number);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("6"),
+                              1).scan() == json::lexer::token_type::value_number);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("7"),
+                              1).scan() == json::lexer::token_type::value_number);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("8"),
+                              1).scan() == json::lexer::token_type::value_number);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("9"),
+                              1).scan() == json::lexer::token_type::value_number);
         }
 
         SECTION("whitespace")
         {
             // result is end_of_input, because not token is following
-            CHECK(json::lexer(" ").scan() == json::lexer::token_type::end_of_input);
-            CHECK(json::lexer("\t").scan() == json::lexer::token_type::end_of_input);
-            CHECK(json::lexer("\n").scan() == json::lexer::token_type::end_of_input);
-            CHECK(json::lexer("\r").scan() == json::lexer::token_type::end_of_input);
-            CHECK(json::lexer(" \t\n\r\n\t ").scan() == json::lexer::token_type::end_of_input);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(" "),
+                              1).scan() == json::lexer::token_type::end_of_input);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("\t"),
+                              1).scan() == json::lexer::token_type::end_of_input);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("\n"),
+                              1).scan() == json::lexer::token_type::end_of_input);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("\r"),
+                              1).scan() == json::lexer::token_type::end_of_input);
+            CHECK(json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(" \t\n\r\n\t "),
+                              7).scan() == json::lexer::token_type::end_of_input);
         }
     }
 
@@ -100,7 +124,11 @@ TEST_CASE("lexer class")
     {
         for (int c = 1; c < 128; ++c)
         {
-            auto s = std::string(1, c);
+            // create string from the ASCII code
+            const auto s = std::string(1, c);
+            // store scan() result
+            const auto res = json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(s.c_str()),
+                                         1).scan();
 
             switch (c)
             {
@@ -122,7 +150,7 @@ TEST_CASE("lexer class")
                 case ('8'):
                 case ('9'):
                 {
-                    CHECK(json::lexer(s.c_str()).scan() != json::lexer::token_type::parse_error);
+                    CHECK(res != json::lexer::token_type::parse_error);
                     break;
                 }
 
@@ -132,14 +160,14 @@ TEST_CASE("lexer class")
                 case ('\n'):
                 case ('\r'):
                 {
-                    CHECK(json::lexer(s.c_str()).scan() == json::lexer::token_type::end_of_input);
+                    CHECK(res == json::lexer::token_type::end_of_input);
                     break;
                 }
 
                 // anything else is not expected
                 default:
                 {
-                    CHECK(json::lexer(s.c_str()).scan() == json::lexer::token_type::parse_error);
+                    CHECK(res == json::lexer::token_type::parse_error);
                     break;
                 }
             }
diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp
index 259daf84..6fcf947d 100644
--- a/test/src/unit-class_parser.cpp
+++ b/test/src/unit-class_parser.cpp
@@ -32,6 +32,8 @@ SOFTWARE.
 #include "json.hpp"
 using nlohmann::json;
 
+#include <valarray>
+
 TEST_CASE("parser class")
 {
     SECTION("parse")
@@ -487,7 +489,7 @@ TEST_CASE("parser class")
                 case ('r'):
                 case ('t'):
                 {
-                    CHECK_NOTHROW(json::parser(s).parse());
+                    CHECK_NOTHROW(json::parser(s.c_str()).parse());
                     break;
                 }
 
@@ -500,8 +502,8 @@ TEST_CASE("parser class")
                 // any other combination of backslash and character is invalid
                 default:
                 {
-                    CHECK_THROWS_AS(json::parser(s).parse(), std::invalid_argument);
-                    CHECK_THROWS_WITH(json::parser(s).parse(), "parse error - unexpected '\"'");
+                    CHECK_THROWS_AS(json::parser(s.c_str()).parse(), std::invalid_argument);
+                    CHECK_THROWS_WITH(json::parser(s.c_str()).parse(), "parse error - unexpected '\"'");
                     break;
                 }
             }
@@ -559,22 +561,22 @@ TEST_CASE("parser class")
 
                 if (valid(c))
                 {
-                    CHECK_NOTHROW(json::parser(s1).parse());
-                    CHECK_NOTHROW(json::parser(s2).parse());
-                    CHECK_NOTHROW(json::parser(s3).parse());
-                    CHECK_NOTHROW(json::parser(s4).parse());
+                    CHECK_NOTHROW(json::parser(s1.c_str()).parse());
+                    CHECK_NOTHROW(json::parser(s2.c_str()).parse());
+                    CHECK_NOTHROW(json::parser(s3.c_str()).parse());
+                    CHECK_NOTHROW(json::parser(s4.c_str()).parse());
                 }
                 else
                 {
-                    CHECK_THROWS_AS(json::parser(s1).parse(), std::invalid_argument);
-                    CHECK_THROWS_AS(json::parser(s2).parse(), std::invalid_argument);
-                    CHECK_THROWS_AS(json::parser(s3).parse(), std::invalid_argument);
-                    CHECK_THROWS_AS(json::parser(s4).parse(), std::invalid_argument);
+                    CHECK_THROWS_AS(json::parser(s1.c_str()).parse(), std::invalid_argument);
+                    CHECK_THROWS_AS(json::parser(s2.c_str()).parse(), std::invalid_argument);
+                    CHECK_THROWS_AS(json::parser(s3.c_str()).parse(), std::invalid_argument);
+                    CHECK_THROWS_AS(json::parser(s4.c_str()).parse(), std::invalid_argument);
 
-                    CHECK_THROWS_WITH(json::parser(s1).parse(), "parse error - unexpected '\"'");
-                    CHECK_THROWS_WITH(json::parser(s2).parse(), "parse error - unexpected '\"'");
-                    CHECK_THROWS_WITH(json::parser(s3).parse(), "parse error - unexpected '\"'");
-                    CHECK_THROWS_WITH(json::parser(s4).parse(), "parse error - unexpected '\"'");
+                    CHECK_THROWS_WITH(json::parser(s1.c_str()).parse(), "parse error - unexpected '\"'");
+                    CHECK_THROWS_WITH(json::parser(s2.c_str()).parse(), "parse error - unexpected '\"'");
+                    CHECK_THROWS_WITH(json::parser(s3.c_str()).parse(), "parse error - unexpected '\"'");
+                    CHECK_THROWS_WITH(json::parser(s4.c_str()).parse(), "parse error - unexpected '\"'");
                 }
             }
         }
@@ -755,11 +757,47 @@ TEST_CASE("parser class")
         }
     }
 
-    SECTION("copy constructor")
+    SECTION("constructing from contiguous containers")
     {
-        json::string_t* s = new json::string_t("[1,2,3,4]");
-        json::parser p(*s);
-        delete s;
-        CHECK(p.parse() == json({1, 2, 3, 4}));
+        SECTION("from std::vector")
+        {
+            std::vector<uint8_t> v = {'t', 'r', 'u', 'e'};
+            CHECK(json::parser(std::begin(v), std::end(v)).parse() == json(true));
+        }
+
+        SECTION("from std::array")
+        {
+            std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} };
+            CHECK(json::parser(std::begin(v), std::end(v)).parse() == json(true));
+        }
+
+        SECTION("from array")
+        {
+            uint8_t v[] = {'t', 'r', 'u', 'e'};
+            CHECK(json::parser(std::begin(v), std::end(v)).parse() == json(true));
+        }
+
+        SECTION("from char literal")
+        {
+            CHECK(json::parser("true").parse() == json(true));
+        }
+
+        SECTION("from std::string")
+        {
+            std::string v = {'t', 'r', 'u', 'e'};
+            CHECK(json::parser(std::begin(v), std::end(v)).parse() == json(true));
+        }
+
+        SECTION("from std::initializer_list")
+        {
+            std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'};
+            CHECK(json::parser(std::begin(v), std::end(v)).parse() == json(true));
+        }
+
+        SECTION("from std::valarray")
+        {
+            std::valarray<uint8_t> v = {'t', 'r', 'u', 'e'};
+            CHECK(json::parser(std::begin(v), std::end(v)).parse() == json(true));
+        }
     }
 }
diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp
index 9d4c064f..d9463213 100644
--- a/test/src/unit-deserialization.cpp
+++ b/test/src/unit-deserialization.cpp
@@ -31,6 +31,8 @@ SOFTWARE.
 #include "json.hpp"
 using nlohmann::json;
 
+#include <valarray>
+
 TEST_CASE("deserialization")
 {
     SECTION("successful deserialization")
@@ -43,7 +45,14 @@ TEST_CASE("deserialization")
             CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
         }
 
-        SECTION("string")
+        SECTION("string literal")
+        {
+            auto s = "[\"foo\",1,2,3,false,{\"one\":1}]";
+            json j = json::parse(s);
+            CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
+        }
+
+        SECTION("string_t")
         {
             json::string_t s = "[\"foo\",1,2,3,false,{\"one\":1}]";
             json j = json::parse(s);
@@ -74,7 +83,7 @@ TEST_CASE("deserialization")
         }
     }
 
-    SECTION("successful deserialization")
+    SECTION("unsuccessful deserialization")
     {
         SECTION("stream")
         {
@@ -116,4 +125,103 @@ TEST_CASE("deserialization")
                               "parse error - unexpected end of input; expected ']'");
         }
     }
+
+    SECTION("contiguous containers")
+    {
+        SECTION("directly")
+        {
+            SECTION("from std::vector")
+            {
+                std::vector<uint8_t> v = {'t', 'r', 'u', 'e'};
+                CHECK(json::parse(v) == json(true));
+            }
+
+            SECTION("from std::array")
+            {
+                std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} };
+                CHECK(json::parse(v) == json(true));
+            }
+
+            SECTION("from array")
+            {
+                uint8_t v[] = {'t', 'r', 'u', 'e'};
+                CHECK(json::parse(v) == json(true));
+            }
+
+            SECTION("from chars")
+            {
+                uint8_t *v = new uint8_t[5];
+                v[0] = 't';
+                v[1] = 'r';
+                v[2] = 'u';
+                v[3] = 'e';
+                v[4] = '\0';
+                CHECK(json::parse(v) == json(true));
+                delete[] v;
+            }
+
+            SECTION("from std::string")
+            {
+                std::string v = {'t', 'r', 'u', 'e'};
+                CHECK(json::parse(v) == json(true));
+            }
+
+            SECTION("from std::initializer_list")
+            {
+                std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'};
+                CHECK(json::parse(v) == json(true));
+            }
+
+            SECTION("empty container")
+            {
+                std::vector<uint8_t> v;
+                CHECK_THROWS_AS(json::parse(v), std::invalid_argument);
+            }
+        }
+
+        SECTION("via iterator range")
+        {
+            SECTION("from std::vector")
+            {
+                std::vector<uint8_t> v = {'t', 'r', 'u', 'e'};
+                CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
+            }
+
+            SECTION("from std::array")
+            {
+                std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} };
+                CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
+            }
+
+            SECTION("from array")
+            {
+                uint8_t v[] = {'t', 'r', 'u', 'e'};
+                CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
+            }
+
+            SECTION("from std::string")
+            {
+                std::string v = {'t', 'r', 'u', 'e'};
+                CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
+            }
+
+            SECTION("from std::initializer_list")
+            {
+                std::initializer_list<uint8_t> v = {'t', 'r', 'u', 'e'};
+                CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
+            }
+
+            SECTION("from std::valarray")
+            {
+                std::valarray<uint8_t> v = {'t', 'r', 'u', 'e'};
+                CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
+            }
+
+            SECTION("with empty range")
+            {
+                std::vector<uint8_t> v;
+                CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), std::invalid_argument);
+            }
+        }
+    }
 }