diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0ed56e67..54e4fa72 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,7 @@
Version 78:
+* Add span
+
HTTP:
* Tidy up basic_string_body
diff --git a/doc/quickref.xml b/doc/quickref.xml
index 7d80de55..d49491ba 100644
--- a/doc/quickref.xml
+++ b/doc/quickref.xml
@@ -192,6 +192,7 @@
iequal
iless
multi_buffer
+ span
static_buffer
static_buffer_n
static_string
diff --git a/include/beast/core.hpp b/include/beast/core.hpp
index 1a1c49c6..9e63e6df 100644
--- a/include/beast/core.hpp
+++ b/include/beast/core.hpp
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/include/beast/core/detail/type_traits.hpp b/include/beast/core/detail/type_traits.hpp
index f80f6fe4..e375b976 100644
--- a/include/beast/core/detail/type_traits.hpp
+++ b/include/beast/core/detail/type_traits.hpp
@@ -138,6 +138,28 @@ struct is_invocable
};
/** @} */
+// for span
+template
+struct is_contiguous_container: std::false_type {};
+
+template
+struct is_contiguous_container() = std::declval().size(),
+ std::declval() = std::declval().data(),
+ (void)0),
+ typename std::enable_if<
+ std::is_same<
+ typename std::remove_cv::type,
+ typename std::remove_cv<
+ typename std::remove_pointer<
+ decltype(std::declval().data())
+ >::type
+ >::type
+ >::value
+ >::type>>: std::true_type
+{};
+
//------------------------------------------------------------------------------
//
diff --git a/include/beast/core/span.hpp b/include/beast/core/span.hpp
new file mode 100644
index 00000000..d6998ea8
--- /dev/null
+++ b/include/beast/core/span.hpp
@@ -0,0 +1,211 @@
+//
+// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BEAST_CORE_SPAN_HPP
+#define BEAST_CORE_SPAN_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+
+/** A range of bytes expressed as a ContiguousContainer
+
+ This class implements a non-owning reference to a storage
+ area of a certain size and having an underlying integral
+ type with size of 1.
+
+ @tparam T The type pointed to by span iterators
+*/
+template
+class span
+{
+ T* data_ = nullptr;
+ std::size_t size_ = 0;
+
+public:
+ /// The type of value, including cv qualifiers
+ using element_type = T;
+
+ /// The type of value of each span element
+ using value_type = typename std::remove_const::type;
+
+ /// The type of integer used to index the span
+ using index_type = std::ptrdiff_t;
+
+ /// A pointer to a span element
+ using pointer = T*;
+
+ /// A reference to a span element
+ using reference = T&;
+
+ /// The iterator used by the container
+ using iterator = pointer;
+
+ /// The const pointer used by the container
+ using const_pointer = T const*;
+
+ /// The const reference used by the container
+ using const_reference = T const&;
+
+ /// The const iterator used by the container
+ using const_iterator = const_pointer;
+
+ /// Constructor
+ span() = default;
+
+ /// Constructor
+ span(span const&) = default;
+
+ /// Assignment
+ span& operator=(span const&) = default;
+
+ /** Constructor
+
+ @param data A pointer to the beginning of the range of elements
+
+ @param size The number of elements pointed to by `data`
+ */
+ span(T* data, std::size_t size)
+ : data_(data), size_(size)
+ {
+ }
+
+ /** Constructor
+
+ @param container The container to construct from
+ */
+ template::value>::type
+#endif
+ >
+ explicit
+ span(ContiguousContainer&& container)
+ : data_(container.data())
+ , size_(container.size())
+ {
+ }
+
+#if ! BEAST_DOXYGEN
+ template
+ explicit
+ span(std::basic_string& s)
+ : data_(&s[0])
+ , size_(s.size())
+ {
+ }
+
+ template
+ explicit
+ span(std::basic_string const& s)
+ : data_(s.data())
+ , size_(s.size())
+ {
+ }
+#endif
+
+ /** Assignment
+
+ @param container The container to assign from
+ */
+ template
+#if BEAST_DOXYGEN
+ span&
+#else
+ typename std::enable_if::value,
+ span&>::type
+#endif
+ operator=(ContiguousContainer&& container)
+ {
+ data_ = container.data();
+ size_ = container.size();
+ return *this;
+ }
+
+#if ! BEAST_DOXYGEN
+ template
+ span&
+ operator=(std::basic_string<
+ CharT, Traits, Allocator>& s)
+ {
+ data_ = &s[0];
+ size_ = s.size();
+ return *this;
+ }
+
+ template
+ span&
+ operator=(std::basic_string<
+ CharT, Traits, Allocator> const& s)
+ {
+ data_ = s.data();
+ size_ = s.size();
+ return *this;
+ }
+#endif
+
+ /// Returns `true` if the span is empty
+ bool
+ empty() const
+ {
+ return size_ == 0;
+ }
+
+ /// Returns a pointer to the beginning of the span
+ T*
+ data() const
+ {
+ return data_;
+ }
+
+ /// Returns the number of elements in the span
+ std::size_t
+ size() const
+ {
+ return size_;
+ }
+
+ /// Returns an iterator to the beginning of the span
+ const_iterator
+ begin() const
+ {
+ return data_;
+ }
+
+ /// Returns an iterator to the beginning of the span
+ const_iterator
+ cbegin() const
+ {
+ return data_;
+ }
+
+ /// Returns an iterator to one past the end of the span
+ const_iterator
+ end() const
+ {
+ return data_ + size_;
+ }
+
+ /// Returns an iterator to one past the end of the span
+ const_iterator
+ cend() const
+ {
+ return data_ + size_;
+ }
+};
+
+} // beast
+
+#endif
diff --git a/test/core/CMakeLists.txt b/test/core/CMakeLists.txt
index 595032bc..39749c57 100644
--- a/test/core/CMakeLists.txt
+++ b/test/core/CMakeLists.txt
@@ -35,6 +35,7 @@ add_executable (core-tests
multi_buffer.cpp
ostream.cpp
read_size.cpp
+ span.cpp
static_buffer.cpp
static_string.cpp
string.cpp
diff --git a/test/core/Jamfile b/test/core/Jamfile
index 52218baa..159b7ae5 100644
--- a/test/core/Jamfile
+++ b/test/core/Jamfile
@@ -29,6 +29,7 @@ unit-test core-tests :
multi_buffer.cpp
ostream.cpp
read_size.cpp
+ span.cpp
static_buffer.cpp
static_string.cpp
string.cpp
diff --git a/test/core/span.cpp b/test/core/span.cpp
new file mode 100644
index 00000000..32892de3
--- /dev/null
+++ b/test/core/span.cpp
@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// Test that header file is self-contained.
+#include
+
+#include
+
+namespace beast {
+
+class span_test : public beast::unit_test::suite
+{
+public:
+ struct base {};
+ struct derived : base {};
+
+ BOOST_STATIC_ASSERT(detail::is_contiguous_container<
+ std::vector, char>::value);
+
+ BOOST_STATIC_ASSERT(detail::is_contiguous_container<
+ std::vector, char const>::value);
+
+ BOOST_STATIC_ASSERT(! detail::is_contiguous_container<
+ std::vector, base>::value);
+
+ BOOST_STATIC_ASSERT(! detail::is_contiguous_container<
+ std::vector, base const>::value);
+
+ void
+ testSpan()
+ {
+ span sp{"hello", 5};
+ BEAST_EXPECT(sp.size() == 5);
+ std::string s("world");
+ sp = s;
+ }
+
+ void
+ run() override
+ {
+ testSpan();
+ }
+};
+
+BEAST_DEFINE_TESTSUITE(span,core,beast);
+
+} // beast