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, "ient, &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, "ient, &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