RESTinio
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 {
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 {
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
496{
497 public:
498 writable_item_t( const writable_item_t & ) = delete;
500
503 {
505 }
506
509 {
510 new( &m_storage ) impl::const_buf_t{ const_buf.m_str, const_buf.m_size };
511 }
512
513 template <
514 typename Datasizeable,
515 typename S = typename
516 std::enable_if_t<
517 !std::is_same<
518 std::vector< writable_item_t >,
519 Datasizeable >::value > >
520 writable_item_t( Datasizeable ds )
522 {
523 static_assert(
525 "size of type is too big" );
526
528 }
529
530 writable_item_t( const char * str )
531 // We can't be sure whether it is valid to consider
532 // data pointed by str a const buffer, so we make a string copy here.
533 : writable_item_t{ std::string{ str } }
534 {}
535
536 template < typename Datasizeable >
537 writable_item_t( std::shared_ptr< Datasizeable > sp )
539 {
540 static_assert(
542 "size of shared_ptr on a type is too big" );
543
544 if( !sp )
545 throw exception_t{ "empty shared_ptr cannot be used as buffer" };
546
548 }
549
552 {
554 }
555
558 {
559 b.get_writable_base()->relocate_to( &m_storage );
560 }
561
564 {
565 if( this != &b )
566 {
568 m_write_type = b.m_write_type;
569 b.get_writable_base()->relocate_to( &m_storage );
570 }
571
572 return *this;
573 }
574
576 {
578 }
579
582 write_type() const noexcept
583 {
584 return m_write_type;
585 }
586
588 std::size_t size() const { return get_writable_base()->size(); }
589
591
594 asio_ns::const_buffer buf() const { return get_buf()->buffer(); }
595
597
603 sendfile_t &
605 {
606 return get_sfwo()->sendfile_options();
607 }
608
609 private:
610 void
612 {
613 using dtor_writable_base_t = impl::writable_base_t;
614 get_writable_base()->~dtor_writable_base_t();
615 }
616
618
623
626 {
627 return reinterpret_cast< const impl::writable_base_t * >( &m_storage );
628 }
629
632 {
633 return reinterpret_cast< impl::writable_base_t * >( &m_storage );
634 }
635
637 const impl::buf_iface_t * get_buf() const noexcept
638 {
639 return reinterpret_cast< const impl::buf_iface_t * >( &m_storage );
640 }
641
644 {
645 return reinterpret_cast< impl::buf_iface_t * >( &m_storage );
646 }
647
650 {
651 return reinterpret_cast< impl::sendfile_write_operation_t * >( &m_storage );
652 }
654
655 using storage_t =
656 std::aligned_storage_t<
659
662};
663
664//
665// writable_items_container_t
666//
667
668using writable_items_container_t = std::vector< writable_item_t >;
669
670//
671// write_status_cb_t
672//
673
676
680 std::function< void( const asio_ns::error_code & ec ) >;
681
682//
683// write_group_t
684//
685
688
692{
693 public:
695 friend void
696 swap( write_group_t & left, write_group_t & right ) noexcept
697 {
698 using std::swap;
699 swap( left.m_items, right.m_items );
700 swap( left.m_status_line_size, right.m_status_line_size );
701 swap( left.m_after_write_notificator, right.m_after_write_notificator );
702 }
703
708 : m_items{ std::move( items ) }
709 , m_status_line_size{ 0 }
710 {}
711
716 write_group_t( const write_group_t & ) = delete;
719
724 write_group_t( write_group_t && wg ) noexcept
725 : m_items{ std::move( wg.m_items ) }
726 , m_status_line_size{ wg.m_status_line_size }
727 , m_after_write_notificator{ std::move( wg.m_after_write_notificator ) }
728 {
729 wg.m_after_write_notificator = write_status_cb_t{}; // Make sure src is cleaned.
730 wg.m_status_line_size = 0;
731 }
732
734 {
735 write_group_t tmp{ std::move( wg ) };
736 swap( *this, tmp );
737
738 return *this;
739 }
741
743
746 ~write_group_t() noexcept
747 {
749 {
754 } );
755 }
756 }
757
762 void
763 status_line_size( std::size_t n )
764 {
765 if( std::size_t{0} != n )
766 {
767 if( m_items.empty() )
768 {
769 throw exception_t{
770 "cannot set status line size for empty write group" };
771 }
772
774 m_items.front().write_type() )
775 {
776 throw exception_t{
777 "cannot set status line size for write group: "
778 "first writable item must be 'trivial_write_operation'" };
779 }
780
781 if( m_items.front().size() < n )
782 {
783 throw exception_t{
784 "cannot set status line size for write group: "
785 "first writable item size is less than provided value" };
786 }
787
789 }
790 }
791
793 std::size_t
795 {
796 return m_status_line_size;
797 }
798
800 void
802 {
803 m_after_write_notificator = std::move( notificator );
804 }
805
807 bool
809 {
810 return static_cast< bool >( m_after_write_notificator );
811 }
812
814 void
815 invoke_after_write_notificator_if_exists( const asio_ns::error_code & ec )
816 {
818 {
820
821 // Make sure we clean notificator,
822 // because on some platforms/compilers `std::move()` does not clean it.
824
825 tmp( ec );
826 }
827 }
829
831 auto
833 {
834 return m_items.size();
835 }
836
838 const auto &
839 items() const noexcept
840 {
841 return m_items;
842 }
843
845
851 auto &
852 items() noexcept
853 {
854 return m_items;
855 }
856
858 void
859 reset() noexcept
860 {
861
864
865 // This assign is expected to be noexcept.
866 // And it is on some compilers.
867 // But for some compilers std::function::operator= is not noexcept
868 // (for example for Visual C++ from VisualStudio 2017).
869 // So we have to hope that this assign won't throw.
870 // Otherwise there is no way to recover from an exception
871 // from std::function::operator= in that place.
873 }
874
876
880 void
882 {
883 auto & second_items = second.m_items;
884 m_items.reserve( m_items.size() + second_items.size() );
885
886 std::move(
887 begin( second_items ),
888 end( second_items ),
889 std::back_inserter( m_items ) );
890
892 }
893
894 private:
897
899
904
907};
908
909} /* 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:496
writable_item_t(writable_item_t &&b)
Definition: buffers.hpp:556
sendfile_t & sendfile_operation()
Get a reference to a sendfile operation.
Definition: buffers.hpp:604
writable_item_t(const writable_item_t &)=delete
writable_item_t(std::shared_ptr< Datasizeable > sp)
Definition: buffers.hpp:537
const impl::writable_base_t * get_writable_base() const noexcept
Access as writable_base_t item.
Definition: buffers.hpp:625
impl::sendfile_write_operation_t * get_sfwo() noexcept
Access as sendfile_write_operation_t item.
Definition: buffers.hpp:649
writable_item_t(const_buffer_t const_buf)
Definition: buffers.hpp:507
writable_item_t(Datasizeable ds)
Definition: buffers.hpp:520
storage_t m_storage
A storage for a buffer object of various types.
Definition: buffers.hpp:661
writable_item_t(const char *str)
Definition: buffers.hpp:530
writable_item_type_t m_write_type
Definition: buffers.hpp:617
std::aligned_storage_t< impl::needed_storage_max_size, impl::buffer_storage_align > storage_t
Definition: buffers.hpp:658
asio_ns::const_buffer buf() const
Create a buf reference object used by ASIO.
Definition: buffers.hpp:594
impl::buf_iface_t * get_buf() noexcept
Access as trivial buf item.
Definition: buffers.hpp:643
writable_item_t(sendfile_t sf_opts)
Definition: buffers.hpp:550
impl::writable_base_t * get_writable_base() noexcept
Access as writable_base_t item.
Definition: buffers.hpp:631
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:588
writable_item_type_t write_type() const noexcept
Get a type of a stored buffer object.
Definition: buffers.hpp:582
const impl::buf_iface_t * get_buf() const noexcept
Access as trivial buf item.
Definition: buffers.hpp:637
Group of writable items transported to the context of underlying connection as one solid piece.
Definition: buffers.hpp:692
auto & items() noexcept
Get access to the stored items.
Definition: buffers.hpp:852
~write_group_t() noexcept
Destruct object.
Definition: buffers.hpp:746
void invoke_after_write_notificator_if_exists(const asio_ns::error_code &ec)
Get after write notificator.
Definition: buffers.hpp:815
write_group_t & operator=(const write_group_t &)=delete
const auto & items() const noexcept
Get access to the stored items.
Definition: buffers.hpp:839
write_group_t(write_group_t &&wg) noexcept
Definition: buffers.hpp:724
std::size_t m_status_line_size
A size of status line located in first "buffer".
Definition: buffers.hpp:903
void status_line_size(std::size_t n)
Definition: buffers.hpp:763
write_group_t(writable_items_container_t items) noexcept
Construct write group with a given bunch of writable items.
Definition: buffers.hpp:705
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:906
writable_items_container_t m_items
A buffer objects included in this group.
Definition: buffers.hpp:896
void after_write_notificator(write_status_cb_t notificator) noexcept
Set after write notificator.
Definition: buffers.hpp:801
bool has_after_write_notificator() const noexcept
Is there an after write notificator set?
Definition: buffers.hpp:808
void reset() noexcept
Reset group.
Definition: buffers.hpp:859
friend void swap(write_group_t &left, write_group_t &right) noexcept
Swap two groups.
Definition: buffers.hpp:696
std::size_t status_line_size() const noexcept
Get status line size.
Definition: buffers.hpp:794
void merge(write_group_t second)
Merges with another group.
Definition: buffers.hpp:881
auto items_count() const noexcept
Get the count of stored items.
Definition: buffers.hpp:832
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.
void swap(optional< T > &x, optional< T > &y)
Definition: optional.hpp:1705
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:668
const_buffer_t const_buffer(const char *str) noexcept
Definition: buffers.hpp:430
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:680
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