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 <array>
12#include <cstring>
13#include <memory>
14#include <new>
15#include <string>
16#include <type_traits>
17
20#include <restinio/sendfile.hpp>
21
25
27
28
29namespace restinio
30{
31
32//
33// fmt_minimal_memory_buffer_t
34//
40using fmt_minimal_memory_buffer_t = fmt::basic_memory_buffer<char, 1u>;
41
42namespace impl
43{
44
45//
46// writable_base_t
47//
48
50
61{
62 public:
63 writable_base_t() = default;
64 writable_base_t( const writable_base_t & ) = default;
68
70 {}
71
74 virtual void relocate_to( void * storage ) = 0;
75
77 virtual std::size_t size() const = 0;
78};
79
82{
83 public:
85
88 virtual asio_ns::const_buffer buffer() const = 0;
89};
90
93{
94 public:
96
97 empty_buf_t( const empty_buf_t & ) = delete;
98 empty_buf_t & operator = ( const empty_buf_t & ) = delete;
99
100 empty_buf_t( empty_buf_t && ) = default; // allow only explicit move.
102
109 virtual asio_ns::const_buffer buffer() const override
110 {
111 return asio_ns::const_buffer{ nullptr, 0 };
112 }
113
114 virtual void relocate_to( void * storage ) override
115 {
116 new( storage ) empty_buf_t{};
117 }
119
126 virtual std::size_t size() const override { return 0; }
128};
129
132{
133 public:
134 const_buf_t() = delete;
135
136 constexpr const_buf_t( const void * data, std::size_t size ) noexcept
137 : m_data{ data }
138 , m_size{ size }
139 {}
140
141 const_buf_t( const const_buf_t & ) = delete;
142 const_buf_t & operator = ( const const_buf_t & ) = delete;
143
144 const_buf_t( const_buf_t && ) = default; // allow only explicit move.
146
153 virtual asio_ns::const_buffer buffer() const override
154 {
155 return asio_ns::const_buffer{ m_data, m_size };
156 }
157
158 virtual void relocate_to( void * storage ) override
159 {
160 new( storage ) const_buf_t{ std::move( *this ) };
161 }
163
170 virtual std::size_t size() const override { return m_size; }
172
173 private:
175 const void * const m_data;
177 const std::size_t m_size;
178};
179
181
188template < typename Datasizeable >
190{
191 // Check datasizeable contract:
192 static_assert(
193 std::is_convertible<
194 decltype( std::declval< const Datasizeable >().data() ),
195 const void *
196 >::value,
197 "Datasizeable requires 'T* data() const' member function, "
198 "where 'T*' is convertible to 'void*' " );
199
200 static_assert(
201 std::is_convertible<
202 decltype( std::declval< const Datasizeable >().size() ),
203 std::size_t
204 >::value,
205 "Datasizeable requires 'N size() const' member function, "
206 "where 'N' is convertible to 'std::size_t'" );
207
208 static_assert(
209 std::is_move_constructible< Datasizeable >::value,
210 "Datasizeable must be move constructible" );
211
212 public:
214 : m_custom_buffer{ std::move( buf ) }
215 {}
216
217 datasizeable_buf_t( datasizeable_buf_t && ) noexcept = default; // allow only explicit move.
218
226 {
227 return asio_ns::const_buffer{
228 m_custom_buffer.data(),
229 m_custom_buffer.size() };
230 }
231
232 virtual void relocate_to( void * storage ) override
233 {
234 new( storage ) datasizeable_buf_t{ std::move( *this ) };
235 }
237
244 virtual std::size_t size() const override { return m_custom_buffer.size(); }
246
247 private:
250};
251
253
258
260
266
267//
268// shared_datasizeable_buf_t
269//
270
272template < typename Datasizeable >
274{
275 public:
276 using shared_ptr_t = std::shared_ptr< Datasizeable >;
277
279
283
286
289
297 {
298 return asio_ns::const_buffer{ m_buf_ptr->data(), m_buf_ptr->size() };
299 }
300
301 virtual void relocate_to( void * storage ) override
302 {
303 new( storage ) shared_datasizeable_buf_t{ std::move( *this ) };
304 }
306
313 virtual std::size_t size() const override { return m_buf_ptr->size(); }
315
316 private:
319};
320
321//
322// sendfile_write_operation_t
323//
324
327{
328 public:
330
334
337
340
347 virtual void relocate_to( void * storage ) override
348 {
349 new( storage ) sendfile_write_operation_t{ std::move( *this ) };
350 }
351
352 virtual std::size_t size() const override
353 {
354 return m_sendfile_options
356 m_sendfile_options->size())
357 : std::size_t{ 0 };
358 }
360
362
367 sendfile_t &
369 {
370 return *m_sendfile_options;
371 }
372
373 private:
375 std::unique_ptr< sendfile_t > m_sendfile_options;
376};
377
378// Constant for suitable alignment of any entity in writable_base_t hierarchy.
379constexpr std::size_t buffer_storage_align =
380 std::max< std::size_t >( {
381 alignof( empty_buf_t ),
382 alignof( const_buf_t ),
383 alignof( string_buf_t ),
386 alignof( fmt_minimal_memory_buffer_buf_t ) } );
387
389constexpr std::size_t needed_storage_max_size =
390 std::max< std::size_t >( {
391 sizeof( empty_buf_t ),
392 sizeof( const_buf_t ),
393 sizeof( string_buf_t ),
397
398} /* namespace impl */
399
400//
401// const_buffer_t/
402
404/*
405 A proxy DTO type.
406 Its instances are emitted with const_buffer functions and
407 are possible to converted to writable_item_t as it has a constructor for it.
408*/
410{
411 constexpr const_buffer_t(
412 const void * str,
413 std::size_t size ) noexcept
414 : m_str{ str }
415 , m_size{ size }
416 {}
417
418 const void * const m_str;
419 const std::size_t m_size;
420};
421
424inline constexpr const_buffer_t
425const_buffer( const void * str, std::size_t size ) noexcept
426{
427 return const_buffer_t{ str, size };
428}
429
430inline const_buffer_t
431const_buffer( const char * str ) noexcept
432{
433 return const_buffer( str, std::strlen( str ) );
434}
436
437//
438// writable_item_type_t
439//
440
450
451//
452// writable_item_t
453//
454
456
524{
525 public:
526 writable_item_t( const writable_item_t & ) = delete;
528
534
540
541 template <
542 typename Datasizeable,
543 typename S = typename
544 std::enable_if_t<
545 !std::is_same<
546 std::vector< writable_item_t >,
547 Datasizeable >::value > >
550 {
551 static_assert(
553 "size of type is too big" );
554
555 new( m_storage.data() ) impl::datasizeable_buf_t< Datasizeable >{ std::move( ds ) };
556 }
557
558 writable_item_t( const char * str )
559 // We can't be sure whether it is valid to consider
560 // data pointed by str a const buffer, so we make a string copy here.
561 : writable_item_t{ std::string{ str } }
562 {}
563
564 template < typename Datasizeable >
565 writable_item_t( std::shared_ptr< Datasizeable > sp )
567 {
568 static_assert(
570 "size of shared_ptr on a type is too big" );
571
572 if( !sp )
573 throw exception_t{ "empty shared_ptr cannot be used as buffer" };
574
576 }
577
583
586 {
587 b.get_writable_base()->relocate_to( m_storage.data() );
588 }
589
592 {
593 if( this != &b )
594 {
596 m_write_type = b.m_write_type;
597 b.get_writable_base()->relocate_to( m_storage.data() );
598 }
599
600 return *this;
601 }
602
607
611 {
612 return m_write_type;
613 }
614
616 std::size_t size() const { return get_writable_base()->size(); }
617
619
622 asio_ns::const_buffer buf() const { return get_buf()->buffer(); }
623
625
631 sendfile_t &
633 {
634 return get_sfwo()->sendfile_options();
635 }
636
637 private:
638 void
640 {
642 get_writable_base()->~dtor_writable_base_t();
643 }
644
646
651
654 {
655 return std::launder(
656 reinterpret_cast< const impl::writable_base_t * >( m_storage.data() ) );
657 }
658
661 {
662 return std::launder(
663 reinterpret_cast< impl::writable_base_t * >( m_storage.data() ) );
664 }
665
668 {
669 return std::launder(
670 reinterpret_cast< const impl::buf_iface_t * >( m_storage.data() ) );
671 }
672
675 {
676 return std::launder(
677 reinterpret_cast< impl::buf_iface_t * >( m_storage.data() ) );
678 }
679
682 {
683 return std::launder(
684 reinterpret_cast< impl::sendfile_write_operation_t * >( m_storage.data() ) );
685 }
687
689
696 std::array< char, impl::needed_storage_max_size > m_storage;
697};
698
699//
700// writable_items_container_t
701//
702
703using writable_items_container_t = std::vector< writable_item_t >;
704
705//
706// write_status_cb_t
707//
708
711
715 std::function< void( const asio_ns::error_code & ec ) >;
716
717//
718// write_group_t
719//
720
723
727{
728 public:
730 friend void
732 {
733 using std::swap;
734 swap( left.m_items, right.m_items );
735 swap( left.m_status_line_size, right.m_status_line_size );
736 swap( left.m_after_write_notificator, right.m_after_write_notificator );
737 }
738
743 : m_items{ std::move( items ) }
744 , m_status_line_size{ 0 }
745 {}
746
751 write_group_t( const write_group_t & ) = delete;
754
760 : m_items{ std::move( wg.m_items ) }
761 , m_status_line_size{ wg.m_status_line_size }
762 , m_after_write_notificator{ std::move( wg.m_after_write_notificator ) }
763 {
764 wg.m_after_write_notificator = write_status_cb_t{}; // Make sure src is cleaned.
765 wg.m_status_line_size = 0;
766 }
767
769 {
770 write_group_t tmp{ std::move( wg ) };
771 swap( *this, tmp );
772
773 return *this;
774 }
776
778
792
797 void
798 status_line_size( std::size_t n )
799 {
800 if( std::size_t{0} != n )
801 {
802 if( m_items.empty() )
803 {
804 throw exception_t{
805 "cannot set status line size for empty write group" };
806 }
807
809 m_items.front().write_type() )
810 {
811 throw exception_t{
812 "cannot set status line size for write group: "
813 "first writable item must be 'trivial_write_operation'" };
814 }
815
816 if( m_items.front().size() < n )
817 {
818 throw exception_t{
819 "cannot set status line size for write group: "
820 "first writable item size is less than provided value" };
821 }
822
824 }
825 }
826
828 std::size_t
833
835 void
840
842 bool
844 {
845 return static_cast< bool >( m_after_write_notificator );
846 }
847
849 void
850 invoke_after_write_notificator_if_exists( const asio_ns::error_code & ec )
851 {
853 {
854 auto tmp = std::move( m_after_write_notificator );
855
856 // Make sure we clean notificator,
857 // because on some platforms/compilers `std::move()` does not clean it.
859
860 tmp( ec );
861 }
862 }
864
866 auto
868 {
869 return m_items.size();
870 }
871
873 const auto &
875 {
876 return m_items;
877 }
878
880
886 auto &
888 {
889 return m_items;
890 }
891
893 void
895 {
896
899
900 // This assign is expected to be noexcept.
901 // And it is on some compilers.
902 // But for some compilers std::function::operator= is not noexcept
903 // (for example for Visual C++ from VisualStudio 2017).
904 // So we have to hope that this assign won't throw.
905 // Otherwise there is no way to recover from an exception
906 // from std::function::operator= in that place.
908 }
909
911
915 void
917 {
918 auto & second_items = second.m_items;
919 m_items.reserve( m_items.size() + second_items.size() );
920
921 std::move(
922 begin( second_items ),
923 end( second_items ),
924 std::back_inserter( m_items ) );
925
926 m_after_write_notificator = std::move( second.m_after_write_notificator );
927 }
928
929 private:
932
934
939
942};
943
944} /* 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:82
virtual asio_ns::const_buffer buffer() const =0
Get asio buf entity.
Buffer entity for const buffer.
Definition buffers.hpp:132
virtual asio_ns::const_buffer buffer() const override
Get asio buf entity.
Definition buffers.hpp:153
constexpr const_buf_t(const void *data, std::size_t size) noexcept
Definition buffers.hpp:136
const void *const m_data
A pointer to data.
Definition buffers.hpp:175
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:158
virtual std::size_t size() const override
Get the size of a writable piece of data.
Definition buffers.hpp:170
const std::size_t m_size
The size of data.
Definition buffers.hpp:177
const_buf_t(const const_buf_t &)=delete
const_buf_t(const_buf_t &&)=default
User defined datasizable object.
Definition buffers.hpp:190
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:232
datasizeable_buf_t(Datasizeable buf)
Definition buffers.hpp:213
virtual asio_ns::const_buffer buffer() const override
Get asio buf entity.
Definition buffers.hpp:225
Datasizeable m_custom_buffer
A datasizeable item that represents buffer.
Definition buffers.hpp:249
virtual std::size_t size() const override
Get the size of a writable piece of data.
Definition buffers.hpp:244
Empty buffer entity.
Definition buffers.hpp:93
virtual void relocate_to(void *storage) override
Move this buffer enitity to a given location.
Definition buffers.hpp:114
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:126
virtual asio_ns::const_buffer buffer() const override
Get asio buf entity.
Definition buffers.hpp:109
empty_buf_t & operator=(const empty_buf_t &)=delete
Buffer based on shared_ptr of data-sizeable entity.
Definition buffers.hpp:274
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:301
std::shared_ptr< Datasizeable > shared_ptr_t
Definition buffers.hpp:276
virtual std::size_t size() const override
Get the size of a writable piece of data.
Definition buffers.hpp:313
shared_ptr_t m_buf_ptr
A shared pointer to a datasizeable entity.
Definition buffers.hpp:318
virtual asio_ns::const_buffer buffer() const override
Get asio buf entity.
Definition buffers.hpp:296
shared_datasizeable_buf_t(shared_ptr_t buf_ptr) noexcept
Definition buffers.hpp:280
A base class for writable items.
Definition buffers.hpp:61
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:232
Class for storing the buffers used for streaming body (request/response).
Definition buffers.hpp:524
writable_item_t(writable_item_t &&b)
Definition buffers.hpp:584
sendfile_t & sendfile_operation()
Get a reference to a sendfile operation.
Definition buffers.hpp:632
writable_item_t(const writable_item_t &)=delete
writable_item_t(std::shared_ptr< Datasizeable > sp)
Definition buffers.hpp:565
const impl::writable_base_t * get_writable_base() const noexcept
Access as writable_base_t item.
Definition buffers.hpp:653
impl::sendfile_write_operation_t * get_sfwo() noexcept
Access as sendfile_write_operation_t item.
Definition buffers.hpp:681
writable_item_t(const_buffer_t const_buf)
Definition buffers.hpp:535
writable_item_t(Datasizeable ds)
Definition buffers.hpp:548
writable_item_t(const char *str)
Definition buffers.hpp:558
writable_item_type_t m_write_type
Definition buffers.hpp:645
asio_ns::const_buffer buf() const
Create a buf reference object used by ASIO.
Definition buffers.hpp:622
impl::buf_iface_t * get_buf() noexcept
Access as trivial buf item.
Definition buffers.hpp:674
writable_item_t(sendfile_t sf_opts)
Definition buffers.hpp:578
impl::writable_base_t * get_writable_base() noexcept
Access as writable_base_t item.
Definition buffers.hpp:660
std::array< char, impl::needed_storage_max_size > m_storage
A storage for a buffer object of various types.
Definition buffers.hpp:696
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:616
writable_item_type_t write_type() const noexcept
Get a type of a stored buffer object.
Definition buffers.hpp:610
const impl::buf_iface_t * get_buf() const noexcept
Access as trivial buf item.
Definition buffers.hpp:667
Group of writable items transported to the context of underlying connection as one solid piece.
Definition buffers.hpp:727
auto & items() noexcept
Get access to the stored items.
Definition buffers.hpp:887
~write_group_t() noexcept
Destruct object.
Definition buffers.hpp:781
void invoke_after_write_notificator_if_exists(const asio_ns::error_code &ec)
Get after write notificator.
Definition buffers.hpp:850
write_group_t & operator=(const write_group_t &)=delete
const auto & items() const noexcept
Get access to the stored items.
Definition buffers.hpp:874
write_group_t(write_group_t &&wg) noexcept
Definition buffers.hpp:759
std::size_t m_status_line_size
A size of status line located in first "buffer".
Definition buffers.hpp:938
void status_line_size(std::size_t n)
Definition buffers.hpp:798
write_group_t(writable_items_container_t items) noexcept
Construct write group with a given bunch of writable items.
Definition buffers.hpp:740
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:941
writable_items_container_t m_items
A buffer objects included in this group.
Definition buffers.hpp:931
void after_write_notificator(write_status_cb_t notificator) noexcept
Set after write notificator.
Definition buffers.hpp:836
bool has_after_write_notificator() const noexcept
Is there an after write notificator set?
Definition buffers.hpp:843
void reset() noexcept
Reset group.
Definition buffers.hpp:894
friend void swap(write_group_t &left, write_group_t &right) noexcept
Swap two groups.
Definition buffers.hpp:731
std::size_t status_line_size() const noexcept
Get status line size.
Definition buffers.hpp:829
void merge(write_group_t second)
Merges with another group.
Definition buffers.hpp:916
auto items_count() const noexcept
Get the count of stored items.
Definition buffers.hpp:867
write_group_t(const write_group_t &)=delete
Detection of compiler version and absence of various features.
#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:379
datasizeable_buf_t< std::string > string_buf_t
An alias for a std::string instantiation of datasizeable_buf_t<D> template.
Definition buffers.hpp:257
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:389
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...
run_on_this_thread_settings_t< Traits > on_this_thread()
A special marker for the case when http_server must be run on the context of the current thread.
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:714
fmt::basic_memory_buffer< char, 1u > fmt_minimal_memory_buffer_t
An alias for fmt::basic_memory_buffer<char,1>.
Definition buffers.hpp:40
writable_item_type_t
Buffers write operation type.
Definition buffers.hpp:443
@ 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...
constexpr const_buffer_t const_buffer(const void *str, std::size_t size) noexcept
Definition buffers.hpp:425
asio_ns::error_code make_asio_compaible_error(asio_convertible_error_t err) noexcept
Make restinio error_code compatible with asio_ns::error_code.
std::vector< writable_item_t > writable_items_container_t
Definition buffers.hpp:703
Helpers for safe truncation of unsigned integers.
Helper class for setting a constant buffer storage explicitly.
Definition buffers.hpp:410
constexpr const_buffer_t(const void *str, std::size_t size) noexcept
Definition buffers.hpp:411
const void *const m_str
Definition buffers.hpp:418
const std::size_t m_size
Definition buffers.hpp:419
Send file operation wrapper.
Definition buffers.hpp:327
virtual void relocate_to(void *storage) override
Move this buffer enitity to a given location.
Definition buffers.hpp:347
sendfile_write_operation_t(sendfile_t &&sf_opts)
Definition buffers.hpp:331
std::unique_ptr< sendfile_t > m_sendfile_options
A pointer to sendfile operation details.
Definition buffers.hpp:375
sendfile_t & sendfile_options() noexcept
Get sendfile operation detaiols.
Definition buffers.hpp:368
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:352
sendfile_write_operation_t(sendfile_write_operation_t &&)=default
Utilities for suppressing exceptions from some code block.