1 /** @file
2 
3   I/O classes
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22 
23   @section watermark Watermark
24 
25   Watermarks can be used as an interface between the data transferring
26   layer (VConnection) and the user layer (a state machine).  Watermarks
27   should be used when you need to have at least a certain amount of data
28   to make some determination.  For example, when parsing a string, one
29   might wish to ensure that an entire line will come in before consuming
30   the data.  In such a case, the water_mark should be set to the largest
31   possible size of the string. (appropriate error handling should take
32   care of excessively long strings).
33 
34   In all other cases, especially when all data will be consumed, the
35   water_mark should be set to 0 (the default).
36 
37  */
38 
39 #pragma once
40 #define I_IOBuffer_h
41 
42 #include "tscore/ink_platform.h"
43 #include "tscore/ink_apidefs.h"
44 #include "tscore/Allocator.h"
45 #include "tscore/Ptr.h"
46 #include "tscore/ink_assert.h"
47 #include "tscore/ink_resource.h"
48 
49 struct MIOBufferAccessor;
50 
51 class MIOBuffer;
52 class IOBufferReader;
53 class VIO;
54 
55 // Removing this optimization since this is breaking WMT over HTTP
56 //#define WRITE_AND_TRANSFER
57 
58 inkcoreapi extern int64_t max_iobuffer_size;
59 extern int64_t default_small_iobuffer_size;
60 extern int64_t default_large_iobuffer_size; // matched to size of OS buffers
61 
62 #if !defined(TRACK_BUFFER_USER)
63 #define TRACK_BUFFER_USER 1
64 #endif
65 
66 enum AllocType {
67   NO_ALLOC,
68   FAST_ALLOCATED,
69   XMALLOCED,
70   MEMALIGNED,
71   DEFAULT_ALLOC,
72   CONSTANT,
73 };
74 
75 #define DEFAULT_BUFFER_NUMBER 128
76 #define DEFAULT_HUGE_BUFFER_NUMBER 32
77 #define MAX_MIOBUFFER_READERS 5
78 #define DEFAULT_BUFFER_ALIGNMENT 8192 // should be disk/page size
79 #define DEFAULT_BUFFER_BASE_SIZE 128
80 
81 ////////////////////////////////////////////////
82 // These are defines so that code that used 2 //
83 // for buffer size index when 2 was 2K will   //
84 // still work if it uses BUFFER_SIZE_INDEX_2K //
85 // instead.                                   //
86 ////////////////////////////////////////////////
87 #define BUFFER_SIZE_INDEX_128 0
88 #define BUFFER_SIZE_INDEX_256 1
89 #define BUFFER_SIZE_INDEX_512 2
90 #define BUFFER_SIZE_INDEX_1K 3
91 #define BUFFER_SIZE_INDEX_2K 4
92 #define BUFFER_SIZE_INDEX_4K 5
93 #define BUFFER_SIZE_INDEX_8K 6
94 #define BUFFER_SIZE_INDEX_16K 7
95 #define BUFFER_SIZE_INDEX_32K 8
96 #define BUFFER_SIZE_INDEX_64K 9
97 #define BUFFER_SIZE_INDEX_128K 10
98 #define BUFFER_SIZE_INDEX_256K 11
99 #define BUFFER_SIZE_INDEX_512K 12
100 #define BUFFER_SIZE_INDEX_1M 13
101 #define BUFFER_SIZE_INDEX_2M 14
102 #define MAX_BUFFER_SIZE_INDEX 14
103 #define DEFAULT_BUFFER_SIZES (MAX_BUFFER_SIZE_INDEX + 1)
104 
105 #define BUFFER_SIZE_FOR_INDEX(_i) (DEFAULT_BUFFER_BASE_SIZE * (1 << (_i)))
106 #define DEFAULT_SMALL_BUFFER_SIZE BUFFER_SIZE_INDEX_512
107 #define DEFAULT_LARGE_BUFFER_SIZE BUFFER_SIZE_INDEX_4K
108 #define DEFAULT_TS_BUFFER_SIZE BUFFER_SIZE_INDEX_8K
109 #define DEFAULT_MAX_BUFFER_SIZE BUFFER_SIZE_FOR_INDEX(MAX_BUFFER_SIZE_INDEX)
110 #define MIN_IOBUFFER_SIZE BUFFER_SIZE_INDEX_128
111 #define MAX_IOBUFFER_SIZE (DEFAULT_BUFFER_SIZES - 1)
112 
113 #define BUFFER_SIZE_ALLOCATED(_i) (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_i) || BUFFER_SIZE_INDEX_IS_XMALLOCED(_i))
114 
115 #define BUFFER_SIZE_NOT_ALLOCATED DEFAULT_BUFFER_SIZES
116 #define BUFFER_SIZE_INDEX_IS_XMALLOCED(_size_index) (_size_index < 0)
117 #define BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index) (((uint64_t)_size_index) < DEFAULT_BUFFER_SIZES)
118 #define BUFFER_SIZE_INDEX_IS_CONSTANT(_size_index) (_size_index >= DEFAULT_BUFFER_SIZES)
119 
120 #define BUFFER_SIZE_FOR_XMALLOC(_size) (-(_size))
121 #define BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(_size) (-(_size))
122 
123 #define BUFFER_SIZE_FOR_CONSTANT(_size) (_size - DEFAULT_BUFFER_SIZES)
124 #define BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(_size) (_size + DEFAULT_BUFFER_SIZES)
125 
126 inkcoreapi extern Allocator ioBufAllocator[DEFAULT_BUFFER_SIZES];
127 
128 void init_buffer_allocators(int iobuffer_advice);
129 
130 /**
131   A reference counted wrapper around fast allocated or malloced memory.
132   The IOBufferData class provides two basic services around a portion
133   of allocated memory.
134 
135   First, it is a reference counted object and ...
136 
137   @remarks The AllocType enum, is used to define the type of allocation
138   for the memory this IOBufferData object manages.
139 
140   <table>
141     <tr>
142       <td align="center">AllocType</td>
143       <td align="center">Meaning</td>
144     </tr>
145     <tr>
146       <td>NO_ALLOC</td>
147       <td></td>
148     </tr>
149     <tr>
150       <td>FAST_ALLOCATED</td>
151       <td></td>
152     </tr>
153     <tr>
154       <td>XMALLOCED</td>
155       <td></td>
156     </tr>
157     <tr>
158       <td>MEMALIGNED</td>
159       <td></td>
160     </tr>
161     <tr>
162       <td>DEFAULT_ALLOC</td>
163       <td></td>
164     </tr>
165     <tr>
166       <td>CONSTANT</td>
167       <td></td>
168     </tr>
169   </table>
170 
171  */
172 class IOBufferData : public RefCountObj
173 {
174 public:
175   /**
176     The size of the memory allocated by this IOBufferData. Calculates
177     the amount of memory allocated by this IOBufferData.
178 
179     @return number of bytes allocated for the '_data' member.
180 
181   */
182   int64_t block_size();
183 
184   /**
185     Frees the memory managed by this IOBufferData.  Deallocates the
186     memory previously allocated by this IOBufferData object. It frees
187     the memory pointed to by '_data' according to the '_mem_type' and
188     '_size_index' members.
189 
190   */
191   void dealloc();
192 
193   /**
194     Allocates memory and sets this IOBufferData to point to it.
195     Allocates memory according to the size_index and type
196     parameters. Any previously allocated memory pointed to by
197     this IOBufferData is deallocated.
198 
199     @param size_index
200     @param type of allocation to use; see remarks section.
201   */
202   void alloc(int64_t size_index, AllocType type = DEFAULT_ALLOC);
203 
204   /**
205     Provides access to the allocated memory. Returns the address of the
206     allocated memory handled by this IOBufferData.
207 
208     @return address of the memory handled by this IOBufferData.
209 
210   */
211   char *
212   data()
213   {
214     return _data;
215   }
216 
217   /**
218     Cast operator. Provided as a convenience, the cast to a char* applied
219     to the IOBufferData returns the address of the memory handled by the
220     IOBuffer data. In this manner, objects of this class can be used as
221     parameter to functions requiring a char*.
222 
223   */
224   operator char *() { return _data; }
225   /**
226     Frees the IOBufferData object and its underlying memory. Deallocates
227     the memory managed by this IOBufferData and then frees itself. You
228     should not use this object or reference after this call.
229 
230   */
231   void free() override;
232 
233   int64_t _size_index;
234 
235   /**
236     Type of allocation used for the managed memory. Stores the type of
237     allocation used for the memory currently managed by the IOBufferData
238     object. Do not set or modify this value directly. Instead use the
239     alloc or dealloc methods.
240 
241   */
242   AllocType _mem_type = NO_ALLOC;
243 
244   /**
245     Points to the allocated memory. This member stores the address of
246     the allocated memory. You should not modify its value directly,
247     instead use the alloc or dealloc methods.
248 
249   */
250   char *_data = nullptr;
251 
252 #ifdef TRACK_BUFFER_USER
253   const char *_location = nullptr;
254 #endif
255 
256   /**
257     Constructor. Initializes state for a IOBufferData object. Do not use
258     this method. Use one of the functions with the 'new_' prefix instead.
259 
260   */
261   IOBufferData() : _size_index(BUFFER_SIZE_NOT_ALLOCATED) {}
262 
263   // noncopyable, declaration only
264   IOBufferData(const IOBufferData &) = delete;
265   IOBufferData &operator=(const IOBufferData &) = delete;
266 };
267 
268 inkcoreapi extern ClassAllocator<IOBufferData> ioDataAllocator;
269 
270 /**
271   A linkable portion of IOBufferData. IOBufferBlock is a chainable
272   buffer block descriptor. The IOBufferBlock represents both the used
273   and available space in the underlying block. The IOBufferBlock is not
274   sharable between buffers but rather represents what part of the data
275   block is both in use and usable by the MIOBuffer it is attached to.
276 
277 */
278 class IOBufferBlock : public RefCountObj
279 {
280 public:
281   /**
282     Access the actual data. Provides access to rhe underlying data
283     managed by the IOBufferData.
284 
285     @return pointer to the underlying data.
286 
287   */
288   char *
289   buf()
290   {
291     return data->_data;
292   }
293 
294   /**
295     Beginning of the inuse section. Returns the position in the buffer
296     where the inuse area begins.
297 
298     @return pointer to the start of the inuse section.
299 
300   */
301   char *
302   start()
303   {
304     return _start;
305   }
306 
307   /**
308     End of the used space. Returns a pointer to end of the used space
309     in the data buffer represented by this block.
310 
311     @return pointer to the end of the inuse portion of the block.
312 
313   */
314   char *
315   end()
316   {
317     return _end;
318   }
319 
320   /**
321     End of the data buffer. Returns a pointer to end of the data buffer
322     represented by this block.
323 
324   */
325   char *
326   buf_end()
327   {
328     return _buf_end;
329   }
330 
331   /**
332     Size of the inuse area. Returns the size of the current inuse area.
333 
334     @return bytes occupied by the inuse area.
335 
336   */
337   int64_t
338   size()
339   {
340     return (int64_t)(_end - _start);
341   }
342 
343   /**
344     Size of the data available for reading. Returns the size of the data
345     available for reading in the inuse area.
346 
347     @return bytes available for reading from the inuse area.
348 
349   */
350   int64_t
351   read_avail() const
352   {
353     return (int64_t)(_end - _start);
354   }
355 
356   /**
357     Space available in the buffer. Returns the number of bytes that can
358     be written to the data buffer.
359 
360     @return space available for writing in this IOBufferBlock.
361   */
362   int64_t
363   write_avail()
364   {
365     return (int64_t)(_buf_end - _end);
366   }
367 
368   /**
369     Size of the memory allocated by the underlying IOBufferData.
370     Computes the size of the entire block, which includes the used and
371     available areas. It is the memory allocated by the IOBufferData
372     referenced by this IOBufferBlock.
373 
374     @return bytes allocated to the IOBufferData referenced by this
375       IOBufferBlock.
376 
377   */
378   int64_t
379   block_size()
380   {
381     return data->block_size();
382   }
383 
384   /**
385     Decrease the size of the inuse area. Moves forward the start of
386     the inuse area. This also decreases the number of available bytes
387     for reading.
388 
389     @param len bytes to consume or positions to skip for the start of
390       the inuse area.
391 
392   */
393   void consume(int64_t len);
394 
395   /**
396     Increase the inuse area of the block. Adds 'len' bytes to the inuse
397     area of the block. Data should be copied into the data buffer by
398     using end() to find the start of the free space in the data buffer
399     before calling fill()
400 
401     @param len bytes to increase the inuse area. It must be less than
402       or equal to the value of write_avail().
403 
404   */
405   void fill(int64_t len);
406 
407   /**
408     Reset the inuse area. The start and end of the inuse area are reset
409     but the actual IOBufferData referenced by this IOBufferBlock is not
410     modified.  This effectively reduces the number of bytes available
411     for reading to zero, and the number of bytes available for writing
412     to the size of the entire buffer.
413 
414   */
415   void reset();
416 
417   /**
418     Create a copy of the IOBufferBlock. Creates and returns a copy of this
419     IOBufferBlock that references the same data that this IOBufferBlock
420     (it does not allocate an another buffer). The cloned block will not
421     have a writable space since the original IOBufferBlock maintains the
422     ownership for writing data to the block.
423 
424     @return copy of this IOBufferBlock.
425 
426   */
427   IOBufferBlock *clone() const;
428 
429   /**
430     Clear the IOBufferData this IOBufferBlock handles. Clears this
431     IOBufferBlock's reference to the data buffer (IOBufferData). You can
432     use alloc after this call to allocate an IOBufferData associated to
433     this IOBufferBlock.
434 
435   */
436   void clear();
437 
438   /**
439     Allocate a data buffer. Allocates a data buffer for this IOBufferBlock
440     based on index 'i'.  Index values are described in the remarks
441     section in MIOBuffer.
442 
443   */
444   void alloc(int64_t i = default_large_iobuffer_size);
445 
446   /**
447     Clear the IOBufferData this IOBufferBlock handles. Clears this
448     IOBufferBlock's reference to the data buffer (IOBufferData).
449 
450   */
451   void dealloc();
452 
453   /**
454     Set or replace this IOBufferBlock's IOBufferData member. Sets this
455     IOBufferBlock's IOBufferData member to point to the IOBufferData
456     passed in. You can optionally specify the inuse area with the 'len'
457     argument and an offset for the start.
458 
459     @param d new IOBufferData this IOBufferBlock references.
460     @param len in use area to set. It must be less than or equal to the
461       length of the block size *IOBufferData).
462     @param offset bytes to skip from the beginning of the IOBufferData
463       and to mark its start.
464 
465   */
466   void set(IOBufferData *d, int64_t len = 0, int64_t offset = 0);
467   void set_internal(void *b, int64_t len, int64_t asize_index);
468   void realloc_set_internal(void *b, int64_t buf_size, int64_t asize_index);
469   void realloc(void *b, int64_t buf_size);
470   void realloc(int64_t i);
471   void realloc_xmalloc(void *b, int64_t buf_size);
472   void realloc_xmalloc(int64_t buf_size);
473 
474   /**
475     Frees the IOBufferBlock object and its underlying memory.
476     Removes the reference to the IOBufferData object and then frees
477     itself. You should not use this object or reference after this
478     call.
479 
480   */
481   void free() override;
482 
483   char *_start   = nullptr;
484   char *_end     = nullptr;
485   char *_buf_end = nullptr;
486 
487 #ifdef TRACK_BUFFER_USER
488   const char *_location = nullptr;
489 #endif
490 
491   /**
492     The underlying reference to the allocated memory. A reference to a
493     IOBufferData representing the memory allocated to this buffer. Do
494     not set or modify its value directly.
495 
496   */
497   Ptr<IOBufferData> data;
498 
499   /**
500     Reference to another IOBufferBlock. A reference to another
501     IOBufferBlock that allows this object to link to other.
502 
503   */
504   Ptr<IOBufferBlock> next;
505 
506   /**
507     Constructor of a IOBufferBlock. Do not use it to create a new object,
508     instead call new_IOBufferBlock
509 
510   */
511   IOBufferBlock();
512 
513   // noncopyable
514   IOBufferBlock(const IOBufferBlock &) = delete;
515   IOBufferBlock &operator=(const IOBufferBlock &) = delete;
516 };
517 
518 extern inkcoreapi ClassAllocator<IOBufferBlock> ioBlockAllocator;
519 
520 /** A class for holding a chain of IO buffer blocks.
521     This class is intended to be used as a member variable for other classes that
522     need to anchor an IO Buffer chain but don't need the full @c MIOBuffer machinery.
523     That is, the owner is the only reader/writer of the data.
524 
525     This does not handle incremental reads or writes well. The intent is that data is
526     placed in the instance, held for a while, then used and discarded.
527 
528     @note Contrast also with @c IOBufferReader which is similar but requires an
529     @c MIOBuffer as its owner.
530 */
531 class IOBufferChain
532 {
533   using self_type = IOBufferChain; ///< Self reference type.
534 
535 public:
536   /// Default constructor - construct empty chain.
537   IOBufferChain() = default;
538   /// Shallow copy.
539   self_type &operator=(self_type const &that);
540 
541   /// Shallow append.
542   self_type &operator+=(self_type const &that);
543 
544   /// Number of bytes of content.
545   int64_t length() const;
546 
547   /// Copy a chain of @a blocks in to this object up to @a length bytes.
548   /// If @a offset is greater than 0 that many bytes are skipped. Those bytes do not count
549   /// as part of @a length.
550   /// This creates a new chain using existing data blocks. This
551   /// breaks the original chain so that changes there (such as appending blocks)
552   /// is not reflected in this chain.
553   /// @return The number of bytes written to the chain.
554   int64_t write(IOBufferBlock *blocks, int64_t length, int64_t offset = 0);
555 
556   /// Add the content of a buffer block.
557   /// The buffer block is unchanged.
558   int64_t write(IOBufferData *data, int64_t length = 0, int64_t offset = 0);
559 
560   /// Remove @a size bytes of content from the front of the chain.
561   /// @return The actual number of bytes removed.
562   int64_t consume(int64_t size);
563 
564   /// Clear current chain.
565   void clear();
566 
567   /// Get the first block.
568   IOBufferBlock *head();
569   IOBufferBlock const *head() const;
570 
571   /// STL Container support.
572 
573   /// Block iterator.
574   /// @internal The reason for this is to override the increment operator.
575   class const_iterator : public std::forward_iterator_tag
576   {
577     using self_type = const_iterator; ///< Self reference type.
578   protected:
579     /// Current buffer block.
580     IOBufferBlock *_b = nullptr;
581 
582   public:
583     using value_type = const IOBufferBlock; ///< Iterator value type.
584 
585     const_iterator() = default; ///< Default constructor.
586 
587     /// Copy constructor.
588     // cppcheck-suppress noExplicitConstructor; copy constructor
589     const_iterator(self_type const &that);
590 
591     /// Assignment.
592     self_type &operator=(self_type const &that);
593 
594     /// Equality.
595     bool operator==(self_type const &that) const;
596     /// Inequality.
597     bool operator!=(self_type const &that) const;
598 
599     value_type &operator*() const;
600     value_type *operator->() const;
601 
602     self_type &operator++();
603     self_type operator++(int);
604   };
605 
606   class iterator : public const_iterator
607   {
608     using self_type = iterator; ///< Self reference type.
609   public:
610     using value_type = IOBufferBlock; ///< Dereferenced type.
611 
612     value_type &operator*() const;
613     value_type *operator->() const;
614   };
615 
616   using value_type = IOBufferBlock;
617 
618   iterator begin();
619   const_iterator begin() const;
620 
621   iterator end();
622   const_iterator end() const;
623 
624 protected:
625   /// Append @a block.
626   void append(IOBufferBlock *block);
627 
628   /// Head of buffer block chain.
629   Ptr<IOBufferBlock> _head;
630   /// Tail of the block chain.
631   IOBufferBlock *_tail = nullptr;
632   /// The amount of data of interest.
633   /// Not necessarily the amount of data in the chain of blocks.
634   int64_t _len = 0;
635 };
636 
637 /**
638   An independent reader from an MIOBuffer. A reader for a set of
639   IOBufferBlocks. The IOBufferReader represents the place where a given
640   consumer of buffer data is reading from. It provides a uniform interface
641   for easily accessing the data contained in a list of IOBufferBlocks
642   associated with the IOBufferReader.
643 
644   IOBufferReaders are the abstraction that determine when data blocks
645   can be removed from the buffer.
646 
647 */
648 class IOBufferReader
649 {
650 public:
651   /**
652     Start of unconsumed data. Returns a pointer to first unconsumed data
653     on the buffer for this reader. A null pointer indicates no data is
654     available. It uses the current start_offset value.
655 
656     @return pointer to the start of the unconsumed data.
657 
658   */
659   char *start();
660 
661   /**
662     End of inuse area of the first block with unconsumed data. Returns a
663     pointer to the end of the first block with unconsumed data for this
664     reader. A nullptr pointer indicates there are no blocks with unconsumed
665     data for this reader.
666 
667     @return pointer to the end of the first block with unconsumed data.
668 
669   */
670   char *end();
671 
672   /**
673     Amount of data available across all of the IOBufferBlocks. Returns the
674     number of unconsumed bytes of data available to this reader across
675     all remaining IOBufferBlocks. It subtracts the current start_offset
676     value from the total.
677 
678     @return bytes of data available across all the buffers.
679 
680   */
681   int64_t read_avail();
682 
683   /** Check if there is more than @a size bytes available to read.
684       @return @c true if more than @a size byte are available.
685   */
686   bool is_read_avail_more_than(int64_t size);
687 
688   /**
689     Number of IOBufferBlocks with data in the block list. Returns the
690     number of IOBufferBlocks on the block list with data remaining for
691     this reader.
692 
693     @return number of blocks with data for this reader.
694 
695   */
696   int block_count();
697 
698   /**
699     Amount of data available in the first buffer with data for this
700     reader.  Returns the number of unconsumed bytes of data available
701     on the first IOBufferBlock with data for this reader.
702 
703     @return number of unconsumed bytes of data available in the first
704       buffer.
705 
706   */
707   int64_t block_read_avail();
708 
709   /** Get a view of the data available to read.
710    *
711    * @return A view encompassing currently available readable data.
712    */
713   std::string_view block_read_view();
714 
715   void skip_empty_blocks();
716 
717   /**
718     Clears all fields in this IOBuffeReader, rendering it unusable. Drops
719     the reference to the IOBufferBlock list, the accessor, MIOBuffer and
720     resets this reader's state. You have to set those fields in order
721     to use this object again.
722 
723   */
724   void clear();
725 
726   /**
727     Instruct the reader to reset the IOBufferBlock list. Resets the
728     reader to the point to the start of the block where new data will
729     be written. After this call, the start_offset field is set to zero
730     and the list of IOBufferBlocks is set using the associated MIOBuffer.
731 
732   */
733   void reset();
734 
735   /**
736     Consume a number of bytes from this reader's IOBufferBlock
737     list. Advances the current position in the IOBufferBlock list of
738     this reader by n bytes.
739 
740     @param n number of bytes to consume. It must be less than or equal
741       to read_avail().
742 
743   */
744   void consume(int64_t n);
745 
746   /**
747     Create another reader with access to the same data as this
748     IOBufferReader. Allocates a new reader with the same state as this
749     IOBufferReader. This means that the new reader will point to the same
750     list of IOBufferBlocks and to the same buffer position as this reader.
751 
752     @return new reader with the same state as this.
753 
754   */
755   IOBufferReader *clone();
756 
757   /**
758     Deallocate this reader. Removes and deallocates this reader from
759     the underlying MIOBuffer. This IOBufferReader object must not be
760     used after this call.
761 
762   */
763   void dealloc();
764 
765   /**
766     Get a pointer to the first block with data. Returns a pointer to
767     the first IOBufferBlock in the block chain with data available for
768     this reader
769 
770     @return pointer to the first IOBufferBlock in the list with data
771       available for this reader.
772 
773   */
774   IOBufferBlock *get_current_block();
775 
776   /**
777     Consult this reader's MIOBuffer writable space. Queries the MIOBuffer
778     associated with this reader about the amount of writable space
779     available without adding any blocks on the buffer and returns true
780     if it is less than the water mark.
781 
782     @return true if the MIOBuffer associated with this IOBufferReader
783       returns true in MIOBuffer::current_low_water().
784 
785   */
786   bool current_low_water();
787 
788   /**
789     Queries the underlying MIOBuffer about. Returns true if the amount
790     of writable space after adding a block on the underlying MIOBuffer
791     is less than its water mark. This function call may add blocks to
792     the MIOBuffer (see MIOBuffer::low_water()).
793 
794     @return result of MIOBuffer::low_water() on the MIOBuffer for
795       this reader.
796 
797   */
798   bool low_water();
799 
800   /**
801     To see if the amount of data available to the reader is greater than
802     the MIOBuffer's water mark. Indicates whether the amount of data
803     available to this reader exceeds the water mark for this reader's
804     MIOBuffer.
805 
806     @return true if the amount of data exceeds the MIOBuffer's water mark.
807 
808   */
809   bool high_water();
810 
811   /**
812     Perform a memchr() across the list of IOBufferBlocks. Returns the
813     offset from the current start point of the reader to the first
814     occurrence of character 'c' in the buffer.
815 
816     @param c character to look for.
817     @param len number of characters to check. If len exceeds the number
818       of bytes available on the buffer or INT64_MAX is passed in, the
819       number of bytes available to the reader is used. It is independent
820       of the offset value.
821     @param offset number of the bytes to skip over before beginning
822       the operation.
823     @return -1 if c is not found, otherwise position of the first
824       occurrence.
825 
826   */
827   inkcoreapi int64_t memchr(char c, int64_t len = INT64_MAX, int64_t offset = 0);
828 
829   /**
830     Copies and consumes data. Copies len bytes of data from the buffer
831     into the supplied buffer, which must be allocated prior to the call
832     and it must be at large enough for the requested bytes. Once the
833     data is copied, it consumed from the reader.
834 
835     @param buf in which to place the data.
836     @param len bytes to copy and consume. If 'len' exceeds the bytes
837       available to the reader, the number of bytes available is used
838       instead.
839 
840     @return number of bytes copied and consumed.
841 
842   */
843   inkcoreapi int64_t read(void *buf, int64_t len);
844 
845   /**
846     Copy data but do not consume it. Copies 'len' bytes of data from
847     the current buffer into the supplied buffer. The copy skips the
848     number of bytes specified by 'offset' beyond the current point of
849     the reader. It also takes into account the current start_offset value.
850 
851     @param buf in which to place the data. The pointer is modified after
852       the call and points one position after the end of the data copied.
853     @param len bytes to copy. If len exceeds the bytes available to the
854       reader or INT64_MAX is passed in, the number of bytes available is
855       used instead. No data is consumed from the reader in this operation.
856     @param offset bytes to skip from the current position. The parameter
857       is modified after the call.
858     @return pointer to one position after the end of the data copied. The
859       parameter buf is set to this value also.
860 
861   */
862   inkcoreapi char *memcpy(void *buf, int64_t len = INT64_MAX, int64_t offset = 0);
863 
864   /**
865     Subscript operator. Returns a reference to the character at the
866     specified position. You must ensure that it is within an appropriate
867     range.
868 
869     @param i positions beyond the current point of the reader. It must
870       be less than the number of the bytes available to the reader.
871 
872     @return reference to the character in that position.
873 
874   */
875   char &operator[](int64_t i);
876 
877   MIOBuffer *
878   writer() const
879   {
880     return mbuf;
881   }
882   MIOBuffer *
883   allocated() const
884   {
885     return mbuf;
886   }
887 
888   MIOBufferAccessor *accessor = nullptr; // pointer back to the accessor
889 
890   /**
891     Back pointer to this object's MIOBuffer. A pointer back to the
892     MIOBuffer this reader is allocated from.
893 
894   */
895   MIOBuffer *mbuf = nullptr;
896   Ptr<IOBufferBlock> block;
897 
898   /**
899     Offset beyond the shared start(). The start_offset is used in the
900     calls that copy or consume data and is an offset at the beginning
901     of the available data.
902 
903   */
904   int64_t start_offset = 0;
905   int64_t size_limit   = INT64_MAX;
906 
907   IOBufferReader() {}
908 };
909 
910 /**
911   A multiple reader, single writer memory buffer. MIOBuffers are at
912   the center of all IOCore data transfer. MIOBuffers are the data
913   buffers used to transfer data to and from VConnections. A MIOBuffer
914   points to a list of IOBufferBlocks which in turn point to IOBufferData
915   structures that in turn point to the actual data. MIOBuffer allows one
916   producer and multiple consumers. The buffer fills up according the
917   amount of data outstanding for the slowest consumer. Thus, MIOBuffer
918   implements automatic flow control between readers of different speeds.
919   Data on IOBuffer is immutable. Once written it cannot be modified, only
920   deallocated once all consumers have finished with it. Immutability is
921   necessary since data can be shared between buffers, which means that
922   multiple IOBufferBlock objects may reference the same data but only
923   one will have ownership for writing.
924 
925 */
926 class MIOBuffer
927 {
928 public:
929   /**
930     Increase writer's inuse area. Instructs the writer associated with
931     this MIOBuffer to increase the inuse area of the block by as much as
932     'len' bytes.
933 
934     @param len number of bytes to add to the inuse area of the block.
935 
936   */
937   void fill(int64_t len);
938 
939   /**
940     Adds a block to the end of the block list. The block added to list
941     must be writable by this buffer and must not be writable by any
942     other buffer.
943 
944   */
945   void append_block(IOBufferBlock *b);
946 
947   /**
948     Adds a new block to the end of the block list. The size is determined
949     by asize_index. See the remarks section for a mapping of indexes to
950     buffer block sizes.
951 
952   */
953   void append_block(int64_t asize_index);
954 
955   /**
956     Adds new block to the end of block list using the block size for
957     the buffer specified when the buffer was allocated.
958 
959   */
960   void add_block();
961 
962   /**
963     Adds by reference len bytes of data pointed to by b to the end
964     of the buffer.  b MUST be a pointer to the beginning of  block
965     allocated from the ats_xmalloc() routine. The data will be deallocated
966     by the buffer once all readers on the buffer have consumed it.
967 
968   */
969   void append_xmalloced(void *b, int64_t len);
970 
971   /**
972     Adds by reference len bytes of data pointed to by b to the end of the
973     buffer. b MUST be a pointer to the beginning of  block allocated from
974     ioBufAllocator of the corresponding index for fast_size_index. The
975     data will be deallocated by the buffer once all readers on the buffer
976     have consumed it.
977 
978   */
979   void append_fast_allocated(void *b, int64_t len, int64_t fast_size_index);
980 
981   /**
982     Adds the nbytes worth of data pointed by rbuf to the buffer. The
983     data is copied into the buffer. write() does not respect watermarks
984     or buffer size limits. Users of write must implement their own flow
985     control. Returns the number of bytes added.
986 
987   */
988   inkcoreapi int64_t write(const void *rbuf, int64_t nbytes);
989 
990 #ifdef WRITE_AND_TRANSFER
991   /**
992     Same functionality as write but for the one small difference. The
993     space available in the last block is taken from the original and
994     this space becomes available to the copy.
995 
996   */
997   inkcoreapi int64_t write_and_transfer_left_over_space(IOBufferReader *r, int64_t len = INT64_MAX, int64_t offset = 0);
998 #endif
999 
1000   /**
1001     Add by data from IOBufferReader r to the this buffer by reference. If
1002     len is INT64_MAX, all available data on the reader is added. If len is
1003     less than INT64_MAX, the smaller of len or the amount of data on the
1004     buffer is added. If offset is greater than zero, than the offset
1005     bytes of data at the front of the reader are skipped. Bytes skipped
1006     by offset reduce the number of bytes available on the reader used
1007     in the amount of data to add computation. write() does not respect
1008     watermarks or buffer size limits. Users of write must implement
1009     their own flow control. Returns the number of bytes added. Each
1010     write() call creates a new IOBufferBlock, even if it is for one
1011     byte. As such, it's necessary to exercise caution in any code that
1012     repeatedly transfers data from one buffer to another, especially if
1013     the data is being read over the network as it may be coming in very
1014     small chunks. Because deallocation of outstanding buffer blocks is
1015     recursive, it's possible to overrun the stack if too many blocks
1016     have been added to the buffer chain. It's imperative that users
1017     both implement their own flow control to prevent too many bytes
1018     from becoming outstanding on a buffer that the write() call is
1019     being used and that care be taken to ensure the transfers are of a
1020     minimum size. Should it be necessary to make a large number of small
1021     transfers, it's preferable to use a interface that copies the data
1022     rather than sharing blocks to prevent a build of blocks on the buffer.
1023 
1024   */
1025   inkcoreapi int64_t write(IOBufferReader *r, int64_t len = INT64_MAX, int64_t offset = 0);
1026 
1027   /** Copy data from the @a chain to this buffer.
1028       New IOBufferBlocks are allocated so this gets a copy of the data that is independent of the source.
1029       @a offset bytes are skipped at the start of the @a chain. The length is bounded by @a len and the
1030       size in the @a chain.
1031 
1032       @return the number of bytes copied.
1033 
1034       @internal I do not like counting @a offset against @a bytes but that's how @c write works...
1035   */
1036   int64_t write(IOBufferChain const *chain, int64_t len = INT64_MAX, int64_t offset = 0);
1037 
1038   int64_t remove_append(IOBufferReader *);
1039 
1040   /**
1041     Returns a pointer to the first writable block on the block chain.
1042     Returns nullptr if there are not currently any writable blocks on the
1043     block list.
1044   */
1045   IOBufferBlock *
1046   first_write_block()
1047   {
1048     if (_writer) {
1049       if (_writer->next && !_writer->write_avail()) {
1050         return _writer->next.get();
1051       }
1052       ink_assert(!_writer->next || !_writer->next->read_avail());
1053       return _writer.get();
1054     }
1055 
1056     return nullptr;
1057   }
1058 
1059   char *
1060   buf()
1061   {
1062     IOBufferBlock *b = first_write_block();
1063     return b ? b->buf() : nullptr;
1064   }
1065 
1066   char *
1067   buf_end()
1068   {
1069     return first_write_block()->buf_end();
1070   }
1071 
1072   char *
1073   start()
1074   {
1075     return first_write_block()->start();
1076   }
1077 
1078   char *
1079   end()
1080   {
1081     return first_write_block()->end();
1082   }
1083 
1084   /**
1085     Returns the amount of space of available for writing on the first
1086     writable block on the block chain (the one that would be returned
1087     by first_write_block()).
1088 
1089   */
1090   int64_t block_write_avail();
1091 
1092   /**
1093     Returns the amount of space of available for writing on all writable
1094     blocks currently on the block chain.  Will NOT add blocks to the
1095     block chain.
1096 
1097   */
1098   int64_t current_write_avail();
1099 
1100   /**
1101     Adds blocks for writing if the watermark criteria are met. Returns
1102     the amount of space of available for writing on all writable blocks
1103     on the block chain after a block due to the watermark criteria.
1104 
1105   */
1106   int64_t write_avail();
1107 
1108   /**
1109     Returns the default data block size for this buffer.
1110 
1111   */
1112   int64_t block_size();
1113 
1114   /**
1115     Returns the default data block size for this buffer.
1116 
1117   */
1118   int64_t
1119   total_size()
1120   {
1121     return block_size();
1122   }
1123 
1124   /**
1125     Returns true if amount of the data outstanding on the buffer exceeds
1126     the watermark.
1127 
1128   */
1129   bool
1130   high_water()
1131   {
1132     return max_read_avail() > water_mark;
1133   }
1134 
1135   /**
1136     Returns true if the amount of writable space after adding a block on
1137     the buffer is less than the water mark. Since this function relies
1138     on write_avail() it may add blocks.
1139 
1140   */
1141   bool
1142   low_water()
1143   {
1144     return write_avail() <= water_mark;
1145   }
1146 
1147   /**
1148     Returns true if amount the amount writable space without adding and
1149     blocks on the buffer is less than the water mark.
1150 
1151   */
1152   bool
1153   current_low_water()
1154   {
1155     return current_write_avail() <= water_mark;
1156   }
1157   void set_size_index(int64_t size);
1158 
1159   /**
1160     Allocates a new IOBuffer reader and sets it's its 'accessor' field
1161     to point to 'anAccessor'.
1162 
1163   */
1164   IOBufferReader *alloc_accessor(MIOBufferAccessor *anAccessor);
1165 
1166   /**
1167     Allocates an IOBufferReader for this buffer. IOBufferReaders hold
1168     data on the buffer for different consumers. IOBufferReaders are
1169     REQUIRED when using buffer. alloc_reader() MUST ONLY be a called
1170     on newly allocated buffers. Calling on a buffer with data already
1171     placed on it will result in the reader starting at an indeterminate
1172     place on the buffer.
1173 
1174   */
1175   IOBufferReader *alloc_reader();
1176 
1177   /**
1178     Allocates a new reader on this buffer and places it's starting
1179     point at the same place as reader r. r MUST be a pointer to a reader
1180     previous allocated from this buffer.
1181 
1182   */
1183   IOBufferReader *clone_reader(IOBufferReader *r);
1184 
1185   /**
1186     Deallocates reader e from this buffer. e MUST be a pointer to a reader
1187     previous allocated from this buffer. Reader need to allocated when a
1188     particularly consumer is being removed from the buffer but the buffer
1189     is still in use. Deallocation is not necessary when the buffer is
1190     being freed as all outstanding readers are automatically deallocated.
1191 
1192   */
1193   void dealloc_reader(IOBufferReader *e);
1194 
1195   /**
1196     Deallocates all outstanding readers on the buffer.
1197 
1198   */
1199   void dealloc_all_readers();
1200 
1201   void set(void *b, int64_t len);
1202   void set_xmalloced(void *b, int64_t len);
1203   void alloc(int64_t i = default_large_iobuffer_size);
1204   void alloc_xmalloc(int64_t buf_size);
1205   void append_block_internal(IOBufferBlock *b);
1206   int64_t write(IOBufferBlock const *b, int64_t len, int64_t offset);
1207   int64_t puts(char *buf, int64_t len);
1208 
1209   // internal interface
1210 
1211   bool
1212   empty()
1213   {
1214     return !_writer;
1215   }
1216   int64_t max_read_avail();
1217 
1218   int max_block_count();
1219   void check_add_block();
1220 
1221   IOBufferBlock *get_current_block();
1222 
1223   void
1224   reset()
1225   {
1226     if (_writer) {
1227       _writer->reset();
1228     }
1229     for (auto &reader : readers) {
1230       if (reader.allocated()) {
1231         reader.reset();
1232       }
1233     }
1234   }
1235 
1236   void
1237   init_readers()
1238   {
1239     for (auto &reader : readers) {
1240       if (reader.allocated() && !reader.block) {
1241         reader.block = _writer;
1242       }
1243     }
1244   }
1245 
1246   void
1247   dealloc()
1248   {
1249     _writer = nullptr;
1250     dealloc_all_readers();
1251   }
1252 
1253   void
1254   clear()
1255   {
1256     dealloc();
1257     size_index = BUFFER_SIZE_NOT_ALLOCATED;
1258     water_mark = 0;
1259   }
1260 
1261   void
1262   realloc(int64_t i)
1263   {
1264     _writer->realloc(i);
1265   }
1266   void
1267   realloc(void *b, int64_t buf_size)
1268   {
1269     _writer->realloc(b, buf_size);
1270   }
1271   void
1272   realloc_xmalloc(void *b, int64_t buf_size)
1273   {
1274     _writer->realloc_xmalloc(b, buf_size);
1275   }
1276   void
1277   realloc_xmalloc(int64_t buf_size)
1278   {
1279     _writer->realloc_xmalloc(buf_size);
1280   }
1281 
1282   int64_t size_index;
1283 
1284   /**
1285     Determines when to stop writing or reading. The watermark is the
1286     level to which the producer (filler) is required to fill the buffer
1287     before it can expect the reader to consume any data.  A watermark
1288     of zero means that the reader will consume any amount of data,
1289     no matter how small.
1290 
1291   */
1292   int64_t water_mark;
1293 
1294   Ptr<IOBufferBlock> _writer;
1295   IOBufferReader readers[MAX_MIOBUFFER_READERS];
1296 
1297 #ifdef TRACK_BUFFER_USER
1298   const char *_location = nullptr;
1299 #endif
1300 
1301   MIOBuffer(void *b, int64_t bufsize, int64_t aWater_mark);
1302   // cppcheck-suppress noExplicitConstructor; allow implicit conversion
1303   MIOBuffer(int64_t default_size_index);
1304   MIOBuffer();
1305   ~MIOBuffer();
1306 };
1307 
1308 /**
1309   A wrapper for either a reader or a writer of an MIOBuffer.
1310 
1311 */
1312 struct MIOBufferAccessor {
1313   IOBufferReader *
1314   reader()
1315   {
1316     return entry;
1317   }
1318 
1319   MIOBuffer *
1320   writer()
1321   {
1322     return mbuf;
1323   }
1324 
1325   int64_t
1326   block_size() const
1327   {
1328     return mbuf->block_size();
1329   }
1330 
1331   int64_t
1332   total_size() const
1333   {
1334     return block_size();
1335   }
1336 
1337   void reader_for(IOBufferReader *abuf);
1338   void reader_for(MIOBuffer *abuf);
1339   void writer_for(MIOBuffer *abuf);
1340 
1341   void
1342   clear()
1343   {
1344     mbuf  = nullptr;
1345     entry = nullptr;
1346   }
1347 
1348   MIOBufferAccessor() {}
1349 
1350   ~MIOBufferAccessor();
1351 
1352 #ifdef DEBUG
1353   const char *name = nullptr;
1354 #endif
1355 
1356   // noncopyable
1357   MIOBufferAccessor(const MIOBufferAccessor &) = delete;
1358   MIOBufferAccessor &operator=(const MIOBufferAccessor &) = delete;
1359 
1360 private:
1361   MIOBuffer *mbuf       = nullptr;
1362   IOBufferReader *entry = nullptr;
1363 };
1364 
1365 extern MIOBuffer *new_MIOBuffer_internal(
1366 #ifdef TRACK_BUFFER_USER
1367   const char *loc,
1368 #endif
1369   int64_t size_index = default_large_iobuffer_size);
1370 
1371 #ifdef TRACK_BUFFER_USER
1372 class MIOBuffer_tracker
1373 {
1374   const char *loc;
1375 
1376 public:
1377   explicit MIOBuffer_tracker(const char *_loc) : loc(_loc) {}
1378   MIOBuffer *
1379   operator()(int64_t size_index = default_large_iobuffer_size)
1380   {
1381     return new_MIOBuffer_internal(loc, size_index);
1382   }
1383 };
1384 #endif
1385 
1386 extern MIOBuffer *new_empty_MIOBuffer_internal(
1387 #ifdef TRACK_BUFFER_USER
1388   const char *loc,
1389 #endif
1390   int64_t size_index = default_large_iobuffer_size);
1391 
1392 #ifdef TRACK_BUFFER_USER
1393 class Empty_MIOBuffer_tracker
1394 {
1395   const char *loc;
1396 
1397 public:
1398   explicit Empty_MIOBuffer_tracker(const char *_loc) : loc(_loc) {}
1399   MIOBuffer *
1400   operator()(int64_t size_index = default_large_iobuffer_size)
1401   {
1402     return new_empty_MIOBuffer_internal(loc, size_index);
1403   }
1404 };
1405 #endif
1406 
1407 /// MIOBuffer allocator/deallocator
1408 #ifdef TRACK_BUFFER_USER
1409 #define new_MIOBuffer MIOBuffer_tracker(RES_PATH("memory/IOBuffer/"))
1410 #define new_empty_MIOBuffer Empty_MIOBuffer_tracker(RES_PATH("memory/IOBuffer/"))
1411 #else
1412 #define new_MIOBuffer new_MIOBuffer_internal
1413 #define new_empty_MIOBuffer new_empty_MIOBuffer_internal
1414 #endif
1415 extern void free_MIOBuffer(MIOBuffer *mio);
1416 //////////////////////////////////////////////////////////////////////
1417 
1418 extern IOBufferBlock *new_IOBufferBlock_internal(
1419 #ifdef TRACK_BUFFER_USER
1420   const char *loc
1421 #endif
1422 );
1423 
1424 extern IOBufferBlock *new_IOBufferBlock_internal(
1425 #ifdef TRACK_BUFFER_USER
1426   const char *loc,
1427 #endif
1428   IOBufferData *d, int64_t len = 0, int64_t offset = 0);
1429 
1430 #ifdef TRACK_BUFFER_USER
1431 class IOBufferBlock_tracker
1432 {
1433   const char *loc;
1434 
1435 public:
1436   explicit IOBufferBlock_tracker(const char *_loc) : loc(_loc) {}
1437   IOBufferBlock *
1438   operator()()
1439   {
1440     return new_IOBufferBlock_internal(loc);
1441   }
1442   IOBufferBlock *
1443   operator()(Ptr<IOBufferData> &d, int64_t len = 0, int64_t offset = 0)
1444   {
1445     return new_IOBufferBlock_internal(loc, d.get(), len, offset);
1446   }
1447 };
1448 #endif
1449 
1450 /// IOBufferBlock allocator
1451 #ifdef TRACK_BUFFER_USER
1452 #define new_IOBufferBlock IOBufferBlock_tracker(RES_PATH("memory/IOBuffer/"))
1453 #else
1454 #define new_IOBufferBlock new_IOBufferBlock_internal
1455 #endif
1456 ////////////////////////////////////////////////////////////
1457 
1458 extern IOBufferData *new_IOBufferData_internal(
1459 #ifdef TRACK_BUFFER_USER
1460   const char *location,
1461 #endif
1462   int64_t size_index = default_large_iobuffer_size, AllocType type = DEFAULT_ALLOC);
1463 
1464 extern IOBufferData *new_xmalloc_IOBufferData_internal(
1465 #ifdef TRACK_BUFFER_USER
1466   const char *location,
1467 #endif
1468   void *b, int64_t size);
1469 
1470 extern IOBufferData *new_constant_IOBufferData_internal(
1471 #ifdef TRACK_BUFFER_USER
1472   const char *locaction,
1473 #endif
1474   void *b, int64_t size);
1475 
1476 #ifdef TRACK_BUFFER_USER
1477 class IOBufferData_tracker
1478 {
1479   const char *loc;
1480 
1481 public:
1482   explicit IOBufferData_tracker(const char *_loc) : loc(_loc) {}
1483   IOBufferData *
1484   operator()(int64_t size_index = default_large_iobuffer_size, AllocType type = DEFAULT_ALLOC)
1485   {
1486     return new_IOBufferData_internal(loc, size_index, type);
1487   }
1488 };
1489 #endif
1490 
1491 #ifdef TRACK_BUFFER_USER
1492 #define new_IOBufferData IOBufferData_tracker(RES_PATH("memory/IOBuffer/"))
1493 #define new_xmalloc_IOBufferData(b, size) new_xmalloc_IOBufferData_internal(RES_PATH("memory/IOBuffer/"), (b), (size))
1494 #define new_constant_IOBufferData(b, size) new_constant_IOBufferData_internal(RES_PATH("memory/IOBuffer/"), (b), (size))
1495 #else
1496 #define new_IOBufferData new_IOBufferData_internal
1497 #define new_xmalloc_IOBufferData new_xmalloc_IOBufferData_internal
1498 #define new_constant_IOBufferData new_constant_IOBufferData_internal
1499 #endif
1500 
1501 extern int64_t iobuffer_size_to_index(int64_t size, int64_t max = max_iobuffer_size);
1502 extern int64_t index_to_buffer_size(int64_t idx);
1503 /**
1504   Clone a IOBufferBlock chain. Used to snarf a IOBufferBlock chain
1505   w/o copy.
1506 
1507   @param b head of source IOBufferBlock chain.
1508   @param offset # bytes in the beginning to skip.
1509   @param len bytes to copy from source.
1510   @return ptr to head of new IOBufferBlock chain.
1511 
1512 */
1513 extern IOBufferBlock *iobufferblock_clone(IOBufferBlock *b, int64_t offset, int64_t len);
1514 /**
1515   Skip over specified bytes in chain. Used for dropping references.
1516 
1517   @param b head of source IOBufferBlock chain.
1518   @param poffset originally offset in b, finally offset in returned
1519     IOBufferBlock.
1520   @param plen value of write is subtracted from plen in the function.
1521   @param write bytes to skip.
1522   @return ptr to head of new IOBufferBlock chain.
1523 
1524 */
1525 extern IOBufferBlock *iobufferblock_skip(IOBufferBlock *b, int64_t *poffset, int64_t *plen, int64_t write);
1526 
1527 inline IOBufferChain &
1528 IOBufferChain::operator=(self_type const &that)
1529 {
1530   _head = that._head;
1531   _tail = that._tail;
1532   _len  = that._len;
1533   return *this;
1534 }
1535 
1536 inline IOBufferChain &
1537 IOBufferChain::operator+=(self_type const &that)
1538 {
1539   if (nullptr == _head)
1540     *this = that;
1541   else {
1542     _tail->next = that._head;
1543     _tail       = that._tail;
1544     _len += that._len;
1545   }
1546   return *this;
1547 }
1548 
1549 inline int64_t
1550 IOBufferChain::length() const
1551 {
1552   return _len;
1553 }
1554 
1555 inline IOBufferBlock const *
1556 IOBufferChain::head() const
1557 {
1558   return _head.get();
1559 }
1560 
1561 inline IOBufferBlock *
1562 IOBufferChain::head()
1563 {
1564   return _head.get();
1565 }
1566 
1567 inline void
1568 IOBufferChain::clear()
1569 {
1570   _head = nullptr;
1571   _tail = nullptr;
1572   _len  = 0;
1573 }
1574 
1575 inline IOBufferChain::const_iterator::const_iterator(self_type const &that) : _b(that._b) {}
1576 
1577 inline IOBufferChain::const_iterator &
1578 IOBufferChain::const_iterator::operator=(self_type const &that)
1579 {
1580   _b = that._b;
1581   return *this;
1582 }
1583 
1584 inline bool
1585 IOBufferChain::const_iterator::operator==(self_type const &that) const
1586 {
1587   return _b == that._b;
1588 }
1589 
1590 inline bool
1591 IOBufferChain::const_iterator::operator!=(self_type const &that) const
1592 {
1593   return _b != that._b;
1594 }
1595 
1596 inline IOBufferChain::const_iterator::value_type &IOBufferChain::const_iterator::operator*() const
1597 {
1598   return *_b;
1599 }
1600 
1601 inline IOBufferChain::const_iterator::value_type *IOBufferChain::const_iterator::operator->() const
1602 {
1603   return _b;
1604 }
1605 
1606 inline IOBufferChain::const_iterator &
1607 IOBufferChain::const_iterator::operator++()
1608 {
1609   _b = _b->next.get();
1610   return *this;
1611 }
1612 
1613 inline IOBufferChain::const_iterator
1614 IOBufferChain::const_iterator::operator++(int)
1615 {
1616   self_type pre{*this};
1617   ++*this;
1618   return pre;
1619 }
1620 
1621 inline IOBufferChain::iterator::value_type &IOBufferChain::iterator::operator*() const
1622 {
1623   return *_b;
1624 }
1625 
1626 inline IOBufferChain::iterator::value_type *IOBufferChain::iterator::operator->() const
1627 {
1628   return _b;
1629 }
1630