RESTinio
buffers.hpp
Go to the documentation of this file.
1 /*
2  restinio
3 */
4 
5 /*!
6  Restinio buffers.
7 */
8 
9 #pragma once
10 
11 #include <array>
12 #include <cstring>
13 #include <memory>
14 #include <new>
15 #include <string>
16 #include <type_traits>
17 
18 #include <restinio/asio_include.hpp>
19 #include <restinio/exception.hpp>
20 #include <restinio/sendfile.hpp>
21 
22 #include <restinio/compiler_features.hpp>
23 #include <restinio/utils/suppress_exceptions.hpp>
24 #include <restinio/utils/impl/safe_uint_truncate.hpp>
25 
26 #include <restinio/impl/include_fmtlib.hpp>
27 
28 
29 namespace restinio
30 {
31 
32 //
33 // fmt_minimal_memory_buffer_t
34 //
35 /*!
36  * @brief An alias for fmt::basic_memory_buffer<char,1>.
37  *
38  * @since v.0.6.3
39  */
41 
42 namespace impl
43 {
44 
45 //
46 // writable_base_t
47 //
48 
49 //! A base class for writable items.
50 /*!
51  Having a condition to put heterogeneous writable-items sequence in vector
52  and to transfer it from builders to connection context,
53  internal writable-items are the pieces encapsulating various
54  implementation that fit into a fixed memory space.
55  That's makes it possible to fit any of them in a binary
56  buffer that resides in writable_item_t.
57  While different descendants might vary in size
58  size of writable_item_t remains the same, so it can be used in a vector.
59 */
61 {
62  public:
63  writable_base_t() = default;
64  writable_base_t( const writable_base_t & ) = default;
65  writable_base_t( writable_base_t && ) = default;
66  writable_base_t & operator = ( const writable_base_t & ) = delete;
67  writable_base_t & operator = ( writable_base_t && ) = delete;
68 
69  virtual ~writable_base_t()
70  {}
71 
72  //! Move this buffer enitity to a given location.
73  //! \note storage must have a sufficient space and proper alignment.
74  virtual void relocate_to( void * storage ) = 0;
75 
76  //! Get the size of a writable piece of data.
77  virtual std::size_t size() const = 0;
78 };
79 
80 //! Internal interface for a trivial buffer-like entity.
82 {
83  public:
84  //! Get asio buf entity.
85  /*!
86  Prepares an item for being used with ASIO API.
87  */
88  virtual asio_ns::const_buffer buffer() const = 0;
89 };
90 
91 //! Empty buffer entity.
92 class empty_buf_t final : public buf_iface_t
93 {
94  public:
95  empty_buf_t() noexcept {}
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.
101  empty_buf_t & operator = ( empty_buf_t && ) = delete;
102 
103  /*!
104  @name An implementation of writable_base_t interface.
105 
106  \see writable_base_t
107  */
108  ///@{
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  }
118  ///@}
119 
120  /*!
121  @name An implementation of buf_iface_t interface.
122 
123  \see buf_iface_t
124  */
125  ///@{
126  virtual std::size_t size() const override { return 0; }
127  ///@}
128 };
129 
130 //! Buffer entity for const buffer.
131 class const_buf_t final : public buf_iface_t
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.
145  const_buf_t & operator = ( const_buf_t && ) = delete;
146 
147  /*!
148  @name An implementation of writable_base_t interface.
149 
150  \see writable_base_t
151  */
152  ///@{
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  }
162  ///@}
163 
164  /*!
165  @name An implementation of buf_iface_t interface.
166 
167  \see buf_iface_t
168  */
169  ///@{
170  virtual std::size_t size() const override { return m_size; }
171  ///@}
172 
173  private:
174  //! A pointer to data.
175  const void * const m_data;
176  //! The size of data.
177  const std::size_t m_size;
178 };
179 
180 //! User defined datasizable object.
181 /*!
182  \note there is a limitation on how large a `Datasizeable` type can be.
183  The limitation is checked with a following predicate:
184  \code
185  sizeof(datasizeable_buf_t<D>) <= needed_storage_max_size;
186  \endcode
187 */
188 template < typename Datasizeable >
190 {
191  // Check datasizeable contract:
192  static_assert(
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(
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(
210  "Datasizeable must be move constructible" );
211 
212  public:
213  datasizeable_buf_t( Datasizeable buf )
214  : m_custom_buffer{ std::move( buf ) }
215  {}
216 
217  datasizeable_buf_t( datasizeable_buf_t && ) noexcept = default; // allow only explicit move.
218 
219  /*!
220  @name An implementation of writable_base_t interface.
221 
222  \see writable_base_t
223  */
224  ///@{
225  virtual asio_ns::const_buffer buffer() const override
226  {
227  return asio_ns::const_buffer{
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  }
236  ///@}
237 
238  /*!
239  @name An implementation of buf_iface_t interface.
240 
241  \see buf_iface_t
242  */
243  ///@{
244  virtual std::size_t size() const override { return m_custom_buffer.size(); }
245  ///@}
246 
247  private:
248  //! A datasizeable item that represents buffer.
249  Datasizeable m_custom_buffer;
250 };
251 
252 //! An alias for a std::string instantiation of datasizeable_buf_t<D> template.
253 /*!
254  Used to figure out buffer_storage_align and needed_storage_max_size
255  constants.
256 */
258 
259 //! An alias for a fmt_minimal_memory_buffer_t instantiation of datasizeable_buf_t<D> template.
260 /*!
261  Used to figure out buffer_storage_align and needed_storage_max_size
262  constants.
263 */
266 
267 //
268 // shared_datasizeable_buf_t
269 //
270 
271 //! Buffer based on shared_ptr of data-sizeable entity.
272 template < typename Datasizeable >
274 {
275  public:
277 
278  shared_datasizeable_buf_t() = delete;
279 
280  shared_datasizeable_buf_t( shared_ptr_t buf_ptr ) noexcept
281  : m_buf_ptr{ std::move( buf_ptr ) }
282  {}
283 
286 
287  shared_datasizeable_buf_t( shared_datasizeable_buf_t && ) noexcept = default; // allow only explicit move.
289 
290  /*!
291  @name An implementation of writable_base_t interface.
292 
293  \see writable_base_t
294  */
295  ///@{
296  virtual asio_ns::const_buffer buffer() const override
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  }
305  ///@}
306 
307  /*!
308  @name An implementation of buf_iface_t interface.
309 
310  \see buf_iface_t
311  */
312  ///@{
313  virtual std::size_t size() const override { return m_buf_ptr->size(); }
314  ///@}
315 
316  private:
317  //! A shared pointer to a datasizeable entity.
319 };
320 
321 //
322 // sendfile_write_operation_t
323 //
324 
325 //! Send file operation wrapper.
327 {
328  public:
329  sendfile_write_operation_t() = delete;
330 
331  sendfile_write_operation_t( sendfile_t && sf_opts )
333  {}
334 
337 
340 
341  /*!
342  @name An implementation of writable_base_t interface.
343 
344  \see writable_base_t
345  */
346  ///@{
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
355  ? ::restinio::utils::impl::uint64_to_size_t(
356  m_sendfile_options->size())
357  : std::size_t{ 0 };
358  }
359  ///@}
360 
361  //! Get sendfile operation detaiols.
362  /*!
363  @note
364  Since v.0.4.9 it is non-const method. It is because we have
365  to work with mutable sendfile_t on some platform (like Windows).
366  */
367  sendfile_t &
368  sendfile_options() noexcept
369  {
370  return *m_sendfile_options;
371  }
372 
373  private:
374  //! A pointer to sendfile operation details.
376 };
377 
378 // Constant for suitable alignment of any entity in writable_base_t hierarchy.
380  std::max< std::size_t >( {
381  alignof( empty_buf_t ),
382  alignof( const_buf_t ),
383  alignof( string_buf_t ),
384  alignof( shared_datasizeable_buf_t< std::string > ),
385  alignof( sendfile_write_operation_t ),
386  alignof( fmt_minimal_memory_buffer_buf_t ) } );
387 
388 //! An of memory that is to be enough to hold any possible buffer entity.
390  std::max< std::size_t >( {
391  sizeof( empty_buf_t ),
392  sizeof( const_buf_t ),
393  sizeof( string_buf_t ),
394  sizeof( shared_datasizeable_buf_t< std::string > ),
395  sizeof( sendfile_write_operation_t ),
396  sizeof( fmt_minimal_memory_buffer_buf_t ) } );
397 
398 } /* namespace impl */
399 
400 //
401 // const_buffer_t/
402 
403 //! Helper class for setting a constant buffer storage explicitly.
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 
422 //! @name Create const buffers.
423 ///@{
424 inline constexpr const_buffer_t
425 const_buffer( const void * str, std::size_t size ) noexcept
426 {
427  return const_buffer_t{ str, size };
428 }
429 
430 inline const_buffer_t
431 const_buffer( const char * str ) noexcept
432 {
433  return const_buffer( str, std::strlen( str ) );
434 }
435 ///@}
436 
437 //
438 // writable_item_type_t
439 //
440 
441 //! Buffers write operation type.
443 {
444  //! Item is a buffer and must be written trivially
446 
447  //! Item is a sendfile operation and implicates file write operation.
449 };
450 
451 //
452 // writable_item_t
453 //
454 
455 //! Class for storing the buffers used for streaming body (request/response).
456 /*!
457  Supporting different types of entities that eventually result in
458  output data sent to peer is a bit tricky.
459  In the first step RESTionio distinguish two types of output data sources:
460  - trivial buffers (those ones that can be presented as a pair
461  of a pointer to data and the size of the data).
462  - sendfile (send a piece of data from file utilizing native
463  sendfile support Linux/FreeBSD/macOS and TransmitFile on windows).
464 
465  Also trivial buffers are implemented diferently for different cases,
466  includeing a template classes `impl::datasizeable_buf_t<Datasizeable>` and
467  `impl::shared_datasizeable_buf_t<Datasizeable>`.
468 
469  When using RESTinio response builder, response body can be constructed
470  using different types of buffers, and once the result
471  is flushed to the connection it must be sent to the socket.
472  A couple of issues arises here.
473  And one of them is how to store all these heterogeneous buffers
474  with fewer allocations and less boilerplate necessary
475  to handle each corner case.
476  Storing and moving a bunch of buffers as a vector would be
477  nice, but vector demands a single type to be used.
478  And writable_item_t represents a custom variant-like abstraction
479  for storing an arbitrary buffer object (`std::variant` itself is not the option
480  as it is restricted to types defined beforehand and cannot benifit
481  from the knowledge that all stored items are types derrived from
482  impl::writable_base_t).
483 
484  For storing the data of buffers #m_storage is used.
485  It is an aligned buffer sufficient to store
486  any impl::writable_base_t descendant (there is a limitation
487  concerned with impl::datasizeable_buf_t).
488  Also writable_item_t exposes interface to treat it
489  like a trivial buffer or a sendfile operation.
490  The type of buffer currently stored in writable_item_t
491  instance a write_type() function used.
492 
493  Having such writable_item_t class, RESTinio can store a sequence
494  of arbitrary buffers in `std::vector`.
495 
496  @par An important note about use placement new, reinterpret_cast and std::launder
497 
498  As described
499  [here](https://blog.panicsoftware.com/objects-their-lifetimes-and-pointers/)
500  (reserve
501  [URL](http://web.archive.org/web/20210723000232/https://blog.panicsoftware.com/objects-their-lifetimes-and-pointers/)) such code contains UB:
502 
503  @code
504  alignas(T) char buffer[sizeof(T)];
505  new(buffer) T{}; // (1)
506  T * p = reinterpret_cast<T*>(buffer); // (2)
507  @endcode
508 
509  The pointer `p` obtained at (2) is invalid because the lifetime of `buffer` ends
510  at point (1) and address of `buffer` can be used as an address of new object T.
511  The solution is to use std::launder function introduced in C++17:
512 
513  @code
514  alignas(T) char buffer[sizeof(T)];
515  new(buffer) T{}; // (1)
516  T * p = std::launder(reinterpret_cast<T*>(buffer)); // (2)
517  @endcode
518 
519  In that case `reinterpret_cast<T*>(buffer)` produces an invalid pointer that
520  contain a valid address of new object T. std::launder makes translates that
521  invalid pointer to a valid one and the resulting `p` can be used without UB.
522 */
524 {
525  public:
526  writable_item_t( const writable_item_t & ) = delete;
527  writable_item_t & operator = ( const writable_item_t & ) = delete;
528 
531  {
532  new( m_storage.data() ) impl::empty_buf_t{};
533  }
534 
537  {
538  new( m_storage.data() ) impl::const_buf_t{ const_buf.m_str, const_buf.m_size };
539  }
540 
541  template <
542  typename Datasizeable,
543  typename S = typename
544  std::enable_if_t<
545  !std::is_same<
547  Datasizeable >::value > >
550  {
551  static_assert(
553  "size of type is too big" );
554 
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 >
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 
580  {
582  }
583 
586  {
588  }
589 
592  {
593  if( this != &b )
594  {
598  }
599 
600  return *this;
601  }
602 
604  {
606  }
607 
608  //! Get a type of a stored buffer object.
610  write_type() const noexcept
611  {
612  return m_write_type;
613  }
614 
615  //! Get the size of the underlying buffer object.
616  std::size_t size() const { return get_writable_base()->size(); }
617 
618  //! Create a buf reference object used by ASIO.
619  /*!
620  \note Stored buffer must be of writable_item_type_t::trivial_write_operation.
621  */
622  asio_ns::const_buffer buf() const { return get_buf()->buffer(); }
623 
624  //! Get a reference to a sendfile operation.
625  /*!
626  @note Stored buffer must be of writable_item_type_t::file_write_operation.
627  @note
628  Since v.0.4.9 it is non-const method. It is because we have
629  to work with mutable sendfile_t on some platform (like Windows).
630  */
631  sendfile_t &
633  {
634  return get_sfwo()->sendfile_options();
635  }
636 
637  private:
638  void
640  {
643  }
644 
646 
647  /** @name Access an item as an object of specific types.
648  * @brief Casts a stored object to one of the types.
649  */
650  ///@{
651 
652  //! Access as writable_base_t item.
653  const impl::writable_base_t * get_writable_base() const noexcept
654  {
655  return std::launder(
656  reinterpret_cast< const impl::writable_base_t * >( m_storage.data() ) );
657  }
658 
659  //! Access as writable_base_t item.
661  {
662  return std::launder(
663  reinterpret_cast< impl::writable_base_t * >( m_storage.data() ) );
664  }
665 
666  //! Access as trivial buf item.
667  const impl::buf_iface_t * get_buf() const noexcept
668  {
669  return std::launder(
670  reinterpret_cast< const impl::buf_iface_t * >( m_storage.data() ) );
671  }
672 
673  //! Access as trivial buf item.
674  impl::buf_iface_t * get_buf() noexcept
675  {
676  return std::launder(
677  reinterpret_cast< impl::buf_iface_t * >( m_storage.data() ) );
678  }
679 
680  //! Access as sendfile_write_operation_t item.
682  {
683  return std::launder(
684  reinterpret_cast< impl::sendfile_write_operation_t * >( m_storage.data() ) );
685  }
686  ///@}
687 
688  //! A storage for a buffer object of various types.
689  /*!
690  * @note
691  * Before 0.6.15 std::aligned_storage_t was used as type of this
692  * buffer. But because std::aligned_storage_t is deprecated in C++23
693  * the type is changed in v.0.6.15.
694  */
695  alignas(impl::buffer_storage_align)
697 };
698 
699 //
700 // writable_items_container_t
701 //
702 
704 
705 //
706 // write_status_cb_t
707 //
708 
709 //! An alias for a callback to be invoked after the write operation of
710 //! a particular group of "buffers".
711 /*!
712  @since v.0.4.8
713 */
714 using write_status_cb_t =
715  std::function< void( const asio_ns::error_code & ec ) >;
716 
717 //
718 // write_group_t
719 //
720 
721 //! Group of writable items transported to the context of underlying connection
722 //! as one solid piece.
723 /*!
724  @since v.0.4.8
725 */
727 {
728  public:
729  //! Swap two groups.
730  friend void
731  swap( write_group_t & left, write_group_t & right ) noexcept
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 
739  //! Construct write group with a given bunch of writable items.
740  explicit write_group_t(
741  //! A buffer objects included in this group.
742  writable_items_container_t items ) noexcept
743  : m_items{ std::move( items ) }
744  , m_status_line_size{ 0 }
745  {}
746 
747  /** @name Copy semantics.
748  * @brief Not allowed.
749  */
750  ///@{
751  write_group_t( const write_group_t & ) = delete;
752  write_group_t & operator = ( const write_group_t & ) = delete;
753  ///@}
754 
755  /** @name Move semantics.
756  * @brief Moves object leaving a moved one in clean state.
757  */
758  ///@{
759  write_group_t( write_group_t && wg ) noexcept
760  : m_items{ std::move( wg.m_items ) }
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 
768  write_group_t & operator = ( write_group_t && wg ) noexcept
769  {
770  write_group_t tmp{ std::move( wg ) };
771  swap( *this, tmp );
772 
773  return *this;
774  }
775  ///@}
776 
777  //! Destruct object.
778  /*!
779  If notificator was not called it would be invoked with error.
780  */
781  ~write_group_t() noexcept
782  {
783  if( m_after_write_notificator )
784  {
785  restinio::utils::suppress_exceptions_quietly( [&] {
786  invoke_after_write_notificator_if_exists(
787  make_asio_compaible_error(
788  asio_convertible_error_t::write_group_destroyed_passively ) );
789  } );
790  }
791  }
792 
793  /** @name Auxiliary data.
794  * @brief Accessors for working with auxiliary data.
795  */
796  ///@{
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 
808  if( writable_item_type_t::trivial_write_operation !=
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 
823  m_status_line_size = n;
824  }
825  }
826 
827  //! Get status line size.
828  std::size_t
829  status_line_size() const noexcept
830  {
831  return m_status_line_size;
832  }
833 
834  //! Set after write notificator.
835  void
836  after_write_notificator( write_status_cb_t notificator ) noexcept
837  {
838  m_after_write_notificator = std::move( notificator );
839  }
840 
841  //! Is there an after write notificator set?
842  bool
844  {
845  return static_cast< bool >( m_after_write_notificator );
846  }
847 
848  //! Get after write notificator.
849  void
850  invoke_after_write_notificator_if_exists( const asio_ns::error_code & ec )
851  {
852  if( m_after_write_notificator )
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.
858  m_after_write_notificator = write_status_cb_t{};
859 
860  tmp( ec );
861  }
862  }
863  ///@}
864 
865  //! Get the count of stored items.
866  auto
867  items_count() const noexcept
868  {
869  return m_items.size();
870  }
871 
872  //! Get access to the stored items.
873  const auto &
874  items() const noexcept
875  {
876  return m_items;
877  }
878 
879  //! Get access to the stored items.
880  /*!
881  Should be used for cases where we should have a non-const
882  access to writeable items.
883 
884  @since v.0.4.9
885  */
886  auto &
887  items() noexcept
888  {
889  return m_items;
890  }
891 
892  //! Reset group.
893  void
894  reset() noexcept
895  {
896 
897  RESTINIO_ENSURE_NOEXCEPT_CALL( m_items.clear() );
898  m_status_line_size = 0;
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.
907  m_after_write_notificator = write_status_cb_t{};
908  }
909 
910  //! Merges with another group.
911  /*!
912  Two groups can be merged if the first one has no after-write callback
913  and the second one has no status line size.
914  */
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:
930  //! A buffer objects included in this group.
932 
933  //! A size of status line located in first "buffer".
934  /*!
935  If the value is not 0 then it means it references
936  a piece of data stored in the first buffer of m_items container.
937  */
939 
940  //! A callback to invoke once the the write opertaion of a given group completes.
942 };
943 
944 } /* namespace restinio */
const_buf_t(const const_buf_t &)=delete
write_group_t & operator=(write_group_t &&wg) noexcept
Definition: buffers.hpp:768
const impl::buf_iface_t * get_buf() const noexcept
Access as trivial buf item.
Definition: buffers.hpp:667
Item is a sendfile operation and implicates file write operation.
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
A base class for writable items.
Definition: buffers.hpp:60
Send file operation wrapper.
Definition: buffers.hpp:326
shared_datasizeable_buf_t & operator=(const shared_datasizeable_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:126
std::array< char, impl::needed_storage_max_size > m_storage
A storage for a buffer object of various types.
Definition: buffers.hpp:696
sendfile_write_operation_t & operator=(const sendfile_write_operation_t &)=delete
constexpr const_buffer_t const_buffer(const void *str, std::size_t size) noexcept
Definition: buffers.hpp:425
sendfile_write_operation_t(sendfile_t &&sf_opts)
Definition: buffers.hpp:331
writable_items_container_t m_items
A buffer objects included in this group.
Definition: buffers.hpp:931
virtual void relocate_to(void *storage) override
Move this buffer enitity to a given location.
Definition: buffers.hpp:232
writable_item_type_t
Buffers write operation type.
Definition: buffers.hpp:442
writable_base_t(writable_base_t &&)=default
bool has_after_write_notificator() const noexcept
Is there an after write notificator set?
Definition: buffers.hpp:843
~write_group_t() noexcept
Destruct object.
Definition: buffers.hpp:781
virtual asio_ns::const_buffer buffer() const override
Get asio buf entity.
Definition: buffers.hpp:109
empty_buf_t(const empty_buf_t &)=delete
const_buffer_t const_buffer(const char *str) noexcept
Definition: buffers.hpp:431
Item is a buffer and must be written trivially.
const_buf_t & operator=(const const_buf_t &)=delete
empty_buf_t(empty_buf_t &&)=default
const_buf_t(const_buf_t &&)=default
virtual std::size_t size() const override
Get the size of a writable piece of data.
Definition: buffers.hpp:244
constexpr const_buffer_t(const void *str, std::size_t size) noexcept
Definition: buffers.hpp:411
impl::buf_iface_t * get_buf() noexcept
Access as trivial buf item.
Definition: buffers.hpp:674
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, std::optional< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in std::optional<Value_Type> if parameter exis...
Definition: value_or.hpp:64
virtual void relocate_to(void *storage)=0
Move this buffer enitity to a given location.
void merge(write_group_t second)
Merges with another group.
Definition: buffers.hpp:916
void after_write_notificator(write_status_cb_t notificator) noexcept
Set after write notificator.
Definition: buffers.hpp:836
write_group_t(const write_group_t &)=delete
Helper class for setting a constant buffer storage explicitly.
Definition: buffers.hpp:409
empty_buf_t & operator=(const empty_buf_t &)=delete
virtual std::size_t size() const override
Get the size of a writable piece of data.
Definition: buffers.hpp:170
virtual void relocate_to(void *storage) override
Move this buffer enitity to a given location.
Definition: buffers.hpp:301
std::size_t status_line_size() const noexcept
Get status line size.
Definition: buffers.hpp:829
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
auto items_count() const noexcept
Get the count of stored items.
Definition: buffers.hpp:867
const impl::writable_base_t * get_writable_base() const noexcept
Access as writable_base_t item.
Definition: buffers.hpp:653
auto & items() noexcept
Get access to the stored items.
Definition: buffers.hpp:887
Internal interface for a trivial buffer-like entity.
Definition: buffers.hpp:81
const void *const m_str
Definition: buffers.hpp:418
writable_base_t(const writable_base_t &)=default
virtual void relocate_to(void *storage) override
Move this buffer enitity to a given location.
Definition: buffers.hpp:347
virtual std::size_t size() const override
Get the size of a writable piece of data.
Definition: buffers.hpp:352
writable_item_t & operator=(const writable_item_t &)=delete
virtual void relocate_to(void *storage) override
Move this buffer enitity to a given location.
Definition: buffers.hpp:114
std::unique_ptr< sendfile_t > m_sendfile_options
A pointer to sendfile operation details.
Definition: buffers.hpp:375
writable_item_t(const_buffer_t const_buf)
Definition: buffers.hpp:535
impl::sendfile_write_operation_t * get_sfwo() noexcept
Access as sendfile_write_operation_t item.
Definition: buffers.hpp:681
const auto & items() const noexcept
Get access to the stored items.
Definition: buffers.hpp:874
writable_base_t & operator=(const writable_base_t &)=delete
empty_buf_t & operator=(empty_buf_t &&)=delete
write_group_t(writable_items_container_t items) noexcept
Construct write group with a given bunch of writable items.
Definition: buffers.hpp:740
void invoke_after_write_notificator_if_exists(const asio_ns::error_code &ec)
Get after write notificator.
Definition: buffers.hpp:850
Group of writable items transported to the context of underlying connection as one solid piece...
Definition: buffers.hpp:726
impl::writable_base_t * get_writable_base() noexcept
Access as writable_base_t item.
Definition: buffers.hpp:660
shared_datasizeable_buf_t & operator=(shared_datasizeable_buf_t &&)=delete
datasizeable_buf_t(datasizeable_buf_t &&) noexcept=default
sendfile_t & sendfile_options() noexcept
Get sendfile operation detaiols.
Definition: buffers.hpp:368
write_group_t(write_group_t &&wg) noexcept
Definition: buffers.hpp:759
void status_line_size(std::size_t n)
Definition: buffers.hpp:798
shared_datasizeable_buf_t(shared_datasizeable_buf_t &&) noexcept=default
virtual std::size_t size() const override
Get the size of a writable piece of data.
Definition: buffers.hpp:313
friend void swap(write_group_t &left, write_group_t &right) noexcept
Swap two groups.
Definition: buffers.hpp:731
const void *const m_data
A pointer to data.
Definition: buffers.hpp:175
const_buf_t & operator=(const_buf_t &&)=delete
virtual asio_ns::const_buffer buffer() const override
Get asio buf entity.
Definition: buffers.hpp:153
sendfile_write_operation_t(const sendfile_write_operation_t &)=delete
void reset() noexcept
Reset group.
Definition: buffers.hpp:894
const std::size_t m_size
The size of data.
Definition: buffers.hpp:177
sendfile_write_operation_t(sendfile_write_operation_t &&)=default
writable_base_t & operator=(writable_base_t &&)=delete
constexpr std::size_t buffer_storage_align
Definition: buffers.hpp:379
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
const std::size_t m_size
Definition: buffers.hpp:419
Datasizeable m_custom_buffer
A datasizeable item that represents buffer.
Definition: buffers.hpp:249
write_group_t & operator=(const write_group_t &)=delete
sendfile_write_operation_t & operator=(sendfile_write_operation_t &&)=delete
shared_ptr_t m_buf_ptr
A shared pointer to a datasizeable entity.
Definition: buffers.hpp:318
writable_item_t(const writable_item_t &)=delete
virtual std::size_t size() const =0
Get the size of a writable piece of data.
virtual asio_ns::const_buffer buffer() const =0
Get asio buf entity.
shared_datasizeable_buf_t(shared_ptr_t buf_ptr) noexcept
Definition: buffers.hpp:280
shared_datasizeable_buf_t(const shared_datasizeable_buf_t &)=delete
User defined datasizable object.
Definition: buffers.hpp:189
constexpr const_buf_t(const void *data, std::size_t size) noexcept
Definition: buffers.hpp:136
virtual asio_ns::const_buffer buffer() const override
Get asio buf entity.
Definition: buffers.hpp:296
Buffer based on shared_ptr of data-sizeable entity.
Definition: buffers.hpp:273
std::size_t m_status_line_size
A size of status line located in first "buffer".
Definition: buffers.hpp:938