RESTinio
Loading...
Searching...
No Matches
buffers.hpp
Go to the documentation of this file.
1/*
2 restinio
3*/
4
9#pragma once
10
11#include <memory>
12#include <array>
13#include <string>
14#include <cstring>
15#include <type_traits>
16
19#include <restinio/sendfile.hpp>
20
24
26
27
28namespace restinio
29{
30
31//
32// fmt_minimal_memory_buffer_t
33//
39using fmt_minimal_memory_buffer_t = fmt::basic_memory_buffer<char, 1u>;
40
41namespace impl
42{
43
44//
45// writable_base_t
46//
47
49
60{
61 public:
62 writable_base_t() = default;
63 writable_base_t( const writable_base_t & ) = default;
67
69 {}
70
73 virtual void relocate_to( void * storage ) = 0;
74
76 virtual std::size_t size() const = 0;
77};
78
81{
82 public:
84
87 virtual asio_ns::const_buffer buffer() const = 0;
88};
89
91class empty_buf_t final : public buf_iface_t
92{
93 public:
94 empty_buf_t() noexcept {}
95
96 empty_buf_t( const empty_buf_t & ) = delete;
97 empty_buf_t & operator = ( const empty_buf_t & ) = delete;
98
99 empty_buf_t( empty_buf_t && ) = default; // allow only explicit move.
101
108 virtual asio_ns::const_buffer buffer() const override
109 {
110 return asio_ns::const_buffer{ nullptr, 0 };
111 }
112
113 virtual void relocate_to( void * storage ) override
114 {
115 new( storage ) empty_buf_t{};
116 }
118
125 virtual std::size_t size() const override { return 0; }
127};
128
130class const_buf_t final : public buf_iface_t
131{
132 public:
133 const_buf_t() = delete;
134
135 constexpr const_buf_t( const void * data, std::size_t size ) noexcept
136 : m_data{ data }
137 , m_size{ size }
138 {}
139
140 const_buf_t( const const_buf_t & ) = delete;
141 const_buf_t & operator = ( const const_buf_t & ) = delete;
142
143 const_buf_t( const_buf_t && ) = default; // allow only explicit move.
145
152 virtual asio_ns::const_buffer buffer() const override
153 {
154 return asio_ns::const_buffer{ m_data, m_size };
155 }
156
157 virtual void relocate_to( void * storage ) override
158 {
159 new( storage ) const_buf_t{ std::move( *this ) };
160 }
162
169 virtual std::size_t size() const override { return m_size; }
171
172 private:
174 const void * const m_data;
176 const std::size_t m_size;
177};
178
180
187template < typename Datasizeable >
188class datasizeable_buf_t final : public buf_iface_t
189{
190 // Check datasizeable contract:
191 static_assert(
192 std::is_convertible<
193 decltype( std::declval< const Datasizeable >().data() ),
194 const void *
195 >::value,
196 "Datasizeable requires 'T* data() const' member function, "
197 "where 'T*' is convertible to 'void*' " );
198
199 static_assert(
200 std::is_convertible<
201 decltype( std::declval< const Datasizeable >().size() ),
202 std::size_t
203 >::value,
204 "Datasizeable requires 'N size() const' member function, "
205 "where 'N' is convertible to 'std::size_t'" );
206
207 static_assert(
208 std::is_move_constructible< Datasizeable >::value,
209 "Datasizeable must be move constructible" );
210
211 public:
212 datasizeable_buf_t( Datasizeable buf )
213 : m_custom_buffer{ std::move( buf ) }
214 {}
215
216 datasizeable_buf_t( datasizeable_buf_t && ) noexcept = default; // allow only explicit move.
217
224 virtual asio_ns::const_buffer buffer() const override
225 {
226 return asio_ns::const_buffer{
227 m_custom_buffer.data(),
228 m_custom_buffer.size() };
229 }
230
231 virtual void relocate_to( void * storage ) override
232 {
233 new( storage ) datasizeable_buf_t{ std::move( *this ) };
234 }
236
243 virtual std::size_t size() const override { return m_custom_buffer.size(); }
245
246 private:
248 Datasizeable m_custom_buffer;
249};
250
252
257
259
265
266//
267// shared_datasizeable_buf_t
268//
269
271template < typename Datasizeable >
273{
274 public:
275 using shared_ptr_t = std::shared_ptr< Datasizeable >;
276
278
280 : m_buf_ptr{ std::move( buf_ptr ) }
281 {}
282
285
286 shared_datasizeable_buf_t( shared_datasizeable_buf_t && ) noexcept = default; // allow only explicit move.
288
295 virtual asio_ns::const_buffer buffer() const override
296 {
297 return asio_ns::const_buffer{ m_buf_ptr->data(), m_buf_ptr->size() };
298 }
299
300 virtual void relocate_to( void * storage ) override
301 {
302 new( storage ) shared_datasizeable_buf_t{ std::move( *this ) };
303 }
305
312 virtual std::size_t size() const override { return m_buf_ptr->size(); }
314
315 private:
318};
319
320//
321// sendfile_write_operation_t
322//
323
326{
327 public:
329
331 : m_sendfile_options{ std::make_unique< sendfile_t >( std::move( sf_opts ) ) }
332 {}
333
336
339
346 virtual void relocate_to( void * storage ) override
347 {
348 new( storage ) sendfile_write_operation_t{ std::move( *this ) };
349 }
350
351 virtual std::size_t size() const override
352 {
353 return m_sendfile_options
355 m_sendfile_options->size())
356 : std::size_t{ 0 };
357 }
359
361
366 sendfile_t &
368 {
369 return *m_sendfile_options;
370 }
371
372 private:
374 std::unique_ptr< sendfile_t > m_sendfile_options;
375};
376
377// Constant for suitable alignment of any entity in writable_base_t hierarchy.
378constexpr std::size_t buffer_storage_align =
379 std::max< std::size_t >( {
380 alignof( empty_buf_t ),
381 alignof( const_buf_t ),
382 alignof( string_buf_t ),
385 alignof( fmt_minimal_memory_buffer_buf_t ) } );
386
388constexpr std::size_t needed_storage_max_size =
389 std::max< std::size_t >( {
390 sizeof( empty_buf_t ),
391 sizeof( const_buf_t ),
392 sizeof( string_buf_t ),
396
397} /* namespace impl */
398
399//
400// const_buffer_t/
401
403/*
404 A proxy DTO type.
405 Its instances are emitted with const_buffer functions and
406 are possible to converted to writable_item_t as it has a constructor for it.
407*/
409{
410 constexpr const_buffer_t(
411 const void * str,
412 std::size_t size ) noexcept
413 : m_str{ str }
414 , m_size{ size }
415 {}
416
417 const void * const m_str;
418 const std::size_t m_size;
419};
420
423inline constexpr const_buffer_t
424const_buffer( const void * str, std::size_t size ) noexcept
425{
426 return const_buffer_t{ str, size };
427}
428
429inline const_buffer_t
430const_buffer( const char * str ) noexcept
431{
432 return const_buffer( str, std::strlen( str ) );
433}
435
436//
437// writable_item_type_t
438//
439
442{
445
448};
449
450//
451// writable_item_t
452//
453
455
526{
527 public:
528 writable_item_t( const writable_item_t & ) = delete;
530
533 {
534 new( m_storage.data() ) impl::empty_buf_t{};
535 }
536
539 {
540 new( m_storage.data() ) impl::const_buf_t{ const_buf.m_str, const_buf.m_size };
541 }
542
543 template <
544 typename Datasizeable,
545 typename S = typename
546 std::enable_if_t<
547 !std::is_same<
548 std::vector< writable_item_t >,
549 Datasizeable >::value > >
550 writable_item_t( Datasizeable ds )
552 {
553 static_assert(
555 "size of type is too big" );
556
557 new( m_storage.data() ) impl::datasizeable_buf_t< Datasizeable >{ std::move( ds ) };
558 }
559
560 writable_item_t( const char * str )
561 // We can't be sure whether it is valid to consider
562 // data pointed by str a const buffer, so we make a string copy here.
563 : writable_item_t{ std::string{ str } }
564 {}
565
566 template < typename Datasizeable >
567 writable_item_t( std::shared_ptr< Datasizeable > sp )
569 {
570 static_assert(
572 "size of shared_ptr on a type is too big" );
573
574 if( !sp )
575 throw exception_t{ "empty shared_ptr cannot be used as buffer" };
576
577 new( m_storage.data() ) impl::shared_datasizeable_buf_t< Datasizeable >{ std::move( sp ) };
578 }
579
582 {
583 new( m_storage.data() ) impl::sendfile_write_operation_t{ std::move( sf_opts ) };
584 }
585
588 {
589 b.get_writable_base()->relocate_to( m_storage.data() );
590 }
591
594 {
595 if( this != &b )
596 {
598 m_write_type = b.m_write_type;
599 b.get_writable_base()->relocate_to( m_storage.data() );
600 }
601
602 return *this;
603 }
604
606 {
608 }
609
612 write_type() const noexcept
613 {
614 return m_write_type;
615 }
616
618 std::size_t size() const { return get_writable_base()->size(); }
619
621
624 asio_ns::const_buffer buf() const { return get_buf()->buffer(); }
625
627
633 sendfile_t &
635 {
636 return get_sfwo()->sendfile_options();
637 }
638
639 private:
640 void
642 {
643 using dtor_writable_base_t = impl::writable_base_t;
644 get_writable_base()->~dtor_writable_base_t();
645 }
646
648
653
656 {
658 reinterpret_cast< const impl::writable_base_t * >( m_storage.data() ) );
659 }
660
663 {
665 reinterpret_cast< impl::writable_base_t * >( m_storage.data() ) );
666 }
667
669 const impl::buf_iface_t * get_buf() const noexcept
670 {
672 reinterpret_cast< const impl::buf_iface_t * >( m_storage.data() ) );
673 }
674
677 {
679 reinterpret_cast< impl::buf_iface_t * >( m_storage.data() ) );
680 }
681
684 {
686 reinterpret_cast< impl::sendfile_write_operation_t * >( m_storage.data() ) );
687 }
689
691
698 std::array< char, impl::needed_storage_max_size > m_storage;
699};
700
701//
702// writable_items_container_t
703//
704
705using writable_items_container_t = std::vector< writable_item_t >;
706
707//
708// write_status_cb_t
709//
710
713
717 std::function< void( const asio_ns::error_code & ec ) >;
718
719//
720// write_group_t
721//
722
725
729{
730 public:
732 friend void
733 swap( write_group_t & left, write_group_t & right ) noexcept
734 {
735 using std::swap;
736 swap( left.m_items, right.m_items );
737 swap( left.m_status_line_size, right.m_status_line_size );
738 swap( left.m_after_write_notificator, right.m_after_write_notificator );
739 }
740
745 : m_items{ std::move( items ) }
746 , m_status_line_size{ 0 }
747 {}
748
753 write_group_t( const write_group_t & ) = delete;
756
761 write_group_t( write_group_t && wg ) noexcept
762 : m_items{ std::move( wg.m_items ) }
763 , m_status_line_size{ wg.m_status_line_size }
764 , m_after_write_notificator{ std::move( wg.m_after_write_notificator ) }
765 {
766 wg.m_after_write_notificator = write_status_cb_t{}; // Make sure src is cleaned.
767 wg.m_status_line_size = 0;
768 }
769
771 {
772 write_group_t tmp{ std::move( wg ) };
773 swap( *this, tmp );
774
775 return *this;
776 }
778
780
783 ~write_group_t() noexcept
784 {
786 {
791 } );
792 }
793 }
794
799 void
800 status_line_size( std::size_t n )
801 {
802 if( std::size_t{0} != n )
803 {
804 if( m_items.empty() )
805 {
806 throw exception_t{
807 "cannot set status line size for empty write group" };
808 }
809
811 m_items.front().write_type() )
812 {
813 throw exception_t{
814 "cannot set status line size for write group: "
815 "first writable item must be 'trivial_write_operation'" };
816 }
817
818 if( m_items.front().size() < n )
819 {
820 throw exception_t{
821 "cannot set status line size for write group: "
822 "first writable item size is less than provided value" };
823 }
824
826 }
827 }
828
830 std::size_t
832 {
833 return m_status_line_size;
834 }
835
837 void
839 {
840 m_after_write_notificator = std::move( notificator );
841 }
842
844 bool
846 {
847 return static_cast< bool >( m_after_write_notificator );
848 }
849
851 void
852 invoke_after_write_notificator_if_exists( const asio_ns::error_code & ec )
853 {
855 {
856 auto tmp = std::move( m_after_write_notificator );
857
858 // Make sure we clean notificator,
859 // because on some platforms/compilers `std::move()` does not clean it.
861
862 tmp( ec );
863 }
864 }
866
868 auto
870 {
871 return m_items.size();
872 }
873
875 const auto &
876 items() const noexcept
877 {
878 return m_items;
879 }
880
882
888 auto &
889 items() noexcept
890 {
891 return m_items;
892 }
893
895 void
896 reset() noexcept
897 {
898
901
902 // This assign is expected to be noexcept.
903 // And it is on some compilers.
904 // But for some compilers std::function::operator= is not noexcept
905 // (for example for Visual C++ from VisualStudio 2017).
906 // So we have to hope that this assign won't throw.
907 // Otherwise there is no way to recover from an exception
908 // from std::function::operator= in that place.
910 }
911
913
917 void
919 {
920 auto & second_items = second.m_items;
921 m_items.reserve( m_items.size() + second_items.size() );
922
923 std::move(
924 begin( second_items ),
925 end( second_items ),
926 std::back_inserter( m_items ) );
927
929 }
930
931 private:
934
936
941
944};
945
946} /* namespace restinio */
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
Internal interface for a trivial buffer-like entity.
Definition: buffers.hpp:81
virtual asio_ns::const_buffer buffer() const =0
Get asio buf entity.
Buffer entity for const buffer.
Definition: buffers.hpp:131
virtual asio_ns::const_buffer buffer() const override
Get asio buf entity.
Definition: buffers.hpp:152
constexpr const_buf_t(const void *data, std::size_t size) noexcept
Definition: buffers.hpp:135
const void *const m_data
A pointer to data.
Definition: buffers.hpp:174
const_buf_t & operator=(const const_buf_t &)=delete
virtual void relocate_to(void *storage) override
Move this buffer enitity to a given location.
Definition: buffers.hpp:157
virtual std::size_t size() const override
Get the size of a writable piece of data.
Definition: buffers.hpp:169
const std::size_t m_size
The size of data.
Definition: buffers.hpp:176
const_buf_t(const const_buf_t &)=delete
const_buf_t(const_buf_t &&)=default
User defined datasizable object.
Definition: buffers.hpp:189
datasizeable_buf_t(datasizeable_buf_t &&) noexcept=default
virtual void relocate_to(void *storage) override
Move this buffer enitity to a given location.
Definition: buffers.hpp:231
datasizeable_buf_t(Datasizeable buf)
Definition: buffers.hpp:212
virtual asio_ns::const_buffer buffer() const override
Get asio buf entity.
Definition: buffers.hpp:224
Datasizeable m_custom_buffer
A datasizeable item that represents buffer.
Definition: buffers.hpp:248
virtual std::size_t size() const override
Get the size of a writable piece of data.
Definition: buffers.hpp:243
Empty buffer entity.
Definition: buffers.hpp:92
virtual void relocate_to(void *storage) override
Move this buffer enitity to a given location.
Definition: buffers.hpp:113
empty_buf_t(empty_buf_t &&)=default
empty_buf_t(const empty_buf_t &)=delete
virtual std::size_t size() const override
Get the size of a writable piece of data.
Definition: buffers.hpp:125
virtual asio_ns::const_buffer buffer() const override
Get asio buf entity.
Definition: buffers.hpp:108
empty_buf_t & operator=(const empty_buf_t &)=delete
Buffer based on shared_ptr of data-sizeable entity.
Definition: buffers.hpp:273
shared_datasizeable_buf_t(shared_datasizeable_buf_t &&) noexcept=default
shared_datasizeable_buf_t & operator=(const shared_datasizeable_buf_t &)=delete
shared_datasizeable_buf_t(const shared_datasizeable_buf_t &)=delete
virtual void relocate_to(void *storage) override
Move this buffer enitity to a given location.
Definition: buffers.hpp:300
std::shared_ptr< Datasizeable > shared_ptr_t
Definition: buffers.hpp:275
virtual std::size_t size() const override
Get the size of a writable piece of data.
Definition: buffers.hpp:312
shared_ptr_t m_buf_ptr
A shared pointer to a datasizeable entity.
Definition: buffers.hpp:317
virtual asio_ns::const_buffer buffer() const override
Get asio buf entity.
Definition: buffers.hpp:295
shared_datasizeable_buf_t(shared_ptr_t buf_ptr) noexcept
Definition: buffers.hpp:279
A base class for writable items.
Definition: buffers.hpp:60
writable_base_t(const writable_base_t &)=default
writable_base_t & operator=(const writable_base_t &)=delete
virtual std::size_t size() const =0
Get the size of a writable piece of data.
writable_base_t(writable_base_t &&)=default
virtual void relocate_to(void *storage)=0
Move this buffer enitity to a given location.
Send file write operation description.
Definition: sendfile.hpp:226
Class for storing the buffers used for streaming body (request/response).
Definition: buffers.hpp:526
writable_item_t(writable_item_t &&b)
Definition: buffers.hpp:586
sendfile_t & sendfile_operation()
Get a reference to a sendfile operation.
Definition: buffers.hpp:634
writable_item_t(const writable_item_t &)=delete
writable_item_t(std::shared_ptr< Datasizeable > sp)
Definition: buffers.hpp:567
const impl::writable_base_t * get_writable_base() const noexcept
Access as writable_base_t item.
Definition: buffers.hpp:655
impl::sendfile_write_operation_t * get_sfwo() noexcept
Access as sendfile_write_operation_t item.
Definition: buffers.hpp:683
writable_item_t(const_buffer_t const_buf)
Definition: buffers.hpp:537
writable_item_t(Datasizeable ds)
Definition: buffers.hpp:550
writable_item_t(const char *str)
Definition: buffers.hpp:560
writable_item_type_t m_write_type
Definition: buffers.hpp:647
asio_ns::const_buffer buf() const
Create a buf reference object used by ASIO.
Definition: buffers.hpp:624
impl::buf_iface_t * get_buf() noexcept
Access as trivial buf item.
Definition: buffers.hpp:676
writable_item_t(sendfile_t sf_opts)
Definition: buffers.hpp:580
impl::writable_base_t * get_writable_base() noexcept
Access as writable_base_t item.
Definition: buffers.hpp:662
std::array< char, impl::needed_storage_max_size > m_storage
A storage for a buffer object of various types.
Definition: buffers.hpp:698
writable_item_t & operator=(const writable_item_t &)=delete
std::size_t size() const
Get the size of the underlying buffer object.
Definition: buffers.hpp:618
writable_item_type_t write_type() const noexcept
Get a type of a stored buffer object.
Definition: buffers.hpp:612
const impl::buf_iface_t * get_buf() const noexcept
Access as trivial buf item.
Definition: buffers.hpp:669
Group of writable items transported to the context of underlying connection as one solid piece.
Definition: buffers.hpp:729
auto & items() noexcept
Get access to the stored items.
Definition: buffers.hpp:889
~write_group_t() noexcept
Destruct object.
Definition: buffers.hpp:783
void invoke_after_write_notificator_if_exists(const asio_ns::error_code &ec)
Get after write notificator.
Definition: buffers.hpp:852
write_group_t & operator=(const write_group_t &)=delete
const auto & items() const noexcept
Get access to the stored items.
Definition: buffers.hpp:876
write_group_t(write_group_t &&wg) noexcept
Definition: buffers.hpp:761
std::size_t m_status_line_size
A size of status line located in first "buffer".
Definition: buffers.hpp:940
void status_line_size(std::size_t n)
Definition: buffers.hpp:800
write_group_t(writable_items_container_t items) noexcept
Construct write group with a given bunch of writable items.
Definition: buffers.hpp:742
write_status_cb_t m_after_write_notificator
A callback to invoke once the the write opertaion of a given group completes.
Definition: buffers.hpp:943
writable_items_container_t m_items
A buffer objects included in this group.
Definition: buffers.hpp:933
void after_write_notificator(write_status_cb_t notificator) noexcept
Set after write notificator.
Definition: buffers.hpp:838
bool has_after_write_notificator() const noexcept
Is there an after write notificator set?
Definition: buffers.hpp:845
void reset() noexcept
Reset group.
Definition: buffers.hpp:896
friend void swap(write_group_t &left, write_group_t &right) noexcept
Swap two groups.
Definition: buffers.hpp:733
std::size_t status_line_size() const noexcept
Get status line size.
Definition: buffers.hpp:831
void merge(write_group_t second)
Merges with another group.
Definition: buffers.hpp:918
auto items_count() const noexcept
Get the count of stored items.
Definition: buffers.hpp:869
write_group_t(const write_group_t &)=delete
Detection of compiler version and absence of various features.
#define RESTINIO_STD_LAUNDER(x)
#define RESTINIO_ENSURE_NOEXCEPT_CALL(expr)
A wrapper around static_assert for checking that an expression is noexcept and execution of that expr...
A special wrapper around fmtlib include files.
constexpr std::size_t buffer_storage_align
Definition: buffers.hpp:378
datasizeable_buf_t< std::string > string_buf_t
An alias for a std::string instantiation of datasizeable_buf_t<D> template.
Definition: buffers.hpp:256
constexpr std::size_t needed_storage_max_size
An of memory that is to be enough to hold any possible buffer entity.
Definition: buffers.hpp:388
std::size_t uint64_to_size_t(std::uint64_t v)
Helper function for truncating uint64 to std::size_t with exception if that truncation will lead to d...
void suppress_exceptions_quietly(Lambda &&lambda) noexcept
Helper function for execution a block of code with suppression of any exceptions raised inside that b...
std::vector< writable_item_t > writable_items_container_t
Definition: buffers.hpp:705
fmt::basic_memory_buffer< char, 1u > fmt_minimal_memory_buffer_t
An alias for fmt::basic_memory_buffer<char,1>.
Definition: buffers.hpp:39
writable_item_type_t
Buffers write operation type.
Definition: buffers.hpp:442
@ trivial_write_operation
Item is a buffer and must be written trivially.
@ file_write_operation
Item is a sendfile operation and implicates file write operation.
@ write_group_destroyed_passively
After write notificator error: a notificator was set for a write_group_t but no external invokation h...
std::function< void(const asio_ns::error_code &ec) > write_status_cb_t
An alias for a callback to be invoked after the write operation of a particular group of "buffers".
Definition: buffers.hpp:717
constexpr const_buffer_t const_buffer(const void *str, std::size_t size) noexcept
Definition: buffers.hpp:424
asio_ns::error_code make_asio_compaible_error(asio_convertible_error_t err) noexcept
Make restinio error_code compatible with asio_ns::error_code.
STL namespace.
Helpers for safe truncation of unsigned integers.
Helper class for setting a constant buffer storage explicitly.
Definition: buffers.hpp:409
constexpr const_buffer_t(const void *str, std::size_t size) noexcept
Definition: buffers.hpp:410
const void *const m_str
Definition: buffers.hpp:417
const std::size_t m_size
Definition: buffers.hpp:418
Send file operation wrapper.
Definition: buffers.hpp:326
virtual void relocate_to(void *storage) override
Move this buffer enitity to a given location.
Definition: buffers.hpp:346
sendfile_write_operation_t(sendfile_t &&sf_opts)
Definition: buffers.hpp:330
std::unique_ptr< sendfile_t > m_sendfile_options
A pointer to sendfile operation details.
Definition: buffers.hpp:374
sendfile_t & sendfile_options() noexcept
Get sendfile operation detaiols.
Definition: buffers.hpp:367
sendfile_write_operation_t(const sendfile_write_operation_t &)=delete
sendfile_write_operation_t & operator=(const sendfile_write_operation_t &)=delete
virtual std::size_t size() const override
Get the size of a writable piece of data.
Definition: buffers.hpp:351
sendfile_write_operation_t(sendfile_write_operation_t &&)=default
Utilities for suppressing exceptions from some code block.
#define const
Definition: zconf.h:230