1b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Protocol Buffers - Google's data interchange format
2b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Copyright 2008 Google Inc.  All rights reserved.
3b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// https://developers.google.com/protocol-buffers/
4b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
5b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Redistribution and use in source and binary forms, with or without
6b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// modification, are permitted provided that the following conditions are
7b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// met:
8b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
9b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions of source code must retain the above copyright
10b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// notice, this list of conditions and the following disclaimer.
11b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions in binary form must reproduce the above
12b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// copyright notice, this list of conditions and the following disclaimer
13b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// in the documentation and/or other materials provided with the
14b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// distribution.
15b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Neither the name of Google Inc. nor the names of its
16b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// contributors may be used to endorse or promote products derived from
17b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// this software without specific prior written permission.
18b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
19b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
31b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/stubs/int128.h>
32b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
33b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <iomanip>
34b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <ostream>  // NOLINT(readability/streams)
35b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <sstream>
36b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
37b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammernamespace google {
38b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammernamespace protobuf {
39b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
40b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerconst uint128_pod kuint128max = {
41b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    static_cast<uint64>(GOOGLE_LONGLONG(0xFFFFFFFFFFFFFFFF)),
42b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    static_cast<uint64>(GOOGLE_LONGLONG(0xFFFFFFFFFFFFFFFF))
43b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
44b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
45b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Returns the 0-based position of the last set bit (i.e., most significant bit)
46b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// in the given uint64. The argument may not be 0.
47b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
48b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// For example:
49b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//   Given: 5 (decimal) == 101 (binary)
50b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//   Returns: 2
51b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#define STEP(T, n, pos, sh)                   \
52b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  do {                                        \
53b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if ((n) >= (static_cast<T>(1) << (sh))) { \
54b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      (n) = (n) >> (sh);                      \
55b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      (pos) |= (sh);                          \
56b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }                                         \
57b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } while (0)
58b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic inline int Fls64(uint64 n) {
59b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  GOOGLE_DCHECK_NE(0, n);
60b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  int pos = 0;
61b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  STEP(uint64, n, pos, 0x20);
62b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint32 n32 = n;
63b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  STEP(uint32, n32, pos, 0x10);
64b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  STEP(uint32, n32, pos, 0x08);
65b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  STEP(uint32, n32, pos, 0x04);
66b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return pos + ((GOOGLE_ULONGLONG(0x3333333322221100) >> (n32 << 2)) & 0x3);
67b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
68b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#undef STEP
69b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
70b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Like Fls64() above, but returns the 0-based position of the last set bit
71b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// (i.e., most significant bit) in the given uint128. The argument may not be 0.
72b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic inline int Fls128(uint128 n) {
73b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (uint64 hi = Uint128High64(n)) {
74b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return Fls64(hi) + 64;
75b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
76b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return Fls64(Uint128Low64(n));
77b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
78b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
79b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Long division/modulo for uint128 implemented using the shift-subtract
80b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// division algorithm adapted from:
81b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// http://stackoverflow.com/questions/5386377/division-without-using
82b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid uint128::DivModImpl(uint128 dividend, uint128 divisor,
83b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                         uint128* quotient_ret, uint128* remainder_ret) {
84b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (divisor == 0) {
85b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    GOOGLE_LOG(FATAL) << "Division or mod by zero: dividend.hi=" << dividend.hi_
86b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                      << ", lo=" << dividend.lo_;
87b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
88b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
89b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (divisor > dividend) {
90b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    *quotient_ret = 0;
91b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    *remainder_ret = dividend;
92b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return;
93b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
94b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
95b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (divisor == dividend) {
96b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    *quotient_ret = 1;
97b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    *remainder_ret = 0;
98b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return;
99b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128 denominator = divisor;
102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128 position = 1;
103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128 quotient = 0;
104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Left aligns the MSB of the denominator and the dividend.
106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  int shift = Fls128(dividend) - Fls128(denominator);
107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  denominator <<= shift;
108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  position <<= shift;
109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Uses shift-subtract algorithm to divide dividend by denominator. The
111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // remainder will be left in dividend.
112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  while (position > 0) {
113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (dividend >= denominator) {
114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      dividend -= denominator;
115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      quotient |= position;
116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    position >>= 1;
118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    denominator >>= 1;
119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  *quotient_ret = quotient;
122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  *remainder_ret = dividend;
123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammeruint128& uint128::operator/=(const uint128& divisor) {
126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128 quotient = 0;
127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128 remainder = 0;
128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  DivModImpl(*this, divisor, &quotient, &remainder);
129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  *this = quotient;
130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return *this;
131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammeruint128& uint128::operator%=(const uint128& divisor) {
133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128 quotient = 0;
134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128 remainder = 0;
135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  DivModImpl(*this, divisor, &quotient, &remainder);
136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  *this = remainder;
137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return *this;
138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstd::ostream& operator<<(std::ostream& o, const uint128& b) {
141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  std::ios_base::fmtflags flags = o.flags();
142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Select a divisor which is the largest power of the base < 2^64.
144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128 div;
145b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  std::streamsize div_base_log;
146b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  switch (flags & std::ios::basefield) {
147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case std::ios::hex:
148b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      div = GOOGLE_ULONGLONG(0x1000000000000000);  // 16^15
149b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      div_base_log = 15;
150b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case std::ios::oct:
152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      div = GOOGLE_ULONGLONG(01000000000000000000000);  // 8^21
153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      div_base_log = 21;
154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    default:  // std::ios::dec
156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      div = GOOGLE_ULONGLONG(10000000000000000000);  // 10^19
157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      div_base_log = 19;
158b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
159b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
160b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
161b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Now piece together the uint128 representation from three chunks of
162b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // the original value, each less than "div" and therefore representable
163b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // as a uint64.
164b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  std::ostringstream os;
165b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  std::ios_base::fmtflags copy_mask =
166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      std::ios::basefield | std::ios::showbase | std::ios::uppercase;
167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  os.setf(flags & copy_mask, copy_mask);
168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128 high = b;
169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128 low;
170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128::DivModImpl(high, div, &high, &low);
171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128 mid;
172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint128::DivModImpl(high, div, &high, &mid);
173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (high.lo_ != 0) {
174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    os << high.lo_;
175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    os << mid.lo_;
177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    os << std::setw(div_base_log);
178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else if (mid.lo_ != 0) {
179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    os << mid.lo_;
180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  os << low.lo_;
183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  std::string rep = os.str();
184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Add the requisite padding.
186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  std::streamsize width = o.width(0);
187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (width > rep.size()) {
188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if ((flags & std::ios::adjustfield) == std::ios::left) {
189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      rep.append(width - rep.size(), o.fill());
190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else {
191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      rep.insert(static_cast<std::string::size_type>(0),
192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                 width - rep.size(), o.fill());
193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Stream the final representation in a single "<<" call.
197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return o << rep;
198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}  // namespace protobuf
201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}  // namespace google
202