commit 599e39ef74f251e93e4a45f35765e685abe960e2 from: Aleksey Ryndin date: Mon Aug 14 08:21:10 2023 UTC Re-implement `span` commit - 6e84684c10bd5da2b1e7d4637888f1fa27a4d7c5 commit + 599e39ef74f251e93e4a45f35765e685abe960e2 blob - fdc3a988a4c2ec5322deee7dc8fc3955f2ccb995 (mode 644) blob + /dev/null --- shared/span.hpp +++ /dev/null @@ -1,618 +0,0 @@ - -/* -This is an implementation of C++20's std::span -http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4820.pdf -*/ - -// Copyright Tristan Brindle 2018. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file ../../LICENSE_1_0.txt or copy at -// https://www.boost.org/LICENSE_1_0.txt) - -#ifndef TCB_SPAN_HPP_INCLUDED -#define TCB_SPAN_HPP_INCLUDED - -#include -#include -#include -#include - -#ifndef TCB_SPAN_NO_EXCEPTIONS -// Attempt to discover whether we're being compiled with exception support -#if !(defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) -#define TCB_SPAN_NO_EXCEPTIONS -#endif -#endif - -#ifndef TCB_SPAN_NO_EXCEPTIONS -#include -#include -#endif - -// Various feature test macros - -#ifndef TCB_SPAN_NAMESPACE_NAME -#define TCB_SPAN_NAMESPACE_NAME tcb -#endif - -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -#define TCB_SPAN_HAVE_CPP17 -#endif - -#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) -#define TCB_SPAN_HAVE_CPP14 -#endif - -namespace TCB_SPAN_NAMESPACE_NAME { - -// Establish default contract checking behavior -#if !defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION) && \ - !defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION) && \ - !defined(TCB_SPAN_NO_CONTRACT_CHECKING) -#if defined(NDEBUG) || !defined(TCB_SPAN_HAVE_CPP14) -#define TCB_SPAN_NO_CONTRACT_CHECKING -#else -#define TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION -#endif -#endif - -#if defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION) -struct contract_violation_error : std::logic_error { - explicit contract_violation_error(const char* msg) : std::logic_error(msg) - {} -}; - -inline void contract_violation(const char* msg) -{ - throw contract_violation_error(msg); -} - -#elif defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION) -[[noreturn]] inline void contract_violation(const char* /*unused*/) -{ - std::terminate(); -} -#endif - -#if !defined(TCB_SPAN_NO_CONTRACT_CHECKING) -#define TCB_SPAN_STRINGIFY(cond) #cond -#define TCB_SPAN_EXPECT(cond) \ - cond ? (void) 0 : contract_violation("Expected " TCB_SPAN_STRINGIFY(cond)) -#else -#define TCB_SPAN_EXPECT(cond) -#endif - -#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_inline_variables) -#define TCB_SPAN_INLINE_VAR inline -#else -#define TCB_SPAN_INLINE_VAR -#endif - -#if defined(TCB_SPAN_HAVE_CPP14) || \ - (defined(__cpp_constexpr) && __cpp_constexpr >= 201304) -#define TCB_SPAN_HAVE_CPP14_CONSTEXPR -#endif - -#if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR) -#define TCB_SPAN_CONSTEXPR14 constexpr -#else -#define TCB_SPAN_CONSTEXPR14 -#endif - -#if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR) && \ - (!defined(_MSC_VER) || _MSC_VER > 1900) -#define TCB_SPAN_CONSTEXPR_ASSIGN constexpr -#else -#define TCB_SPAN_CONSTEXPR_ASSIGN -#endif - -#if defined(TCB_SPAN_NO_CONTRACT_CHECKING) -#define TCB_SPAN_CONSTEXPR11 constexpr -#else -#define TCB_SPAN_CONSTEXPR11 TCB_SPAN_CONSTEXPR14 -#endif - -#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_deduction_guides) -#define TCB_SPAN_HAVE_DEDUCTION_GUIDES -#endif - -#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_byte) -#define TCB_SPAN_HAVE_STD_BYTE -#endif - -#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_array_constexpr) -#define TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC -#endif - -#if defined(TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC) -#define TCB_SPAN_ARRAY_CONSTEXPR constexpr -#else -#define TCB_SPAN_ARRAY_CONSTEXPR -#endif - -#ifdef TCB_SPAN_HAVE_STD_BYTE -using byte = std::byte; -#else -using byte = unsigned char; -#endif - -#if defined(TCB_SPAN_HAVE_CPP17) -#define TCB_SPAN_NODISCARD [[nodiscard]] -#else -#define TCB_SPAN_NODISCARD -#endif - -TCB_SPAN_INLINE_VAR constexpr std::size_t dynamic_extent = SIZE_MAX; - -template -class span; - -namespace detail { - -template -struct span_storage { - constexpr span_storage() noexcept = default; - - constexpr span_storage(E* p_ptr, std::size_t /*unused*/) noexcept - : ptr(p_ptr) - {} - - E* ptr = nullptr; - static constexpr std::size_t size = S; -}; - -template -struct span_storage { - constexpr span_storage() noexcept = default; - - constexpr span_storage(E* p_ptr, std::size_t p_size) noexcept - : ptr(p_ptr), size(p_size) - {} - - E* ptr = nullptr; - std::size_t size = 0; -}; - -// Reimplementation of C++17 std::size() and std::data() -#if defined(TCB_SPAN_HAVE_CPP17) || \ - defined(__cpp_lib_nonmember_container_access) -using std::data; -using std::size; -#else -template -constexpr auto size(const C& c) -> decltype(c.size()) -{ - return c.size(); -} - -template -constexpr std::size_t size(const T (&)[N]) noexcept -{ - return N; -} - -template -constexpr auto data(C& c) -> decltype(c.data()) -{ - return c.data(); -} - -template -constexpr auto data(const C& c) -> decltype(c.data()) -{ - return c.data(); -} - -template -constexpr T* data(T (&array)[N]) noexcept -{ - return array; -} - -template -constexpr const E* data(std::initializer_list il) noexcept -{ - return il.begin(); -} -#endif // TCB_SPAN_HAVE_CPP17 - -#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_void_t) -using std::void_t; -#else -template -using void_t = void; -#endif - -template -using uncvref_t = - typename std::remove_cv::type>::type; - -template -struct is_span : std::false_type {}; - -template -struct is_span> : std::true_type {}; - -template -struct is_std_array : std::false_type {}; - -template -struct is_std_array> : std::true_type {}; - -template -struct has_size_and_data : std::false_type {}; - -template -struct has_size_and_data())), - decltype(detail::data(std::declval()))>> - : std::true_type {}; - -template > -struct is_container { - static constexpr bool value = - !is_span::value && !is_std_array::value && - !std::is_array::value && has_size_and_data::value; -}; - -template -using remove_pointer_t = typename std::remove_pointer::type; - -template -struct is_container_element_type_compatible : std::false_type {}; - -template -struct is_container_element_type_compatible< - T, E, - typename std::enable_if< - !std::is_same< - typename std::remove_cv()))>::type, - void>::value && - std::is_convertible< - remove_pointer_t()))> (*)[], - E (*)[]>::value - >::type> - : std::true_type {}; - -template -struct is_complete : std::false_type {}; - -template -struct is_complete : std::true_type {}; - -} // namespace detail - -template -class span { - static_assert(std::is_object::value, - "A span's ElementType must be an object type (not a " - "reference type or void)"); - static_assert(detail::is_complete::value, - "A span's ElementType must be a complete type (not a forward " - "declaration)"); - static_assert(!std::is_abstract::value, - "A span's ElementType cannot be an abstract class type"); - - using storage_type = detail::span_storage; - -public: - // constants and types - using element_type = ElementType; - using value_type = typename std::remove_cv::type; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - using pointer = element_type*; - using const_pointer = const element_type*; - using reference = element_type&; - using const_reference = const element_type&; - using iterator = pointer; - using reverse_iterator = std::reverse_iterator; - - static constexpr size_type extent = Extent; - - // [span.cons], span constructors, copy, assignment, and destructor - template < - std::size_t E = Extent, - typename std::enable_if<(E == dynamic_extent || E <= 0), int>::type = 0> - constexpr span() noexcept - {} - - TCB_SPAN_CONSTEXPR11 span(pointer ptr, size_type count) - : storage_(ptr, count) - { - TCB_SPAN_EXPECT(extent == dynamic_extent || count == extent); - } - - TCB_SPAN_CONSTEXPR11 span(pointer first_elem, pointer last_elem) - : storage_(first_elem, last_elem - first_elem) - { - TCB_SPAN_EXPECT(extent == dynamic_extent || - last_elem - first_elem == - static_cast(extent)); - } - - template ::value, - int>::type = 0> - constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N) - {} - - template &, ElementType>::value, - int>::type = 0> - TCB_SPAN_ARRAY_CONSTEXPR span(std::array& arr) noexcept - : storage_(arr.data(), N) - {} - - template &, ElementType>::value, - int>::type = 0> - TCB_SPAN_ARRAY_CONSTEXPR span(const std::array& arr) noexcept - : storage_(arr.data(), N) - {} - - template < - typename Container, std::size_t E = Extent, - typename std::enable_if< - E == dynamic_extent && detail::is_container::value && - detail::is_container_element_type_compatible< - Container&, ElementType>::value, - int>::type = 0> - constexpr span(Container& cont) - : storage_(detail::data(cont), detail::size(cont)) - {} - - template < - typename Container, std::size_t E = Extent, - typename std::enable_if< - E == dynamic_extent && detail::is_container::value && - detail::is_container_element_type_compatible< - const Container&, ElementType>::value, - int>::type = 0> - constexpr span(const Container& cont) - : storage_(detail::data(cont), detail::size(cont)) - {} - - constexpr span(const span& other) noexcept = default; - - template ::value, - int>::type = 0> - constexpr span(const span& other) noexcept - : storage_(other.data(), other.size()) - {} - - ~span() noexcept = default; - - TCB_SPAN_CONSTEXPR_ASSIGN span& - operator=(const span& other) noexcept = default; - - // [span.sub], span subviews - template - TCB_SPAN_CONSTEXPR11 span first() const - { - TCB_SPAN_EXPECT(Count <= size()); - return {data(), Count}; - } - - template - TCB_SPAN_CONSTEXPR11 span last() const - { - TCB_SPAN_EXPECT(Count <= size()); - return {data() + (size() - Count), Count}; - } - - template - using subspan_return_t = - span; - - template - TCB_SPAN_CONSTEXPR11 subspan_return_t subspan() const - { - TCB_SPAN_EXPECT(Offset <= size() && - (Count == dynamic_extent || Offset + Count <= size())); - return {data() + Offset, - Count != dynamic_extent ? Count : size() - Offset}; - } - - TCB_SPAN_CONSTEXPR11 span - first(size_type count) const - { - TCB_SPAN_EXPECT(count <= size()); - return {data(), count}; - } - - TCB_SPAN_CONSTEXPR11 span - last(size_type count) const - { - TCB_SPAN_EXPECT(count <= size()); - return {data() + (size() - count), count}; - } - - TCB_SPAN_CONSTEXPR11 span - subspan(size_type offset, size_type count = dynamic_extent) const - { - TCB_SPAN_EXPECT(offset <= size() && - (count == dynamic_extent || offset + count <= size())); - return {data() + offset, - count == dynamic_extent ? size() - offset : count}; - } - - // [span.obs], span observers - constexpr size_type size() const noexcept { return storage_.size; } - - constexpr size_type size_bytes() const noexcept - { - return size() * sizeof(element_type); - } - - TCB_SPAN_NODISCARD constexpr bool empty() const noexcept - { - return size() == 0; - } - - // [span.elem], span element access - TCB_SPAN_CONSTEXPR11 reference operator[](size_type idx) const - { - TCB_SPAN_EXPECT(idx < size()); - return *(data() + idx); - } - - TCB_SPAN_CONSTEXPR11 reference front() const - { - TCB_SPAN_EXPECT(!empty()); - return *data(); - } - - TCB_SPAN_CONSTEXPR11 reference back() const - { - TCB_SPAN_EXPECT(!empty()); - return *(data() + (size() - 1)); - } - - constexpr pointer data() const noexcept { return storage_.ptr; } - - // [span.iterators], span iterator support - constexpr iterator begin() const noexcept { return data(); } - - constexpr iterator end() const noexcept { return data() + size(); } - - TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rbegin() const noexcept - { - return reverse_iterator(end()); - } - - TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rend() const noexcept - { - return reverse_iterator(begin()); - } - -private: - storage_type storage_{}; -}; - -#ifdef TCB_SPAN_HAVE_DEDUCTION_GUIDES - -/* Deduction Guides */ -template -span(T (&)[N])->span; - -template -span(std::array&)->span; - -template -span(const std::array&)->span; - -template -span(Container&)->span()))>::type>; - -template -span(const Container&)->span; - -#endif // TCB_HAVE_DEDUCTION_GUIDES - -template -constexpr span -make_span(span s) noexcept -{ - return s; -} - -template -constexpr span make_span(T (&arr)[N]) noexcept -{ - return {arr}; -} - -template -TCB_SPAN_ARRAY_CONSTEXPR span make_span(std::array& arr) noexcept -{ - return {arr}; -} - -template -TCB_SPAN_ARRAY_CONSTEXPR span -make_span(const std::array& arr) noexcept -{ - return {arr}; -} - -template -constexpr span()))>::type> -make_span(Container& cont) -{ - return {cont}; -} - -template -constexpr span -make_span(const Container& cont) -{ - return {cont}; -} - -template -span -as_bytes(span s) noexcept -{ - return {reinterpret_cast(s.data()), s.size_bytes()}; -} - -template < - class ElementType, size_t Extent, - typename std::enable_if::value, int>::type = 0> -span -as_writable_bytes(span s) noexcept -{ - return {reinterpret_cast(s.data()), s.size_bytes()}; -} - -template -constexpr auto get(span s) -> decltype(s[N]) -{ - return s[N]; -} - -} // namespace TCB_SPAN_NAMESPACE_NAME - -namespace std { - -template -class tuple_size> - : public integral_constant {}; - -template -class tuple_size>; // not defined - -template -class tuple_element> { -public: - static_assert(Extent != TCB_SPAN_NAMESPACE_NAME::dynamic_extent && - I < Extent, - ""); - using type = ElementType; -}; - -} // end namespace std - -#endif // TCB_SPAN_HPP_INCLUDED blob - /dev/null blob + 08a5d754c5e4e8f433a230fce92b6a1438a8ade7 (mode 644) --- /dev/null +++ shared/span @@ -0,0 +1,45 @@ +/** Simply std::span implementation for C++11 */ + +#pragma once + + +namespace vostok +{ + +template +class span +{ +public: + using element_type = ElemT; + using iterator = ElemT *; + + + constexpr span() : m_p{nullptr}, m_count{0} {} + constexpr span(element_type *p, size_t count) : m_p{count ? p : nullptr}, m_count{count} {} + template + constexpr span(element_type (&arr)[N]) : m_p{arr}, m_count{N} {} + template + constexpr span(std::array &arr) : m_p{arr.data()}, m_count{N} {} + + constexpr size_t size() const {return m_count;} + + constexpr iterator begin() const noexcept { return m_p; } + constexpr iterator end() const noexcept { return m_p + size(); } + + span first(size_t count) const + { + assert(count <= m_count); + return span{m_p, count}; + } + span subspan(size_t offset) const + { + assert(offset <= m_count); + return (offset < m_count) ? span{m_p + offset, m_count - offset} : span{}; + } + +private: + element_type *m_p; + size_t m_count; +}; + +} // namespace vostok blob - cb103a9a567aed21307000a84fbdb6a952ee0c64 blob + e6d666b97f804f3ff012ebb92e6591199fca6a96 --- shared/transport.cc +++ shared/transport.cc @@ -15,12 +15,12 @@ using config_t = std::unique_ptr read(not_null ctx, tcb::span buff) +span read(not_null ctx, span buff) { ssize_t ret{}; for (; ; ) { - ret = tls_read(ctx, &buff[0], buff.size()); + ret = tls_read(ctx, buff.begin(), buff.size()); if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) continue; break; @@ -36,9 +36,9 @@ tcb::span read(not_null ctx, tcb:: error::g_log << "Error: " << last_error << std::endl; } ); - return tcb::span{}; + return span{}; } - return tcb::span{&buff[0], static_cast(ret)}; + return buff.first(ret); } @@ -143,11 +143,11 @@ void accept( } -tcb::span read_request(not_null ctx, std::array &buffer) +span read_request(not_null ctx, std::array &buffer) { const auto request = read(ctx, buffer); if (!request.size()) - return tcb::span{}; + return span{}; for (auto current = request.begin(); current < request.end(); ++current) { @@ -158,15 +158,15 @@ tcb::span read_request(not_null ct if (*current == CRLF[0] && *next == CRLF[1]) { // > servers MUST ignore anything sent after the first occurrence of a . - return tcb::span{&request[0], static_cast(current - request.begin())}; + return request.first(current - request.begin()); } } error::occurred("Parse request", error::none{}); - return tcb::span{}; + return span{}; } -bool send_response(not_null ctx, status_t status, tcb::span meta) +bool send_response(not_null ctx, status_t status, span meta) { // > std::array buff; @@ -177,20 +177,20 @@ bool send_response(not_null ctx, status_ current = std::copy(meta.begin(), meta.end(), current); current = std::copy(CRLF.cbegin(), CRLF.cend(), current); - return send(ctx, tcb::span{&buff[0], static_cast(current - buff.begin())}); + return send(ctx, span{&buff[0], static_cast(current - buff.begin())}); } -bool send(not_null ctx, tcb::span buff) +bool send(not_null ctx, span buff) { ssize_t ret{0}; while (buff.size() > 0) { - ret = tls_write(ctx, &buff[0], buff.size()); + ret = tls_write(ctx, buff.begin(), buff.size()); if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) continue; break; - buff = decltype(buff){&buff[ret], buff.size() - ret}; + buff = buff.subspan(buff.size() - ret); } if (ret == -1) { blob - 137cf9aaf8f4cdfe634162e8481daef491e79f28 blob + df192b248ee3733f9ec9c3728ae77d6d18f9fbe8 --- shared/transport.h +++ shared/transport.h @@ -4,9 +4,9 @@ #include #include #include +#include #include -#include #include @@ -85,15 +85,15 @@ void accept( /** Read genimi request and return url (empty url - error) */ -tcb::span read_request(not_null ctx, std::array &buffer); +span read_request(not_null ctx, std::array &buffer); /** Write gemini response */ -bool send_response(not_null ctx, status_t status, tcb::span meta); +bool send_response(not_null ctx, status_t status, span meta); /** Send raw bytes */ -bool send(not_null ctx, tcb::span buff); +bool send(not_null ctx, span buff); } // namespace transport blob - ec616dd3564f0010d8c801009f3d6de7524b98cb blob + c1c6d79110769a612749d821eda6858d3825e565 --- vostokd/Makefile +++ vostokd/Makefile @@ -8,7 +8,7 @@ HXXFILES += ${.PATH}../shared/zstring HXXFILES += ${.PATH}../shared/unique_fd HXXFILES += ${.PATH}../shared/non_copiable HXXFILES += ${.PATH}../shared/unique_fd -HXXFILES += ${.PATH}../shared/span.hpp +HXXFILES += ${.PATH}../shared/span CXXFILES += ${.PATH}../shared/transport.cc HXXFILES += ${.PATH}../shared/transport.h CXXFILES += ${.PATH}../shared/error.cc blob - 8244dc2b89c635fe09a9d5489f4765b3ff222a03 blob + 88c122fe1ed1029919a57118bf1df380b1c9f120 --- vostokd/vostokd.cc +++ vostokd/vostokd.cc @@ -21,10 +21,10 @@ namespace /** Remove null terminating character and return as span */ template -constexpr tcb::span cut_null(const char (&arr)[N]) +constexpr span cut_null(const char (&arr)[N]) { static_assert(N > 0, "!(N > 0)"); - return tcb::span{&arr[0], N - 1}; + return span{arr, N - 1}; } @@ -133,7 +133,7 @@ void client_thread(transport::accepted_context::value transport::send_response(ctx.get_ctx(), transport::STATUS_53_PROXY_REQUEST_REFUSED, meta::non_gemini); return; } - url = decltype(url){&url[gemini_scheme.size()], url.size() - gemini_scheme.size()}; + url = url.subspan(gemini_scheme.size()); // skip domain[:port] const char *current = url.begin(); @@ -142,7 +142,7 @@ void client_thread(transport::accepted_context::value if (*current == '/') { const auto skip_len = (current + 1) - url.begin(); - url = decltype(url){&url[skip_len], url.size() - skip_len}; + url = url.subspan(skip_len); break; } } @@ -156,7 +156,7 @@ void client_thread(transport::accepted_context::value // > If is an empty string, the MIME type MUST default to "text/gemini; charset=utf-8". - transport::send_response(ctx.get_ctx(), transport::STATUS_20_SUCCESS, tcb::span{}); + transport::send_response(ctx.get_ctx(), transport::STATUS_20_SUCCESS, span{}); static const char content[] = "# Vostok server\r\n\r\n...work-in-progress..."; transport::send(ctx.get_ctx(), cut_null(content)); }