1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	/*
4    	 * Ceph - scalable distributed file system
5    	 *
6    	 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7    	 *
8    	 * This is free software; you can redistribute it and/or
9    	 * modify it under the terms of the GNU Lesser General Public
10   	 * License version 2.1, as published by the Free Software
11   	 * Foundation.  See file COPYING.
12   	 *
13   	 */
14   	#ifndef CEPH_BUFFER_H
15   	#define CEPH_BUFFER_H
16   	
17   	#if defined(__linux__) || defined(__FreeBSD__)
18   	#include <stdlib.h>
19   	#endif
20   	#include <limits.h>
21   	
22   	#ifndef _XOPEN_SOURCE
23   	# define _XOPEN_SOURCE 600
24   	#endif
25   	
26   	#include <stdio.h>
27   	#include <sys/uio.h>
28   	
29   	#if defined(__linux__)	// For malloc(2).
30   	#include <malloc.h>
31   	#endif
32   	
33   	#include <inttypes.h>
34   	#include <stdint.h>
35   	#include <string.h>
36   	
37   	#ifndef __CYGWIN__
38   	# include <sys/mman.h>
39   	#endif
40   	
41   	#include <iosfwd>
42   	#include <iomanip>
43   	#include <list>
44   	#include <vector>
45   	#include <string>
46   	#if __cplusplus >= 201703L
47   	#include <string_view>
48   	#endif // __cplusplus >= 201703L
49   	
50   	#include <exception>
51   	#include <type_traits>
52   	
53   	#include "page.h"
54   	#include "crc32c.h"
55   	#include "buffer_fwd.h"
56   	
57   	#ifdef __CEPH__
58   	# include "include/ceph_assert.h"
59   	#else
60   	# include <assert.h>
61   	#endif
62   	
63   	#include "inline_memory.h"
64   	
65   	#define CEPH_BUFFER_API
66   	
67   	#ifdef HAVE_SEASTAR
68   	namespace seastar {
69   	template <typename T> class temporary_buffer;
70   	namespace net {
71   	class packet;
72   	}
73   	}
74   	#endif // HAVE_SEASTAR
75   	class deleter;
76   	
77   	template<typename T> class DencDumper;
78   	
79   	namespace ceph {
80   	
81   	template <class T>
82   	struct nop_delete {
83   	  void operator()(T*) {}
84   	};
85   	
86   	// This is not unique_ptr-like smart pointer! It just signalizes ownership
87   	// but DOES NOT manage the resource. It WILL LEAK if not manually deleted.
88   	// It's rather a replacement for raw pointer than any other smart one.
89   	//
90   	// Considered options:
91   	//  * unique_ptr with custom deleter implemented in .cc (would provide
92   	//    the non-zero-cost resource management),
93   	//  * GSL's owner<T*> (pretty neat but would impose an extra depedency),
94   	//  * unique_ptr with nop deleter,
95   	//  * raw pointer (doesn't embed ownership enforcement - std::move).
96   	template <class T>
97   	struct unique_leakable_ptr : public std::unique_ptr<T, ceph::nop_delete<T>> {
98   	  using std::unique_ptr<T, ceph::nop_delete<T>>::unique_ptr;
99   	};
100  	
101  	namespace buffer CEPH_BUFFER_API {
102  	inline namespace v14_2_0 {
103  	
104  	  /*
105  	   * exceptions
106  	   */
107  	
108  	  struct error : public std::exception{
109  	    const char *what() const throw () override;
110  	  };
111  	  struct bad_alloc : public error {
112  	    const char *what() const throw () override;
113  	  };
114  	  struct end_of_buffer : public error {
115  	    const char *what() const throw () override;
116  	  };
117  	  struct malformed_input : public error {
118  	    explicit malformed_input(const std::string& w) {
119  	      snprintf(buf, sizeof(buf), "buffer::malformed_input: %s", w.c_str());
120  	    }
121  	    const char *what() const throw () override;
122  	  private:
123  	    char buf[256];
124  	  };
125  	  struct error_code : public malformed_input {
126  	    explicit error_code(int error);
127  	    int code;
128  	  };
129  	
130  	
131  	  /// count of cached crc hits (matching input)
132  	  int get_cached_crc();
133  	  /// count of cached crc hits (mismatching input, required adjustment)
134  	  int get_cached_crc_adjusted();
135  	  /// count of crc cache misses
136  	  int get_missed_crc();
137  	  /// enable/disable tracking of cached crcs
138  	  void track_cached_crc(bool b);
139  	
140  	  /*
141  	   * an abstract raw buffer.  with a reference count.
142  	   */
143  	  class raw;
144  	  class raw_malloc;
145  	  class raw_static;
146  	  class raw_posix_aligned;
147  	  class raw_hack_aligned;
148  	  class raw_char;
149  	  class raw_claimed_char;
150  	  class raw_unshareable; // diagnostic, unshareable char buffer
151  	  class raw_combined;
152  	  class raw_claim_buffer;
153  	
154  	
155  	  /*
156  	   * named constructors
157  	   */
158  	  ceph::unique_leakable_ptr<raw> copy(const char *c, unsigned len);
159  	  ceph::unique_leakable_ptr<raw> create(unsigned len);
160  	  ceph::unique_leakable_ptr<raw> create_in_mempool(unsigned len, int mempool);
161  	  raw* claim_char(unsigned len, char *buf);
162  	  raw* create_malloc(unsigned len);
163  	  raw* claim_malloc(unsigned len, char *buf);
164  	  raw* create_static(unsigned len, char *buf);
165  	  ceph::unique_leakable_ptr<raw> create_aligned(unsigned len, unsigned align);
166  	  ceph::unique_leakable_ptr<raw> create_aligned_in_mempool(unsigned len, unsigned align, int mempool);
167  	  ceph::unique_leakable_ptr<raw> create_page_aligned(unsigned len);
168  	  ceph::unique_leakable_ptr<raw> create_small_page_aligned(unsigned len);
169  	  raw* create_unshareable(unsigned len);
170  	  raw* create_static(unsigned len, char *buf);
171  	  raw* claim_buffer(unsigned len, char *buf, deleter del);
172  	
173  	#ifdef HAVE_SEASTAR
174  	  /// create a raw buffer to wrap seastar cpu-local memory, using foreign_ptr to
175  	  /// make it safe to share between cpus
176  	  raw* create_foreign(seastar::temporary_buffer<char>&& buf);
177  	  /// create a raw buffer to wrap seastar cpu-local memory, without the safety
178  	  /// of foreign_ptr. the caller must otherwise guarantee that the buffer ptr is
179  	  /// destructed on this cpu
180  	  raw* create(seastar::temporary_buffer<char>&& buf);
181  	#endif
182  	
183  	  /*
184  	   * a buffer pointer.  references (a subsequence of) a raw buffer.
185  	   */
186  	  class CEPH_BUFFER_API ptr {
187  	    raw *_raw;
188  	  public: // dirty hack for testing; if it works, this will be abstracted
189  	    unsigned _off, _len;
190  	  private:
191  	
192  	    void release();
193  	
194  	    template<bool is_const>
195  	    class iterator_impl {
196  	      const ptr *bp;     ///< parent ptr
197  	      const char *start; ///< starting pointer into bp->c_str()
198  	      const char *pos;   ///< pointer into bp->c_str()
199  	      const char *end_ptr;   ///< pointer to bp->end_c_str()
200  	      const bool deep;   ///< if true, do not allow shallow ptr copies
201  	
202  	      iterator_impl(typename std::conditional<is_const, const ptr*, ptr*>::type p,
203  			    size_t offset, bool d)
204  		: bp(p),
205  		  start(p->c_str() + offset),
206  		  pos(start),
207  		  end_ptr(p->end_c_str()),
208  		  deep(d)
209  	      {}
210  	
211  	      friend class ptr;
212  	
213  	    public:
214  	      using pointer = typename std::conditional<is_const, const char*, char *>::type;
215  	      pointer get_pos_add(size_t n) {
216  		auto r = pos;
217  		advance(n);
218  		return r;
219  	      }
220  	      ptr get_ptr(size_t len) {
221  		if (deep) {
222  		  return buffer::copy(get_pos_add(len), len);
223  		} else {
224  		  size_t off = pos - bp->c_str();
225  		  advance(len);
226  		  return ptr(*bp, off, len);
227  		}
228  	      }
229  	
230  	      void advance(size_t len) {
231  		pos += len;
232  		if (pos > end_ptr)
233  		  throw end_of_buffer();
234  	      }
235  	
236  	      const char *get_pos() {
237  		return pos;
238  	      }
239  	      const char *get_end() {
240  		return end_ptr;
241  	      }
242  	
243  	      size_t get_offset() {
244  		return pos - start;
245  	      }
246  	
247  	      bool end() const {
248  		return pos == end_ptr;
249  	      }
250  	    };
251  	
252  	  public:
253  	    using const_iterator = iterator_impl<true>;
254  	    using iterator = iterator_impl<false>;
255  	
256  	    ptr() : _raw(nullptr), _off(0), _len(0) {}
257  	    // cppcheck-suppress noExplicitConstructor
258  	    ptr(raw* r);
259  	    ptr(ceph::unique_leakable_ptr<raw> r);
260  	    // cppcheck-suppress noExplicitConstructor
261  	    ptr(unsigned l);
262  	    ptr(const char *d, unsigned l);
263  	    ptr(const ptr& p);
264  	    ptr(ptr&& p) noexcept;
265  	    ptr(const ptr& p, unsigned o, unsigned l);
266  	    ptr(const ptr& p, ceph::unique_leakable_ptr<raw> r);
267  	    ptr& operator= (const ptr& p);
268  	    ptr& operator= (ptr&& p) noexcept;
269  	    ~ptr() {
270  	      // BE CAREFUL: this destructor is called also for hypercombined ptr_node.
271  	      // After freeing underlying raw, `*this` can become inaccessible as well!
272  	      release();
273  	    }
274  	
275  	    bool have_raw() const { return _raw ? true:false; }
276  	
277  	    ceph::unique_leakable_ptr<raw> clone();
278  	    void swap(ptr& other) noexcept;
279  	
280  	    iterator begin(size_t offset=0) {
281  	      return iterator(this, offset, false);
282  	    }
283  	    const_iterator begin(size_t offset=0) const {
284  	      return const_iterator(this, offset, false);
285  	    }
286  	    const_iterator cbegin() const {
287  	      return begin();
288  	    }
289  	    const_iterator begin_deep(size_t offset=0) const {
290  	      return const_iterator(this, offset, true);
291  	    }
292  	
293  	    // misc
294  	    bool is_aligned(unsigned align) const {
295  	      return ((long)c_str() & (align-1)) == 0;
296  	    }
297  	    bool is_page_aligned() const { return is_aligned(CEPH_PAGE_SIZE); }
298  	    bool is_n_align_sized(unsigned align) const
299  	    {
300  	      return (length() % align) == 0;
301  	    }
302  	    bool is_n_page_sized() const { return is_n_align_sized(CEPH_PAGE_SIZE); }
303  	    bool is_partial() const {
304  	      return have_raw() && (start() > 0 || end() < raw_length());
305  	    }
306  	
307  	    int get_mempool() const;
308  	    void reassign_to_mempool(int pool);
309  	    void try_assign_to_mempool(int pool);
310  	
311  	    // accessors
312  	    raw *get_raw() const { return _raw; }
313  	    const char *c_str() const;
314  	    char *c_str();
315  	    const char *end_c_str() const;
316  	    char *end_c_str();
317  	    unsigned length() const { return _len; }
318  	    unsigned offset() const { return _off; }
319  	    unsigned start() const { return _off; }
320  	    unsigned end() const { return _off + _len; }
321  	    unsigned unused_tail_length() const;
322  	    const char& operator[](unsigned n) const;
323  	    char& operator[](unsigned n);
324  	
325  	    const char *raw_c_str() const;
326  	    unsigned raw_length() const;
327  	    int raw_nref() const;
328  	
329  	    void copy_out(unsigned o, unsigned l, char *dest) const;
330  	
331  	    unsigned wasted() const;
332  	
333  	    int cmp(const ptr& o) const;
334  	    bool is_zero() const;
335  	
336  	    // modifiers
337  	    void set_offset(unsigned o) {
338  	#ifdef __CEPH__
339  	      ceph_assert(raw_length() >= o);
340  	#else
341  	      assert(raw_length() >= o);
342  	#endif
343  	      _off = o;
344  	    }
345  	    void set_length(unsigned l) {
346  	#ifdef __CEPH__
347  	      ceph_assert(raw_length() >= l);
348  	#else
349  	      assert(raw_length() >= l);
350  	#endif
351  	      _len = l;
352  	    }
353  	
354  	    unsigned append(char c);
355  	    unsigned append(const char *p, unsigned l);
356  	#if __cplusplus >= 201703L
357  	    inline unsigned append(std::string_view s) {
358  	      return append(s.data(), s.length());
359  	    }
360  	#endif // __cplusplus >= 201703L
361  	    void copy_in(unsigned o, unsigned l, const char *src, bool crc_reset = true);
362  	    void zero(bool crc_reset = true);
363  	    void zero(unsigned o, unsigned l, bool crc_reset = true);
364  	    unsigned append_zeros(unsigned l);
365  	
366  	#ifdef HAVE_SEASTAR
367  	    /// create a temporary_buffer, copying the ptr as its deleter
368  	    operator seastar::temporary_buffer<char>() &;
369  	    /// convert to temporary_buffer, stealing the ptr as its deleter
370  	    operator seastar::temporary_buffer<char>() &&;
371  	#endif // HAVE_SEASTAR
372  	
373  	  };
374  	
375  	
376  	  struct ptr_hook {
377  	    mutable ptr_hook* next;
378  	
379  	    ptr_hook() = default;
380  	    ptr_hook(ptr_hook* const next)
381  	      : next(next) {
382  	    }
383  	  };
384  	
385  	  class ptr_node : public ptr_hook, public ptr {
386  	  public:
387  	    struct cloner {
388  	      ptr_node* operator()(const ptr_node& clone_this);
389  	    };
390  	    struct disposer {
391  	      void operator()(ptr_node* const delete_this) {
392  		if (!dispose_if_hypercombined(delete_this)) {
393  		  delete delete_this;
394  		}
395  	      }
396  	    };
397  	
398  	    ~ptr_node() = default;
399  	
400  	    static std::unique_ptr<ptr_node, disposer>
401  	    create(ceph::unique_leakable_ptr<raw> r) {
402  	      return create_hypercombined(std::move(r));
403  	    }
404  	    static std::unique_ptr<ptr_node, disposer> create(raw* const r) {
405  	      return create_hypercombined(r);
406  	    }
407  	    static std::unique_ptr<ptr_node, disposer> create(const unsigned l) {
408  	      return create_hypercombined(buffer::create(l));
409  	    }
410  	    template <class... Args>
411  	    static std::unique_ptr<ptr_node, disposer> create(Args&&... args) {
412  	      return std::unique_ptr<ptr_node, disposer>(
413  		new ptr_node(std::forward<Args>(args)...));
414  	    }
415  	
416  	    static ptr_node* copy_hypercombined(const ptr_node& copy_this);
417  	
418  	  private:
419  	    template <class... Args>
420  	    ptr_node(Args&&... args) : ptr(std::forward<Args>(args)...) {
421  	    }
422  	    ptr_node(const ptr_node&) = default;
423  	
424  	    ptr& operator= (const ptr& p) = delete;
425  	    ptr& operator= (ptr&& p) noexcept = delete;
426  	    ptr_node& operator= (const ptr_node& p) = delete;
427  	    ptr_node& operator= (ptr_node&& p) noexcept = delete;
428  	    void swap(ptr& other) noexcept = delete;
429  	    void swap(ptr_node& other) noexcept = delete;
430  	
431  	    static bool dispose_if_hypercombined(ptr_node* delete_this);
432  	    static std::unique_ptr<ptr_node, disposer> create_hypercombined(
433  	      buffer::raw* r);
434  	    static std::unique_ptr<ptr_node, disposer> create_hypercombined(
435  	      ceph::unique_leakable_ptr<raw> r);
436  	  };
437  	  /*
438  	   * list - the useful bit!
439  	   */
440  	
441  	  class CEPH_BUFFER_API list {
442  	  public:
443  	    // this the very low-level implementation of singly linked list
444  	    // ceph::buffer::list is built on. We don't use intrusive slist
445  	    // of Boost (or any other 3rd party) to save extra dependencies
446  	    // in our public headers.
447  	    class buffers_t {
448  	      // _root.next can be thought as _head
449  	      ptr_hook _root;
450  	      ptr_hook* _tail;
451  	      std::size_t _size;
452  	
453  	    public:
454  	      template <class T>
455  	      class buffers_iterator {
456  		typename std::conditional<
457  		  std::is_const<T>::value, const ptr_hook*, ptr_hook*>::type cur;
458  		template <class U> friend class buffers_iterator;
459  	      public:
460  		using value_type = T;
461  		using reference = typename std::add_lvalue_reference<T>::type;
462  		using pointer = typename std::add_pointer<T>::type;
463  		using difference_type = std::ptrdiff_t;
464  		using iterator_category = std::forward_iterator_tag;
465  	
466  		template <class U>
467  		buffers_iterator(U* const p)
468  		  : cur(p) {
469  		}
470  		template <class U>
471  		buffers_iterator(const buffers_iterator<U>& other)
472  		  : cur(other.cur) {
473  		}
474  		buffers_iterator() = default;
475  	
476  		T& operator*() const {
477  		  return *reinterpret_cast<T*>(cur);
478  		}
479  		T* operator->() const {
480  		  return reinterpret_cast<T*>(cur);
481  		}
482  	
483  		buffers_iterator& operator++() {
484  		  cur = cur->next;
485  		  return *this;
486  		}
487  		buffers_iterator operator++(int) {
488  		  const auto temp(*this);
489  		  ++*this;
490  		  return temp;
491  		}
492  	
493  		template <class U>
494  		buffers_iterator& operator=(buffers_iterator<U>& other) {
495  		  cur = other.cur;
496  		  return *this;
497  		}
498  	
499  		bool operator==(const buffers_iterator& rhs) const {
500  		  return cur == rhs.cur;
501  		}
502  		bool operator!=(const buffers_iterator& rhs) const {
503  		  return !(*this==rhs);
504  		}
505  	
506  		using citer_t = buffers_iterator<typename std::add_const<T>::type>;
507  		operator citer_t() const {
508  		  return citer_t(cur);
509  		}
510  	      };
511  	
512  	      typedef buffers_iterator<const ptr_node> const_iterator;
513  	      typedef buffers_iterator<ptr_node> iterator;
514  	
515  	      typedef const ptr_node& const_reference;
516  	      typedef ptr_node& reference;
517  	
518  	      buffers_t()
519  	        : _root(&_root),
520  		  _tail(&_root),
521  		  _size(0) {
522  	      }
523  	      buffers_t(const buffers_t&) = delete;
524  	      buffers_t(buffers_t&& other)
525  		: _root(other._root.next == &other._root ? &_root : other._root.next),
526  		  _tail(other._tail == &other._root ? &_root : other._tail),
527  		  _size(other._size) {
528  		other._root.next = &other._root;
529  		other._tail = &other._root;
530  		other._size = 0;
531  	
532  		_tail->next = &_root;
533  	      }
534  	      buffers_t& operator=(buffers_t&& other) {
535  		if (&other != this) {
536  		  clear_and_dispose();
537  		  swap(other);
538  		}
539  		return *this;
540  	      }
541  	
542  	      void push_back(reference item) {
543  		item.next = &_root;
544  		// this updates _root.next when called on empty
545  		_tail->next = &item;
546  		_tail = &item;
547  		_size++;
548  	      }
549  	
550  	      void push_front(reference item) {
551  		item.next = _root.next;
552  		_root.next = &item;
553  		_tail = _tail == &_root ? &item : _tail;
554  		_size++;
555  	      }
556  	
557  	      // *_after
558  	      iterator erase_after(const_iterator it) {
559  		const auto* to_erase = it->next;
560  	
561  		it->next = to_erase->next;
562  		_root.next = _root.next == to_erase ? to_erase->next : _root.next;
563  		_tail = _tail == to_erase ? (ptr_hook*)&*it : _tail;
564  		_size--;
565  		return it->next;
566  	      }
567  	
568  	      void insert_after(const_iterator it, reference item) {
569  		item.next = it->next;
570  		it->next = &item;
571  		_root.next = it == end() ? &item : _root.next;
572  		_tail = const_iterator(_tail) == it ? &item : _tail;
573  		_size++;
574  	      }
575  	
576  	      void splice_back(buffers_t& other) {
577  		if (other._size == 0) {
578  		  return;
579  		}
580  	
581  		other._tail->next = &_root;
582  		// will update root.next if empty() == true
583  		_tail->next = other._root.next;
584  		_tail = other._tail;
585  		_size += other._size;
586  	
587  		other._root.next = &other._root;
588  		other._tail = &other._root;
589  		other._size = 0;
590  	      }
591  	
592  	      std::size_t size() const { return _size; }
593  	      bool empty() const { return _tail == &_root; }
594  	
595  	      const_iterator begin() const {
596  		return _root.next;
597  	      }
598  	      const_iterator before_begin() const {
599  		return &_root;
600  	      }
601  	      const_iterator end() const {
602  		return &_root;
603  	      }
604  	      iterator begin() {
605  		return _root.next;
606  	      }
607  	      iterator before_begin() {
608  		return &_root;
609  	      }
610  	      iterator end() {
611  		return &_root;
612  	      }
613  	
614  	      reference front() {
615  		return reinterpret_cast<reference>(*_root.next);
616  	      }
617  	      reference back() {
618  		return reinterpret_cast<reference>(*_tail);
619  	      }
620  	      const_reference front() const {
621  		return reinterpret_cast<const_reference>(*_root.next);
622  	      }
623  	      const_reference back() const {
624  		return reinterpret_cast<const_reference>(*_tail);
625  	      }
626  	
627  	      void clone_from(const buffers_t& other) {
628  		clear_and_dispose();
629  		for (auto& node : other) {
630  		  ptr_node* clone = ptr_node::cloner()(node);
631  		  push_back(*clone);
632  		}
633  	      }
634  	      void clear_and_dispose() {
635  		for (auto it = begin(); it != end(); /* nop */) {
636  		  auto& node = *it;
637  		  it = it->next;
638  		  ptr_node::disposer()(&node);
639  		}
640  		_root.next = &_root;
641  		_tail = &_root;
642  		_size = 0;
643  	      }
644  	      iterator erase_after_and_dispose(iterator it) {
645  		auto* to_dispose = &*std::next(it);
646  		auto ret = erase_after(it);
647  		ptr_node::disposer()(to_dispose);
648  		return ret;
649  	      }
650  	
651  	      void swap(buffers_t& other) {
652  		const auto copy_root = _root;
653  		_root.next = \
654  		  other._root.next == &other._root ? &this->_root : other._root.next;
655  		other._root.next = \
656  		  copy_root.next == &_root ? &other._root : copy_root.next;
657  	
658  		const auto copy_tail = _tail;
659  		_tail = other._tail == &other._root ? &this->_root : other._tail;
660  		other._tail = copy_tail == &_root ? &other._root : copy_tail;
661  	
662  		_tail->next = &_root;
663  		other._tail->next = &other._root;
664  		std::swap(_size, other._size);
665  	      }
666  	    };
667  	
668  	    class iterator;
669  	
670  	  private:
671  	    // my private bits
672  	    buffers_t _buffers;
673  	
674  	    // track bufferptr we can modify (especially ::append() to). Not all bptrs
675  	    // bufferlist holds have this trait -- if somebody ::push_back(const ptr&),
676  	    // he expects it won't change.
677  	    ptr* _carriage;
678  	    unsigned _len;
679  	    unsigned _memcopy_count; //the total of memcopy using rebuild().
680  	
681  	    template <bool is_const>
682  	    class CEPH_BUFFER_API iterator_impl {
683  	    protected:
684  	      typedef typename std::conditional<is_const,
685  						const list,
686  						list>::type bl_t;
687  	      typedef typename std::conditional<is_const,
688  						const buffers_t,
689  						buffers_t >::type list_t;
690  	      typedef typename std::conditional<is_const,
691  						typename buffers_t::const_iterator,
692  						typename buffers_t::iterator>::type list_iter_t;
693  	      bl_t* bl;
694  	      list_t* ls;  // meh.. just here to avoid an extra pointer dereference..
695  	      list_iter_t p;
696  	      unsigned off; // in bl
697  	      unsigned p_off;   // in *p
698  	      friend class iterator_impl<true>;
699  	
700  	    public:
701  	      using iterator_category = std::forward_iterator_tag;
702  	      using value_type = typename std::conditional<is_const, const char, char>::type;
703  	      using difference_type = std::ptrdiff_t;
704  	      using pointer = typename std::add_pointer<value_type>::type;
705  	      using reference = typename std::add_lvalue_reference<value_type>::type;
706  	
707  	      // constructor.  position.
708  	      iterator_impl()
709  		: bl(0), ls(0), off(0), p_off(0) {}
710  	      iterator_impl(bl_t *l, unsigned o=0);
711  	      iterator_impl(bl_t *l, unsigned o, list_iter_t ip, unsigned po)
712  		: bl(l), ls(&bl->_buffers), p(ip), off(o), p_off(po) {}
713  	      iterator_impl(const list::iterator& i);
714  	
715  	      /// get current iterator offset in buffer::list
716  	      unsigned get_off() const { return off; }
717  	
718  	      /// get number of bytes remaining from iterator position to the end of the buffer::list
719  	      unsigned get_remaining() const { return bl->length() - off; }
720  	
721  	      /// true if iterator is at the end of the buffer::list
722  	      bool end() const {
723  		return p == ls->end();
724  		//return off == bl->length();
725  	      }
726  	
727  	      void advance(unsigned o);
728  	      void seek(unsigned o);
729  	      char operator*() const;
730  	      iterator_impl& operator++();
731  	      ptr get_current_ptr() const;
732  	      bool is_pointing_same_raw(const ptr& other) const;
733  	
734  	      bl_t& get_bl() const { return *bl; }
735  	
736  	      // copy data out.
737  	      // note that these all _append_ to dest!
738  	      void copy(unsigned len, char *dest);
739  	      // deprecated, use copy_deep()
740  	      void copy(unsigned len, ptr &dest) __attribute__((deprecated));
741  	      void copy_deep(unsigned len, ptr &dest);
742  	      void copy_shallow(unsigned len, ptr &dest);
743  	      void copy(unsigned len, list &dest);
744  	      void copy(unsigned len, std::string &dest);
745  	      void copy_all(list &dest);
746  	
747  	      // get a pointer to the currenet iterator position, return the
748  	      // number of bytes we can read from that position (up to want),
749  	      // and advance the iterator by that amount.
750  	      size_t get_ptr_and_advance(size_t want, const char **p);
751  	
752  	      /// calculate crc from iterator position
753  	      uint32_t crc32c(size_t length, uint32_t crc);
754  	
755  	      friend bool operator==(const iterator_impl& lhs,
756  				     const iterator_impl& rhs) {
757  		return &lhs.get_bl() == &rhs.get_bl() && lhs.get_off() == rhs.get_off();
758  	      }
759  	      friend bool operator!=(const iterator_impl& lhs,
760  				     const iterator_impl& rhs) {
761  		return &lhs.get_bl() != &rhs.get_bl() || lhs.get_off() != rhs.get_off();
762  	      }
763  	    };
764  	
765  	  public:
766  	    typedef iterator_impl<true> const_iterator;
767  	
768  	    class CEPH_BUFFER_API iterator : public iterator_impl<false> {
769  	    public:
770  	      iterator() = default;
771  	      iterator(bl_t *l, unsigned o=0);
772  	      iterator(bl_t *l, unsigned o, list_iter_t ip, unsigned po);
773  	      // copy data in
774  	      void copy_in(unsigned len, const char *src, bool crc_reset = true);
775  	      void copy_in(unsigned len, const list& otherl);
776  	    };
777  	
778  	    struct reserve_t {
779  	      char* bp_data;
780  	      unsigned* bp_len;
781  	      unsigned* bl_len;
782  	    };
783  	
784  	    class contiguous_appender {
785  	      ceph::bufferlist& bl;
786  	      ceph::bufferlist::reserve_t space;
787  	      char* pos;
788  	      bool deep;
789  	
790  	      /// running count of bytes appended that are not reflected by @pos
791  	      size_t out_of_band_offset = 0;
792  	
793  	      contiguous_appender(bufferlist& bl, size_t len, bool d)
794  		: bl(bl),
795  		  space(bl.obtain_contiguous_space(len)),
796  		  pos(space.bp_data),
797  		  deep(d) {
798  	      }
799  	
800  	      void flush_and_continue() {
801  		const size_t l = pos - space.bp_data;
802  		*space.bp_len += l;
803  		*space.bl_len += l;
804  		space.bp_data = pos;
805  	      }
806  	
807  	      friend class list;
808  	      template<typename Type> friend class ::DencDumper;
809  	
810  	    public:
811  	      ~contiguous_appender() {
812  		flush_and_continue();
813  	      }
814  	
815  	      size_t get_out_of_band_offset() const {
816  		return out_of_band_offset;
817  	      }
818  	      void append(const char* __restrict__ p, size_t l) {
819  		maybe_inline_memcpy(pos, p, l, 16);
820  		pos += l;
821  	      }
822  	      char *get_pos_add(size_t len) {
823  		char *r = pos;
824  		pos += len;
825  		return r;
826  	      }
827  	      char *get_pos() const {
828  		return pos;
829  	      }
830  	
831  	      void append(const bufferptr& p) {
832  		const auto plen = p.length();
833  		if (!plen) {
834  		  return;
835  		}
836  		if (deep) {
837  		  append(p.c_str(), plen);
838  		} else {
839  		  flush_and_continue();
840  		  bl.append(p);
841  		  space = bl.obtain_contiguous_space(0);
842  		  out_of_band_offset += plen;
843  		}
844  	      }
845  	      void append(const bufferlist& l) {
846  		if (deep) {
847  		  for (const auto &p : l._buffers) {
848  		    append(p.c_str(), p.length());
849  		  }
850  		} else {
851  		  flush_and_continue();
852  		  bl.append(l);
853  		  space = bl.obtain_contiguous_space(0);
854  		  out_of_band_offset += l.length();
855  		}
856  	      }
857  	
858  	      size_t get_logical_offset() const {
859  		return out_of_band_offset + (pos - space.bp_data);
860  	      }
861  	    };
862  	
863  	    contiguous_appender get_contiguous_appender(size_t len, bool deep=false) {
864  	      return contiguous_appender(*this, len, deep);
865  	    }
866  	
867  	    class contiguous_filler {
868  	      friend buffer::list;
869  	      char* pos;
870  	
871  	      contiguous_filler(char* const pos) : pos(pos) {}
872  	
873  	    public:
874  	      void advance(const unsigned len) {
875  		pos += len;
876  	      }
877  	      void copy_in(const unsigned len, const char* const src) {
878  		memcpy(pos, src, len);
879  		advance(len);
880  	      }
881  	      char* c_str() {
882  	        return pos;
883  	      }
884  	    };
885  	    // The contiguous_filler is supposed to be not costlier than a single
886  	    // pointer. Keep it dumb, please.
887  	    static_assert(sizeof(contiguous_filler) == sizeof(char*),
888  			  "contiguous_filler should be no costlier than pointer");
889  	
890  	    class page_aligned_appender {
891  	      bufferlist *pbl;
892  	      unsigned min_alloc;
893  	      ptr buffer;
894  	      char *pos, *end;
895  	
896  	      page_aligned_appender(list *l, unsigned min_pages)
897  		: pbl(l),
898  		  min_alloc(min_pages * CEPH_PAGE_SIZE),
899  		  pos(nullptr), end(nullptr) {}
900  	
901  	      friend class list;
902  	
903  	    public:
904  	      ~page_aligned_appender() {
905  		flush();
906  	      }
907  	
908  	      void flush() {
909  		if (pos && pos != buffer.c_str()) {
910  		  size_t len = pos - buffer.c_str();
911  		  pbl->append(buffer, 0, len);
912  		  buffer.set_length(buffer.length() - len);
913  		  buffer.set_offset(buffer.offset() + len);
914  		}
915  	      }
916  	
917  	      void append(const char *buf, size_t len) {
918  		while (len > 0) {
919  		  if (!pos) {
920  		    size_t alloc = (len + CEPH_PAGE_SIZE - 1) & CEPH_PAGE_MASK;
921  		    if (alloc < min_alloc) {
922  		      alloc = min_alloc;
923  		    }
924  		    buffer = create_page_aligned(alloc);
925  		    pos = buffer.c_str();
926  		    end = buffer.end_c_str();
927  		  }
928  		  size_t l = len;
929  		  if (l > (size_t)(end - pos)) {
930  		    l = end - pos;
931  		  }
932  		  memcpy(pos, buf, l);
933  		  pos += l;
934  		  buf += l;
935  		  len -= l;
936  		  if (pos == end) {
937  		    pbl->append(buffer, 0, buffer.length());
938  		    pos = end = nullptr;
939  		  }
940  		}
941  	      }
942  	    };
943  	
944  	    page_aligned_appender get_page_aligned_appender(unsigned min_pages=1) {
945  	      return page_aligned_appender(this, min_pages);
946  	    }
947  	
948  	  private:
949  	    mutable iterator last_p;
950  	
951  	    // always_empty_bptr has no underlying raw but its _len is always 0.
952  	    // This is useful for e.g. get_append_buffer_unused_tail_length() as
953  	    // it allows to avoid conditionals on hot paths.
954  	    static ptr always_empty_bptr;
955  	    ptr_node& refill_append_space(const unsigned len);
956  	
957  	  public:
958  	    // cons/des
959  	    list()
960  	      : _carriage(&always_empty_bptr),
961  	        _len(0),
962  	        _memcopy_count(0),
(1) Event fun_call_w_exception: Called function throws an exception of type "ceph::buffer::v14_2_0::end_of_buffer". [details]
963  	        last_p(this) {
964  	    }
965  	    // cppcheck-suppress noExplicitConstructor
966  	    // cppcheck-suppress noExplicitConstructor
967  	    list(unsigned prealloc)
968  	      : _carriage(&always_empty_bptr),
969  	        _len(0),
970  	        _memcopy_count(0),
971  		last_p(this) {
972  	      reserve(prealloc);
973  	    }
974  	
975  	    list(const list& other)
976  	      : _carriage(&always_empty_bptr),
977  	        _len(other._len),
978  	        _memcopy_count(other._memcopy_count),
979  	        last_p(this) {
980  	      _buffers.clone_from(other._buffers);
981  	    }
982  	    list(list&& other) noexcept;
983  	
984  	    ~list() {
985  	      _buffers.clear_and_dispose();
986  	    }
987  	
988  	    list& operator= (const list& other) {
989  	      if (this != &other) {
990  	        _carriage = &always_empty_bptr;
991  	        _buffers.clone_from(other._buffers);
992  	        _len = other._len;
993  	      }
994  	      return *this;
995  	    }
996  	    list& operator= (list&& other) noexcept {
997  	      _buffers = std::move(other._buffers);
998  	      _carriage = other._carriage;
999  	      _len = other._len;
1000 	      _memcopy_count = other._memcopy_count;
1001 	      last_p = begin();
1002 	      other.clear();
1003 	      return *this;
1004 	    }
1005 	
1006 	    uint64_t get_wasted_space() const;
1007 	    unsigned get_num_buffers() const { return _buffers.size(); }
1008 	    const ptr_node& front() const { return _buffers.front(); }
1009 	    const ptr_node& back() const { return _buffers.back(); }
1010 	
1011 	    int get_mempool() const;
1012 	    void reassign_to_mempool(int pool);
1013 	    void try_assign_to_mempool(int pool);
1014 	
1015 	    size_t get_append_buffer_unused_tail_length() const {
1016 	      return _carriage->unused_tail_length();
1017 	    }
1018 	
1019 	    unsigned get_memcopy_count() const {return _memcopy_count; }
1020 	    const buffers_t& buffers() const { return _buffers; }
1021 	    void swap(list& other) noexcept;
1022 	    unsigned length() const {
1023 	#if 0
1024 	      // DEBUG: verify _len
1025 	      unsigned len = 0;
1026 	      for (std::list<ptr>::const_iterator it = _buffers.begin();
1027 		   it != _buffers.end();
1028 		   it++) {
1029 		len += (*it).length();
1030 	      }
1031 	#ifdef __CEPH__
1032 	      ceph_assert(len == _len);
1033 	#else
1034 	      assert(len == _len);
1035 	#endif // __CEPH__
1036 	#endif
1037 	      return _len;
1038 	    }
1039 	
1040 	    bool contents_equal(const buffer::list& other) const;
1041 	    bool contents_equal(const void* other, size_t length) const;
1042 	
1043 	    bool is_provided_buffer(const char *dst) const;
1044 	    bool is_aligned(unsigned align) const;
1045 	    bool is_page_aligned() const;
1046 	    bool is_n_align_sized(unsigned align) const;
1047 	    bool is_n_page_sized() const;
1048 	    bool is_aligned_size_and_memory(unsigned align_size,
1049 					    unsigned align_memory) const;
1050 	
1051 	    bool is_zero() const;
1052 	
1053 	    // modifiers
1054 	    void clear() noexcept {
1055 	      _carriage = &always_empty_bptr;
1056 	      _buffers.clear_and_dispose();
1057 	      _len = 0;
1058 	      _memcopy_count = 0;
1059 	      last_p = begin();
1060 	    }
1061 	    void push_back(const ptr& bp) {
1062 	      if (bp.length() == 0)
1063 		return;
1064 	      _buffers.push_back(*ptr_node::create(bp).release());
1065 	      _len += bp.length();
1066 	    }
1067 	    void push_back(ptr&& bp) {
1068 	      if (bp.length() == 0)
1069 		return;
1070 	      _len += bp.length();
1071 	      _buffers.push_back(*ptr_node::create(std::move(bp)).release());
1072 	      _carriage = &always_empty_bptr;
1073 	    }
1074 	    void push_back(const ptr_node&) = delete;
1075 	    void push_back(ptr_node&) = delete;
1076 	    void push_back(ptr_node&&) = delete;
1077 	    void push_back(std::unique_ptr<ptr_node, ptr_node::disposer> bp) {
1078 	      if (bp->length() == 0)
1079 		return;
1080 	      _carriage = bp.get();
1081 	      _len += bp->length();
1082 	      _buffers.push_back(*bp.release());
1083 	    }
1084 	    void push_back(raw* const r) {
1085 	      _buffers.push_back(*ptr_node::create(r).release());
1086 	      _carriage = &_buffers.back();
1087 	      _len += _buffers.back().length();
1088 	    }
1089 	    void push_back(ceph::unique_leakable_ptr<raw> r) {
1090 	      push_back(r.release());
1091 	    }
1092 	
1093 	    void zero();
1094 	    void zero(unsigned o, unsigned l);
1095 	
1096 	    bool is_contiguous() const;
1097 	    void rebuild();
1098 	    void rebuild(std::unique_ptr<ptr_node, ptr_node::disposer> nb);
1099 	    bool rebuild_aligned(unsigned align);
1100 	    // max_buffers = 0 mean don't care _buffers.size(), other
1101 	    // must make _buffers.size() <= max_buffers after rebuilding.
1102 	    bool rebuild_aligned_size_and_memory(unsigned align_size,
1103 						 unsigned align_memory,
1104 						 unsigned max_buffers = 0);
1105 	    bool rebuild_page_aligned();
1106 	
1107 	    void reserve(size_t prealloc);
1108 	
1109 	    // assignment-op with move semantics
1110 	    const static unsigned int CLAIM_DEFAULT = 0;
1111 	    const static unsigned int CLAIM_ALLOW_NONSHAREABLE = 1;
1112 	
1113 	    void claim(list& bl, unsigned int flags = CLAIM_DEFAULT);
1114 	    void claim_append(list& bl, unsigned int flags = CLAIM_DEFAULT);
1115 	    // only for bl is bufferlist::page_aligned_appender
1116 	    void claim_append_piecewise(list& bl);
1117 	
1118 	    // copy with explicit volatile-sharing semantics
1119 	    void share(const list& bl)
1120 	    {
1121 	      if (this != &bl) {
1122 	        clear();
1123 		for (const auto& bp : bl._buffers) {
1124 	          _buffers.push_back(*ptr_node::create(bp).release());
1125 	        }
1126 	        _len = bl._len;
1127 	      }
1128 	    }
1129 	
1130 	#ifdef HAVE_SEASTAR
1131 	    /// convert the bufferlist into a network packet
1132 	    operator seastar::net::packet() &&;
1133 	#endif
1134 	
1135 	    iterator begin() {
1136 	      return iterator(this, 0);
1137 	    }
1138 	    iterator end() {
1139 	      return iterator(this, _len, _buffers.end(), 0);
1140 	    }
1141 	
1142 	    const_iterator begin() const {
1143 	      return const_iterator(this, 0);
1144 	    }
1145 	    const_iterator cbegin() const {
1146 	      return begin();
1147 	    }
1148 	    const_iterator end() const {
1149 	      return const_iterator(this, _len, _buffers.end(), 0);
1150 	    }
1151 	
1152 	    // crope lookalikes.
1153 	    // **** WARNING: this are horribly inefficient for large bufferlists. ****
1154 	    void copy(unsigned off, unsigned len, char *dest) const;
1155 	    void copy(unsigned off, unsigned len, list &dest) const;
1156 	    void copy(unsigned off, unsigned len, std::string& dest) const;
1157 	    void copy_in(unsigned off, unsigned len, const char *src, bool crc_reset = true);
1158 	    void copy_in(unsigned off, unsigned len, const list& src);
1159 	
1160 	    void append(char c);
1161 	    void append(const char *data, unsigned len);
1162 	    void append(std::string s) {
1163 	      append(s.data(), s.length());
1164 	    }
1165 	#if __cplusplus >= 201703L
1166 	    // To forcibly disambiguate between string and string_view in the
1167 	    // case of arrays
1168 	    template<std::size_t N>
1169 	    void append(const char (&s)[N]) {
1170 	      append(s, N);
1171 	    }
1172 	    void append(const char* s) {
1173 	      append(s, strlen(s));
1174 	    }
1175 	    void append(std::string_view s) {
1176 	      append(s.data(), s.length());
1177 	    }
1178 	#endif // __cplusplus >= 201703L
1179 	    void append(const ptr& bp);
1180 	    void append(ptr&& bp);
1181 	    void append(const ptr& bp, unsigned off, unsigned len);
1182 	    void append(const list& bl);
1183 	    void append(std::istream& in);
1184 	    contiguous_filler append_hole(unsigned len);
1185 	    void append_zero(unsigned len);
1186 	    void prepend_zero(unsigned len);
1187 	
1188 	    reserve_t obtain_contiguous_space(unsigned len);
1189 	
1190 	    /*
1191 	     * get a char
1192 	     */
1193 	    const char& operator[](unsigned n) const;
1194 	    char *c_str();
1195 	    std::string to_str() const;
1196 	
1197 	    void substr_of(const list& other, unsigned off, unsigned len);
1198 	
1199 	    // funky modifer
1200 	    void splice(unsigned off, unsigned len, list *claim_by=0 /*, bufferlist& replace_with */);
1201 	    void write(int off, int len, std::ostream& out) const;
1202 	
1203 	    void encode_base64(list& o);
1204 	    void decode_base64(list& o);
1205 	
1206 	    void write_stream(std::ostream &out) const;
1207 	    void hexdump(std::ostream &out, bool trailing_newline = true) const;
1208 	    ssize_t pread_file(const char *fn, uint64_t off, uint64_t len, std::string *error);
1209 	    int read_file(const char *fn, std::string *error);
1210 	    ssize_t read_fd(int fd, size_t len);
1211 	    int write_file(const char *fn, int mode=0644);
1212 	    int write_fd(int fd) const;
1213 	    int write_fd(int fd, uint64_t offset) const;
1214 	    template<typename VectorT>
1215 	    void prepare_iov(VectorT *piov) const {
1216 	#ifdef __CEPH__
1217 	      ceph_assert(_buffers.size() <= IOV_MAX);
1218 	#else
1219 	      assert(_buffers.size() <= IOV_MAX);
1220 	#endif
1221 	      piov->resize(_buffers.size());
1222 	      unsigned n = 0;
1223 	      for (auto& p : _buffers) {
1224 		(*piov)[n].iov_base = (void *)p.c_str();
1225 		(*piov)[n].iov_len = p.length();
1226 		++n;
1227 	      }
1228 	    }
1229 	    uint32_t crc32c(uint32_t crc) const;
1230 	    void invalidate_crc();
1231 	
1232 	    // These functions return a bufferlist with a pointer to a single
1233 	    // static buffer. They /must/ not outlive the memory they
1234 	    // reference.
1235 	    static list static_from_mem(char* c, size_t l);
1236 	    static list static_from_cstring(char* c);
1237 	    static list static_from_string(std::string& s);
1238 	  };
1239 	
1240 	} // inline namespace v14_2_0
1241 	
1242 	  /*
1243 	   * efficient hash of one or more bufferlists
1244 	   */
1245 	
1246 	  class hash {
1247 	    uint32_t crc;
1248 	
1249 	  public:
1250 	    hash() : crc(0) { }
1251 	    // cppcheck-suppress noExplicitConstructor
1252 	    hash(uint32_t init) : crc(init) { }
1253 	
1254 	    void update(const buffer::list& bl) {
1255 	      crc = bl.crc32c(crc);
1256 	    }
1257 	
1258 	    uint32_t digest() {
1259 	      return crc;
1260 	    }
1261 	  };
1262 	
1263 	inline bool operator>(bufferlist& l, bufferlist& r) {
1264 	  for (unsigned p = 0; ; p++) {
1265 	    if (l.length() > p && r.length() == p) return true;
1266 	    if (l.length() == p) return false;
1267 	    if (l[p] > r[p]) return true;
1268 	    if (l[p] < r[p]) return false;
1269 	  }
1270 	}
1271 	inline bool operator>=(bufferlist& l, bufferlist& r) {
1272 	  for (unsigned p = 0; ; p++) {
1273 	    if (l.length() > p && r.length() == p) return true;
1274 	    if (r.length() == p && l.length() == p) return true;
1275 	    if (l.length() == p && r.length() > p) return false;
1276 	    if (l[p] > r[p]) return true;
1277 	    if (l[p] < r[p]) return false;
1278 	  }
1279 	}
1280 	
1281 	inline bool operator==(const bufferlist &l, const bufferlist &r) {
1282 	  if (l.length() != r.length())
1283 	    return false;
1284 	  for (unsigned p = 0; p < l.length(); p++) {
1285 	    if (l[p] != r[p])
1286 	      return false;
1287 	  }
1288 	  return true;
1289 	}
1290 	inline bool operator<(bufferlist& l, bufferlist& r) {
1291 	  return r > l;
1292 	}
1293 	inline bool operator<=(bufferlist& l, bufferlist& r) {
1294 	  return r >= l;
1295 	}
1296 	
1297 	
1298 	std::ostream& operator<<(std::ostream& out, const buffer::ptr& bp);
1299 	
1300 	std::ostream& operator<<(std::ostream& out, const buffer::raw &r);
1301 	
1302 	std::ostream& operator<<(std::ostream& out, const buffer::list& bl);
1303 	
1304 	std::ostream& operator<<(std::ostream& out, const buffer::error& e);
1305 	
1306 	inline bufferhash& operator<<(bufferhash& l, const bufferlist &r) {
1307 	  l.update(r);
1308 	  return l;
1309 	}
1310 	
1311 	} // namespace buffer
1312 	
1313 	} // namespace ceph
1314 	
1315 	#endif
1316