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_TYPES_H
15   	#define CEPH_TYPES_H
16   	
17   	// this is needed for ceph_fs to compile in userland
18   	#include "int_types.h"
19   	#include "byteorder.h"
20   	
21   	#include "uuid.h"
22   	
23   	#include <netinet/in.h>
24   	#include <fcntl.h>
25   	#include <string.h>
26   	
27   	#include "ceph_fs.h"
28   	#include "ceph_frag.h"
29   	#include "rbd_types.h"
30   	
31   	#ifdef __cplusplus
32   	#ifndef _BACKWARD_BACKWARD_WARNING_H
33   	#define _BACKWARD_BACKWARD_WARNING_H   // make gcc 4.3 shut up about hash_*
34   	#endif
35   	#endif
36   	
37   	extern "C" {
38   	#include <stdint.h>
39   	#include <sys/types.h>
40   	#include <sys/stat.h>
41   	#include "statlite.h"
42   	}
43   	
44   	#include <string>
45   	#include <list>
46   	#include <set>
47   	#include <boost/container/flat_set.hpp>
48   	#include <boost/container/flat_map.hpp>
49   	#include <map>
50   	#include <vector>
51   	#include <optional>
52   	#include <iostream>
53   	#include <iomanip>
54   	
55   	
56   	#include "include/unordered_map.h"
57   	
58   	#include "object.h"
59   	#include "intarith.h"
60   	
61   	#include "acconfig.h"
62   	
63   	#include "assert.h"
64   	
65   	// DARWIN compatibility
66   	#ifdef __APPLE__
67   	typedef long long loff_t;
68   	typedef long long off64_t;
69   	#define O_DIRECT 00040000
70   	#endif
71   	
72   	// FreeBSD compatibility
73   	#ifdef __FreeBSD__
74   	typedef off_t loff_t;
75   	typedef off_t off64_t;
76   	#endif
77   	
78   	#if defined(__sun) || defined(_AIX)
79   	typedef off_t loff_t;
80   	#endif
81   	
82   	
83   	// -- io helpers --
84   	
85   	// Forward declare all the I/O helpers so strict ADL can find them in
86   	// the case of containers of containers. I'm tempted to abstract this
87   	// stuff using template templates like I did for denc.
88   	
89   	namespace std {
90   	template<class A, class B>
91   	inline std::ostream& operator<<(std::ostream&out, const std::pair<A,B>& v);
92   	template<class A, class Alloc>
93   	inline std::ostream& operator<<(std::ostream& out, const std::vector<A,Alloc>& v);
94   	template<class A, std::size_t N, class Alloc>
95   	inline std::ostream& operator<<(std::ostream& out, const boost::container::small_vector<A,N,Alloc>& v);
96   	template<class A, class Comp, class Alloc>
97   	inline std::ostream& operator<<(std::ostream& out, const std::deque<A,Alloc>& v);
98   	template<typename... Ts>
99   	inline std::ostream& operator<<(std::ostream& out, const std::tuple<Ts...> &t);
100  	template<typename T>
101  	inline std::ostream& operator<<(std::ostream& out, const std::optional<T> &t);
102  	template<class A, class Alloc>
103  	inline std::ostream& operator<<(std::ostream& out, const std::list<A,Alloc>& ilist);
104  	template<class A, class Comp, class Alloc>
105  	inline std::ostream& operator<<(std::ostream& out, const std::set<A, Comp, Alloc>& iset);
106  	template<class A, class Comp, class Alloc>
107  	inline std::ostream& operator<<(std::ostream& out, const std::multiset<A,Comp,Alloc>& iset);
108  	template<class A, class B, class Comp, class Alloc>
109  	inline std::ostream& operator<<(std::ostream& out, const std::map<A,B,Comp,Alloc>& m);
110  	template<class A, class B, class Comp, class Alloc>
111  	inline std::ostream& operator<<(std::ostream& out, const std::multimap<A,B,Comp,Alloc>& m);
112  	}
113  	
114  	namespace boost {
115  	template<typename... Ts>
116  	inline std::ostream& operator<<(std::ostream& out, const boost::tuple<Ts...> &t);
117  	
118  	namespace container {
119  	template<class A, class Comp, class Alloc>
120  	inline std::ostream& operator<<(std::ostream& out, const boost::container::flat_set<A, Comp, Alloc>& iset);
121  	template<class A, class B, class Comp, class Alloc>
122  	inline std::ostream& operator<<(std::ostream& out, const boost::container::flat_map<A, B, Comp, Alloc>& iset);
123  	}
124  	}
125  	
126  	namespace std {
127  	template<class A, class B>
128  	inline std::ostream& operator<<(std::ostream& out, const std::pair<A,B>& v) {
129  	  return out << v.first << "," << v.second;
130  	}
131  	
132  	template<class A, class Alloc>
133  	inline std::ostream& operator<<(std::ostream& out, const std::vector<A,Alloc>& v) {
134  	  bool first = true;
135  	  out << "[";
136  	  for (const auto& p : v) {
137  	    if (!first) out << ",";
138  	    out << p;
139  	    first = false;
140  	  }
141  	  out << "]";
142  	  return out;
143  	}
144  	
145  	template<class A, std::size_t N, class Alloc>
146  	inline std::ostream& operator<<(std::ostream& out, const boost::container::small_vector<A,N,Alloc>& v) {
147  	  bool first = true;
148  	  out << "[";
149  	  for (const auto& p : v) {
150  	    if (!first) out << ",";
151  	    out << p;
152  	    first = false;
153  	  }
154  	  out << "]";
155  	  return out;
156  	}
157  	
158  	template<class A, class Alloc>
159  	inline std::ostream& operator<<(std::ostream& out, const std::deque<A,Alloc>& v) {
160  	  out << "<";
161  	  for (auto p = v.begin(); p != v.end(); ++p) {
162  	    if (p != v.begin()) out << ",";
163  	    out << *p;
164  	  }
165  	  out << ">";
166  	  return out;
167  	}
168  	
169  	template<typename... Ts>
170  	inline std::ostream& operator<<(std::ostream& out, const std::tuple<Ts...> &t) {
171  	  auto f = [n = sizeof...(Ts), i = 0U, &out](const auto& e) mutable {
172  	    out << e;
173  	    if (++i != n)
174  	      out << ",";
175  	  };
176  	  ceph::for_each(t, f);
177  	  return out;
178  	}
179  	
180  	// Mimics boost::optional
181  	template<typename T>
182  	inline std::ostream& operator<<(std::ostream& out, const std::optional<T> &t) {
183  	  if (!t)
184  	    out << "--" ;
185  	  else
186  	    out << ' ' << *t ;
187  	  return out;
188  	}
189  	
190  	template<class A, class Alloc>
191  	inline std::ostream& operator<<(std::ostream& out, const std::list<A,Alloc>& ilist) {
192  	  for (auto it = ilist.begin();
193  	       it != ilist.end();
194  	       ++it) {
195  	    if (it != ilist.begin()) out << ",";
196  	    out << *it;
197  	  }
198  	  return out;
199  	}
200  	
201  	template<class A, class Comp, class Alloc>
202  	inline std::ostream& operator<<(std::ostream& out, const std::set<A, Comp, Alloc>& iset) {
203  	  for (auto it = iset.begin();
204  	       it != iset.end();
205  	       ++it) {
206  	    if (it != iset.begin()) out << ",";
207  	    out << *it;
208  	  }
209  	  return out;
210  	}
211  	
212  	template<class A, class Comp, class Alloc>
213  	inline std::ostream& operator<<(std::ostream& out, const std::multiset<A,Comp,Alloc>& iset) {
214  	  for (auto it = iset.begin();
215  	       it != iset.end();
216  	       ++it) {
217  	    if (it != iset.begin()) out << ",";
218  	    out << *it;
219  	  }
220  	  return out;
221  	}
222  	
223  	template<class A, class B, class Comp, class Alloc>
224  	inline std::ostream& operator<<(std::ostream& out, const std::map<A,B,Comp,Alloc>& m)
225  	{
226  	  out << "{";
227  	  for (auto it = m.begin();
228  	       it != m.end();
229  	       ++it) {
230  	    if (it != m.begin()) out << ",";
231  	    out << it->first << "=" << it->second;
232  	  }
233  	  out << "}";
234  	  return out;
235  	}
236  	
237  	template<class A, class B, class Comp, class Alloc>
238  	inline std::ostream& operator<<(std::ostream& out, const std::multimap<A,B,Comp,Alloc>& m)
239  	{
240  	  out << "{{";
241  	  for (auto it = m.begin();
242  	       it != m.end();
243  	       ++it) {
244  	    if (it != m.begin()) out << ",";
245  	    out << it->first << "=" << it->second;
246  	  }
247  	  out << "}}";
248  	  return out;
249  	}
250  	
251  	} // namespace std
252  	
253  	namespace boost {
254  	namespace tuples {
255  	template<typename A, typename B, typename C>
256  	inline std::ostream& operator<<(std::ostream& out, const boost::tuples::tuple<A, B, C> &t) {
257  	  return out << boost::get<0>(t) << ","
258  		     << boost::get<1>(t) << ","
259  		     << boost::get<2>(t);
260  	}
261  	}
262  	namespace container {
263  	template<class A, class Comp, class Alloc>
264  	inline std::ostream& operator<<(std::ostream& out, const boost::container::flat_set<A, Comp, Alloc>& iset) {
265  	  for (auto it = iset.begin();
266  	       it != iset.end();
267  	       ++it) {
268  	    if (it != iset.begin()) out << ",";
269  	    out << *it;
270  	  }
271  	  return out;
272  	}
273  	
274  	template<class A, class B, class Comp, class Alloc>
275  	inline std::ostream& operator<<(std::ostream& out, const boost::container::flat_map<A, B, Comp, Alloc>& m) {
276  	  for (auto it = m.begin();
277  	       it != m.end();
278  	       ++it) {
279  	    if (it != m.begin()) out << ",";
280  	    out << it->first << "=" << it->second;
281  	  }
282  	  return out;
283  	}
284  	}
285  	} // namespace boost
286  	
287  	
288  	
289  	/*
290  	 * comparators for stl containers
291  	 */
292  	// for ceph::unordered_map:
293  	//   ceph::unordered_map<const char*, long, hash<const char*>, eqstr> vals;
294  	struct eqstr
295  	{
296  	  bool operator()(const char* s1, const char* s2) const
297  	  {
298  	    return strcmp(s1, s2) == 0;
299  	  }
300  	};
301  	
302  	// for set, map
303  	struct ltstr
304  	{
305  	  bool operator()(const char* s1, const char* s2) const
306  	  {
307  	    return strcmp(s1, s2) < 0;
308  	  }
309  	};
310  	
311  	
312  	namespace ceph {
313  	  class Formatter;
314  	}
315  	
316  	#include "encoding.h"
317  	
318  	WRITE_RAW_ENCODER(ceph_fsid)
319  	WRITE_RAW_ENCODER(ceph_file_layout)
320  	WRITE_RAW_ENCODER(ceph_dir_layout)
321  	WRITE_RAW_ENCODER(ceph_mds_session_head)
322  	WRITE_RAW_ENCODER(ceph_mds_request_head_legacy)
323  	WRITE_RAW_ENCODER(ceph_mds_request_head)
324  	WRITE_RAW_ENCODER(ceph_mds_request_release)
325  	WRITE_RAW_ENCODER(ceph_filelock)
326  	WRITE_RAW_ENCODER(ceph_mds_caps_head)
327  	WRITE_RAW_ENCODER(ceph_mds_caps_body_legacy)
328  	WRITE_RAW_ENCODER(ceph_mds_cap_peer)
329  	WRITE_RAW_ENCODER(ceph_mds_cap_release)
330  	WRITE_RAW_ENCODER(ceph_mds_cap_item)
331  	WRITE_RAW_ENCODER(ceph_mds_lease)
332  	WRITE_RAW_ENCODER(ceph_mds_snap_head)
333  	WRITE_RAW_ENCODER(ceph_mds_snap_realm)
334  	WRITE_RAW_ENCODER(ceph_mds_reply_head)
335  	WRITE_RAW_ENCODER(ceph_mds_reply_cap)
336  	WRITE_RAW_ENCODER(ceph_mds_cap_reconnect)
337  	WRITE_RAW_ENCODER(ceph_mds_snaprealm_reconnect)
338  	WRITE_RAW_ENCODER(ceph_frag_tree_split)
339  	WRITE_RAW_ENCODER(ceph_osd_reply_head)
340  	WRITE_RAW_ENCODER(ceph_osd_op)
341  	WRITE_RAW_ENCODER(ceph_msg_header)
342  	WRITE_RAW_ENCODER(ceph_msg_footer)
343  	WRITE_RAW_ENCODER(ceph_msg_footer_old)
344  	WRITE_RAW_ENCODER(ceph_mon_subscribe_item)
345  	
346  	WRITE_RAW_ENCODER(ceph_mon_statfs)
347  	WRITE_RAW_ENCODER(ceph_mon_statfs_reply)
348  	
349  	// ----------------------
350  	// some basic types
351  	
352  	// NOTE: these must match ceph_fs.h typedefs
353  	typedef uint64_t ceph_tid_t; // transaction id
354  	typedef uint64_t version_t;
355  	typedef __u32 epoch_t;       // map epoch  (32bits -> 13 epochs/second for 10 years)
356  	
357  	// --------------------------------------
358  	// identify individual mount clients by 64bit value
359  	
360  	struct client_t {
361  	  int64_t v;
362  	
363  	  // cppcheck-suppress noExplicitConstructor
364  	  client_t(int64_t _v = -2) : v(_v) {}
365  	
366  	  void encode(ceph::buffer::list& bl) const {
367  	    using ceph::encode;
368  	    encode(v, bl);
369  	  }
370  	  void decode(ceph::buffer::list::const_iterator& bl) {
371  	    using ceph::decode;
372  	    decode(v, bl);
373  	  }
374  	};
375  	WRITE_CLASS_ENCODER(client_t)
376  	
377  	static inline bool operator==(const client_t& l, const client_t& r) { return l.v == r.v; }
378  	static inline bool operator!=(const client_t& l, const client_t& r) { return l.v != r.v; }
379  	static inline bool operator<(const client_t& l, const client_t& r) { return l.v < r.v; }
380  	static inline bool operator<=(const client_t& l, const client_t& r) { return l.v <= r.v; }
381  	static inline bool operator>(const client_t& l, const client_t& r) { return l.v > r.v; }
382  	static inline bool operator>=(const client_t& l, const client_t& r) { return l.v >= r.v; }
383  	
384  	static inline bool operator>=(const client_t& l, int64_t o) { return l.v >= o; }
385  	static inline bool operator<(const client_t& l, int64_t o) { return l.v < o; }
386  	
387  	inline std::ostream& operator<<(std::ostream& out, const client_t& c) {
388  	  return out << c.v;
389  	}
390  	
391  	
392  	
393  	// --
394  	
395  	namespace {
396  	inline std::ostream& format_u(std::ostream& out, const uint64_t v, const uint64_t n,
397  	      const int index, const uint64_t mult, const char* u)
398  	  {
399  	    char buffer[32];
400  	
401  	    if (index == 0) {
402  	      (void) snprintf(buffer, sizeof(buffer), "%" PRId64 "%s", n, u);
403  	    } else if ((v % mult) == 0) {
404  	      // If this is an even multiple of the base, always display
405  	      // without any decimal fraction.
406  	      (void) snprintf(buffer, sizeof(buffer), "%" PRId64 "%s", n, u);
407  	    } else {
408  	      // We want to choose a precision that reflects the best choice
409  	      // for fitting in 5 characters.  This can get rather tricky when
410  	      // we have numbers that are very close to an order of magnitude.
411  	      // For example, when displaying 10239 (which is really 9.999K),
412  	      // we want only a single place of precision for 10.0K.  We could
413  	      // develop some complex heuristics for this, but it's much
414  	      // easier just to try each combination in turn.
415  	      int i;
416  	      for (i = 2; i >= 0; i--) {
417  	        if (snprintf(buffer, sizeof(buffer), "%.*f%s", i,
418  	          static_cast<double>(v) / mult, u) <= 7)
419  	          break;
420  	      }
421  	    }
422  	
423  	    return out << buffer;
424  	  }
425  	}
426  	
427  	/*
428  	 * Use this struct to pretty print values that should be formatted with a
429  	 * decimal unit prefix (the classic SI units). No actual unit will be added.
430  	 */
431  	struct si_u_t {
432  	  uint64_t v;
433  	  explicit si_u_t(uint64_t _v) : v(_v) {};
434  	};
435  	
436  	inline std::ostream& operator<<(std::ostream& out, const si_u_t& b)
437  	{
438  	  uint64_t n = b.v;
439  	  int index = 0;
440  	  uint64_t mult = 1;
441  	  const char* u[] = {"", "k", "M", "G", "T", "P", "E"};
442  	
443  	  while (n >= 1000 && index < 7) {
444  	    n /= 1000;
445  	    index++;
446  	    mult *= 1000;
447  	  }
448  	
449  	  return format_u(out, b.v, n, index, mult, u[index]);
450  	}
451  	
452  	/*
453  	 * Use this struct to pretty print values that should be formatted with a
454  	 * binary unit prefix (IEC units). Since binary unit prefixes are to be used for
455  	 * "multiples of units in data processing, data transmission, and digital
456  	 * information" (so bits and bytes) and so far bits are not printed, the unit
457  	 * "B" for "byte" is added besides the multiplier.
458  	 */
459  	struct byte_u_t {
460  	  uint64_t v;
461  	  explicit byte_u_t(uint64_t _v) : v(_v) {};
462  	};
463  	
464  	inline std::ostream& operator<<(std::ostream& out, const byte_u_t& b)
465  	{
466  	  uint64_t n = b.v;
467  	  int index = 0;
468  	  const char* u[] = {" B", " KiB", " MiB", " GiB", " TiB", " PiB", " EiB"};
469  	
(1) Event cond_true: Condition "n >= 1024", taking true branch.
(2) Event cond_true: Condition "index < 7", taking true branch.
(4) Event loop_begin: Jumped back to beginning of loop.
(5) Event cond_true: Condition "n >= 1024", taking true branch.
(6) Event cond_true: Condition "index < 7", taking true branch.
(8) Event loop_begin: Jumped back to beginning of loop.
(9) Event cond_true: Condition "n >= 1024", taking true branch.
(10) Event cond_true: Condition "index < 7", taking true branch.
(11) Event cond_at_most: Checking "index < 7" implies that "index" may be up to 6 on the true branch.
(14) Event loop_begin: Jumped back to beginning of loop.
(15) Event cond_false: Condition "n >= 1024", taking false branch.
Also see events: [incr][large_shift]
470  	  while (n >= 1024 && index < 7) {
471  	    n /= 1024;
(12) Event incr: Incrementing "index". The value of "index" may now be up to 7.
Also see events: [cond_at_most][large_shift]
472  	    index++;
(3) Event loop: Jumping back to the beginning of the loop.
(7) Event loop: Jumping back to the beginning of the loop.
(13) Event loop: Jumping back to the beginning of the loop.
(16) Event loop_end: Reached end of loop.
473  	  }
474  	
(17) Event large_shift: In expression "1ULL << 10 * index", left shifting by more than 63 bits has undefined behavior. The shift amount, "10 * index", is as much as 70.
Also see events: [cond_at_most][incr]
475  	  return format_u(out, b.v, n, index, 1ULL << (10 * index), u[index]);
476  	}
477  	
478  	inline std::ostream& operator<<(std::ostream& out, const ceph_mon_subscribe_item& i)
479  	{
480  	  return out << i.start
481  		     << ((i.flags & CEPH_SUBSCRIBE_ONETIME) ? "" : "+");
482  	}
483  	
484  	struct weightf_t {
485  	  float v;
486  	  // cppcheck-suppress noExplicitConstructor
487  	  weightf_t(float _v) : v(_v) {}
488  	};
489  	
490  	inline std::ostream& operator<<(std::ostream& out, const weightf_t& w)
491  	{
492  	  if (w.v < -0.01F) {
493  	    return out << "-";
494  	  } else if (w.v < 0.000001F) {
495  	    return out << "0";
496  	  } else {
497  	    std::streamsize p = out.precision();
498  	    return out << std::fixed << std::setprecision(5) << w.v << std::setprecision(p);
499  	  }
500  	}
501  	
502  	struct shard_id_t {
503  	  int8_t id;
504  	
505  	  shard_id_t() : id(0) {}
506  	  explicit shard_id_t(int8_t _id) : id(_id) {}
507  	
508  	  operator int8_t() const { return id; }
509  	
510  	  const static shard_id_t NO_SHARD;
511  	
512  	  void encode(ceph::buffer::list &bl) const {
513  	    using ceph::encode;
514  	    encode(id, bl);
515  	  }
516  	  void decode(ceph::buffer::list::const_iterator &bl) {
517  	    using ceph::decode;
518  	    decode(id, bl);
519  	  }
520  	};
521  	WRITE_CLASS_ENCODER(shard_id_t)
522  	WRITE_EQ_OPERATORS_1(shard_id_t, id)
523  	WRITE_CMP_OPERATORS_1(shard_id_t, id)
524  	std::ostream &operator<<(std::ostream &lhs, const shard_id_t &rhs);
525  	
526  	#if defined(__sun) || defined(_AIX) || defined(__APPLE__) || defined(__FreeBSD__)
527  	__s32  ceph_to_hostos_errno(__s32 e);
528  	__s32  hostos_to_ceph_errno(__s32 e);
529  	#else
530  	#define  ceph_to_hostos_errno(e) (e)
531  	#define  hostos_to_ceph_errno(e) (e)
532  	#endif
533  	
534  	struct errorcode32_t {
535  	  int32_t code;
536  	
537  	  errorcode32_t() : code(0) {}
538  	  // cppcheck-suppress noExplicitConstructor
539  	  errorcode32_t(int32_t i) : code(i) {}
540  	
541  	  operator int() const  { return code; }
542  	  int* operator&()      { return &code; }
543  	  int operator==(int i) { return code == i; }
544  	  int operator>(int i)  { return code > i; }
545  	  int operator>=(int i) { return code >= i; }
546  	  int operator<(int i)  { return code < i; }
547  	  int operator<=(int i) { return code <= i; }
548  	
549  	  void encode(ceph::buffer::list &bl) const {
550  	    using ceph::encode;
551  	    __s32 newcode = hostos_to_ceph_errno(code);
552  	    encode(newcode, bl);
553  	  }
554  	  void decode(ceph::buffer::list::const_iterator &bl) {
555  	    using ceph::decode;
556  	    decode(code, bl);
557  	    code = ceph_to_hostos_errno(code);
558  	  }
559  	};
560  	WRITE_CLASS_ENCODER(errorcode32_t)
561  	WRITE_EQ_OPERATORS_1(errorcode32_t, code)
562  	WRITE_CMP_OPERATORS_1(errorcode32_t, code)
563  	
564  	template <uint8_t S>
565  	struct sha_digest_t {
566  	  constexpr static uint32_t SIZE = S;
567  	  // TODO: we might consider std::array in the future. Avoiding it for now
568  	  // as sha_digest_t is a part of our public API.
569  	  unsigned char v[S] = {0};
570  	
571  	  std::string to_str() const {
572  	    char str[S * 2 + 1] = {0};
573  	    str[0] = '\0';
574  	    for (size_t i = 0; i < S; i++) {
575  	      ::sprintf(&str[i * 2], "%02x", static_cast<int>(v[i]));
576  	    }
577  	    return string(str);
578  	  }
579  	  sha_digest_t(const unsigned char *_v) { memcpy(v, _v, SIZE); };
580  	  sha_digest_t() {}
581  	
582  	  bool operator==(const sha_digest_t& r) const {
583  	    return ::memcmp(v, r.v, SIZE) == 0;
584  	  }
585  	  bool operator!=(const sha_digest_t& r) const {
586  	    return ::memcmp(v, r.v, SIZE) != 0;
587  	  }
588  	
589  	  void encode(ceph::buffer::list &bl) const {
590  	    // copy to avoid reinterpret_cast, is_pod and other nasty things
591  	    using ceph::encode;
592  	    std::array<unsigned char, SIZE> tmparr;
593  	    memcpy(tmparr.data(), v, SIZE);
594  	    encode(tmparr, bl);
595  	  }
596  	  void decode(ceph::buffer::list::const_iterator &bl) {
597  	    using ceph::decode;
598  	    std::array<unsigned char, SIZE> tmparr;
599  	    decode(tmparr, bl);
600  	    memcpy(v, tmparr.data(), SIZE);
601  	  }
602  	};
603  	
604  	template<uint8_t S>
605  	inline std::ostream &operator<<(std::ostream &out, const sha_digest_t<S> &b) {
606  	  std::string str = b.to_str();
607  	  return out << str;
608  	}
609  	
610  	using sha1_digest_t = sha_digest_t<20>;
611  	WRITE_CLASS_ENCODER(sha1_digest_t)
612  	
613  	using sha256_digest_t = sha_digest_t<32>;
614  	WRITE_CLASS_ENCODER(sha256_digest_t)
615  	
616  	using sha512_digest_t = sha_digest_t<64>;
617  	
618  	using md5_digest_t = sha_digest_t<16>;
619  	WRITE_CLASS_ENCODER(md5_digest_t)
620  	
621  	
622  	#endif
623