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