Media CAS Proxy SDK release: 16.5.0
This commit is contained in:
198
ubuntu/google/protobuf/stubs/bytestream.cc
Normal file
198
ubuntu/google/protobuf/stubs/bytestream.cc
Normal file
@@ -0,0 +1,198 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <google/protobuf/stubs/bytestream.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include <google/protobuf/stubs/logging.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace strings {
|
||||
|
||||
void ByteSource::CopyTo(ByteSink* sink, size_t n) {
|
||||
while (n > 0) {
|
||||
StringPiece fragment = Peek();
|
||||
if (fragment.empty()) {
|
||||
GOOGLE_LOG(DFATAL) << "ByteSource::CopyTo() overran input.";
|
||||
break;
|
||||
}
|
||||
std::size_t fragment_size = std::min<std::size_t>(n, fragment.size());
|
||||
sink->Append(fragment.data(), fragment_size);
|
||||
Skip(fragment_size);
|
||||
n -= fragment_size;
|
||||
}
|
||||
}
|
||||
|
||||
void ByteSink::Flush() {}
|
||||
|
||||
void UncheckedArrayByteSink::Append(const char* data, size_t n) {
|
||||
if (data != dest_) {
|
||||
// Catch cases where the pointer returned by GetAppendBuffer() was modified.
|
||||
GOOGLE_DCHECK(!(dest_ <= data && data < (dest_ + n)))
|
||||
<< "Append() data[] overlaps with dest_[]";
|
||||
memcpy(dest_, data, n);
|
||||
}
|
||||
dest_ += n;
|
||||
}
|
||||
|
||||
CheckedArrayByteSink::CheckedArrayByteSink(char* outbuf, size_t capacity)
|
||||
: outbuf_(outbuf), capacity_(capacity), size_(0), overflowed_(false) {
|
||||
}
|
||||
|
||||
void CheckedArrayByteSink::Append(const char* bytes, size_t n) {
|
||||
size_t available = capacity_ - size_;
|
||||
if (n > available) {
|
||||
n = available;
|
||||
overflowed_ = true;
|
||||
}
|
||||
if (n > 0 && bytes != (outbuf_ + size_)) {
|
||||
// Catch cases where the pointer returned by GetAppendBuffer() was modified.
|
||||
GOOGLE_DCHECK(!(outbuf_ <= bytes && bytes < (outbuf_ + capacity_)))
|
||||
<< "Append() bytes[] overlaps with outbuf_[]";
|
||||
memcpy(outbuf_ + size_, bytes, n);
|
||||
}
|
||||
size_ += n;
|
||||
}
|
||||
|
||||
GrowingArrayByteSink::GrowingArrayByteSink(size_t estimated_size)
|
||||
: capacity_(estimated_size),
|
||||
buf_(new char[estimated_size]),
|
||||
size_(0) {
|
||||
}
|
||||
|
||||
GrowingArrayByteSink::~GrowingArrayByteSink() {
|
||||
delete[] buf_; // Just in case the user didn't call GetBuffer.
|
||||
}
|
||||
|
||||
void GrowingArrayByteSink::Append(const char* bytes, size_t n) {
|
||||
size_t available = capacity_ - size_;
|
||||
if (bytes != (buf_ + size_)) {
|
||||
// Catch cases where the pointer returned by GetAppendBuffer() was modified.
|
||||
// We need to test for this before calling Expand() which may reallocate.
|
||||
GOOGLE_DCHECK(!(buf_ <= bytes && bytes < (buf_ + capacity_)))
|
||||
<< "Append() bytes[] overlaps with buf_[]";
|
||||
}
|
||||
if (n > available) {
|
||||
Expand(n - available);
|
||||
}
|
||||
if (n > 0 && bytes != (buf_ + size_)) {
|
||||
memcpy(buf_ + size_, bytes, n);
|
||||
}
|
||||
size_ += n;
|
||||
}
|
||||
|
||||
char* GrowingArrayByteSink::GetBuffer(size_t* nbytes) {
|
||||
ShrinkToFit();
|
||||
char* b = buf_;
|
||||
*nbytes = size_;
|
||||
buf_ = nullptr;
|
||||
size_ = capacity_ = 0;
|
||||
return b;
|
||||
}
|
||||
|
||||
void GrowingArrayByteSink::Expand(size_t amount) { // Expand by at least 50%.
|
||||
size_t new_capacity = std::max(capacity_ + amount, (3 * capacity_) / 2);
|
||||
char* bigger = new char[new_capacity];
|
||||
memcpy(bigger, buf_, size_);
|
||||
delete[] buf_;
|
||||
buf_ = bigger;
|
||||
capacity_ = new_capacity;
|
||||
}
|
||||
|
||||
void GrowingArrayByteSink::ShrinkToFit() {
|
||||
// Shrink only if the buffer is large and size_ is less than 3/4
|
||||
// of capacity_.
|
||||
if (capacity_ > 256 && size_ < (3 * capacity_) / 4) {
|
||||
char* just_enough = new char[size_];
|
||||
memcpy(just_enough, buf_, size_);
|
||||
delete[] buf_;
|
||||
buf_ = just_enough;
|
||||
capacity_ = size_;
|
||||
}
|
||||
}
|
||||
|
||||
void StringByteSink::Append(const char* data, size_t n) {
|
||||
dest_->append(data, n);
|
||||
}
|
||||
|
||||
size_t ArrayByteSource::Available() const {
|
||||
return input_.size();
|
||||
}
|
||||
|
||||
StringPiece ArrayByteSource::Peek() {
|
||||
return input_;
|
||||
}
|
||||
|
||||
void ArrayByteSource::Skip(size_t n) {
|
||||
GOOGLE_DCHECK_LE(n, input_.size());
|
||||
input_.remove_prefix(n);
|
||||
}
|
||||
|
||||
LimitByteSource::LimitByteSource(ByteSource *source, size_t limit)
|
||||
: source_(source),
|
||||
limit_(limit) {
|
||||
}
|
||||
|
||||
size_t LimitByteSource::Available() const {
|
||||
size_t available = source_->Available();
|
||||
if (available > limit_) {
|
||||
available = limit_;
|
||||
}
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
StringPiece LimitByteSource::Peek() {
|
||||
StringPiece piece(source_->Peek());
|
||||
if (piece.size() > limit_) {
|
||||
piece.set(piece.data(), limit_);
|
||||
}
|
||||
|
||||
return piece;
|
||||
}
|
||||
|
||||
void LimitByteSource::Skip(size_t n) {
|
||||
GOOGLE_DCHECK_LE(n, limit_);
|
||||
source_->Skip(n);
|
||||
limit_ -= n;
|
||||
}
|
||||
|
||||
void LimitByteSource::CopyTo(ByteSink *sink, size_t n) {
|
||||
GOOGLE_DCHECK_LE(n, limit_);
|
||||
source_->CopyTo(sink, n);
|
||||
limit_ -= n;
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
351
ubuntu/google/protobuf/stubs/bytestream.h
Normal file
351
ubuntu/google/protobuf/stubs/bytestream.h
Normal file
@@ -0,0 +1,351 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// This file declares the ByteSink and ByteSource abstract interfaces. These
|
||||
// interfaces represent objects that consume (ByteSink) or produce (ByteSource)
|
||||
// a sequence of bytes. Using these abstract interfaces in your APIs can help
|
||||
// make your code work with a variety of input and output types.
|
||||
//
|
||||
// This file also declares the following commonly used implementations of these
|
||||
// interfaces.
|
||||
//
|
||||
// ByteSink:
|
||||
// UncheckedArrayByteSink Writes to an array, without bounds checking
|
||||
// CheckedArrayByteSink Writes to an array, with bounds checking
|
||||
// GrowingArrayByteSink Allocates and writes to a growable buffer
|
||||
// StringByteSink Writes to an STL string
|
||||
// NullByteSink Consumes a never-ending stream of bytes
|
||||
//
|
||||
// ByteSource:
|
||||
// ArrayByteSource Reads from an array or string/StringPiece
|
||||
// LimitedByteSource Limits the number of bytes read from an
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_BYTESTREAM_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_BYTESTREAM_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stringpiece.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
class CordByteSink;
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace strings {
|
||||
|
||||
// An abstract interface for an object that consumes a sequence of bytes. This
|
||||
// interface offers a way to append data as well as a Flush() function.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// string my_data;
|
||||
// ...
|
||||
// ByteSink* sink = ...
|
||||
// sink->Append(my_data.data(), my_data.size());
|
||||
// sink->Flush();
|
||||
//
|
||||
class PROTOBUF_EXPORT ByteSink {
|
||||
public:
|
||||
ByteSink() {}
|
||||
virtual ~ByteSink() {}
|
||||
|
||||
// Appends the "n" bytes starting at "bytes".
|
||||
virtual void Append(const char* bytes, size_t n) = 0;
|
||||
|
||||
// Flushes internal buffers. The default implementation does nothing. ByteSink
|
||||
// subclasses may use internal buffers that require calling Flush() at the end
|
||||
// of the stream.
|
||||
virtual void Flush();
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSink);
|
||||
};
|
||||
|
||||
// An abstract interface for an object that produces a fixed-size sequence of
|
||||
// bytes.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// ByteSource* source = ...
|
||||
// while (source->Available() > 0) {
|
||||
// StringPiece data = source->Peek();
|
||||
// ... do something with "data" ...
|
||||
// source->Skip(data.length());
|
||||
// }
|
||||
//
|
||||
class PROTOBUF_EXPORT ByteSource {
|
||||
public:
|
||||
ByteSource() {}
|
||||
virtual ~ByteSource() {}
|
||||
|
||||
// Returns the number of bytes left to read from the source. Available()
|
||||
// should decrease by N each time Skip(N) is called. Available() may not
|
||||
// increase. Available() returning 0 indicates that the ByteSource is
|
||||
// exhausted.
|
||||
//
|
||||
// Note: Size() may have been a more appropriate name as it's more
|
||||
// indicative of the fixed-size nature of a ByteSource.
|
||||
virtual size_t Available() const = 0;
|
||||
|
||||
// Returns a StringPiece of the next contiguous region of the source. Does not
|
||||
// reposition the source. The returned region is empty iff Available() == 0.
|
||||
//
|
||||
// The returned region is valid until the next call to Skip() or until this
|
||||
// object is destroyed, whichever occurs first.
|
||||
//
|
||||
// The length of the returned StringPiece will be <= Available().
|
||||
virtual StringPiece Peek() = 0;
|
||||
|
||||
// Skips the next n bytes. Invalidates any StringPiece returned by a previous
|
||||
// call to Peek().
|
||||
//
|
||||
// REQUIRES: Available() >= n
|
||||
virtual void Skip(size_t n) = 0;
|
||||
|
||||
// Writes the next n bytes in this ByteSource to the given ByteSink, and
|
||||
// advances this ByteSource past the copied bytes. The default implementation
|
||||
// of this method just copies the bytes normally, but subclasses might
|
||||
// override CopyTo to optimize certain cases.
|
||||
//
|
||||
// REQUIRES: Available() >= n
|
||||
virtual void CopyTo(ByteSink* sink, size_t n);
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSource);
|
||||
};
|
||||
|
||||
//
|
||||
// Some commonly used implementations of ByteSink
|
||||
//
|
||||
|
||||
// Implementation of ByteSink that writes to an unsized byte array. No
|
||||
// bounds-checking is performed--it is the caller's responsibility to ensure
|
||||
// that the destination array is large enough.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// char buf[10];
|
||||
// UncheckedArrayByteSink sink(buf);
|
||||
// sink.Append("hi", 2); // OK
|
||||
// sink.Append(data, 100); // WOOPS! Overflows buf[10].
|
||||
//
|
||||
class PROTOBUF_EXPORT UncheckedArrayByteSink : public ByteSink {
|
||||
public:
|
||||
explicit UncheckedArrayByteSink(char* dest) : dest_(dest) {}
|
||||
virtual void Append(const char* data, size_t n) override;
|
||||
|
||||
// Returns the current output pointer so that a caller can see how many bytes
|
||||
// were produced.
|
||||
//
|
||||
// Note: this method is not part of the ByteSink interface.
|
||||
char* CurrentDestination() const { return dest_; }
|
||||
|
||||
private:
|
||||
char* dest_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UncheckedArrayByteSink);
|
||||
};
|
||||
|
||||
// Implementation of ByteSink that writes to a sized byte array. This sink will
|
||||
// not write more than "capacity" bytes to outbuf. Once "capacity" bytes are
|
||||
// appended, subsequent bytes will be ignored and Overflowed() will return true.
|
||||
// Overflowed() does not cause a runtime error (i.e., it does not CHECK fail).
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// char buf[10];
|
||||
// CheckedArrayByteSink sink(buf, 10);
|
||||
// sink.Append("hi", 2); // OK
|
||||
// sink.Append(data, 100); // Will only write 8 more bytes
|
||||
//
|
||||
class PROTOBUF_EXPORT CheckedArrayByteSink : public ByteSink {
|
||||
public:
|
||||
CheckedArrayByteSink(char* outbuf, size_t capacity);
|
||||
virtual void Append(const char* bytes, size_t n) override;
|
||||
|
||||
// Returns the number of bytes actually written to the sink.
|
||||
size_t NumberOfBytesWritten() const { return size_; }
|
||||
|
||||
// Returns true if any bytes were discarded, i.e., if there was an
|
||||
// attempt to write more than 'capacity' bytes.
|
||||
bool Overflowed() const { return overflowed_; }
|
||||
|
||||
private:
|
||||
char* outbuf_;
|
||||
const size_t capacity_;
|
||||
size_t size_;
|
||||
bool overflowed_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CheckedArrayByteSink);
|
||||
};
|
||||
|
||||
// Implementation of ByteSink that allocates an internal buffer (a char array)
|
||||
// and expands it as needed to accommodate appended data (similar to a string),
|
||||
// and allows the caller to take ownership of the internal buffer via the
|
||||
// GetBuffer() method. The buffer returned from GetBuffer() must be deleted by
|
||||
// the caller with delete[]. GetBuffer() also sets the internal buffer to be
|
||||
// empty, and subsequent appends to the sink will create a new buffer. The
|
||||
// destructor will free the internal buffer if GetBuffer() was not called.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// GrowingArrayByteSink sink(10);
|
||||
// sink.Append("hi", 2);
|
||||
// sink.Append(data, n);
|
||||
// const char* buf = sink.GetBuffer(); // Ownership transferred
|
||||
// delete[] buf;
|
||||
//
|
||||
class PROTOBUF_EXPORT GrowingArrayByteSink : public strings::ByteSink {
|
||||
public:
|
||||
explicit GrowingArrayByteSink(size_t estimated_size);
|
||||
virtual ~GrowingArrayByteSink();
|
||||
virtual void Append(const char* bytes, size_t n) override;
|
||||
|
||||
// Returns the allocated buffer, and sets nbytes to its size. The caller takes
|
||||
// ownership of the buffer and must delete it with delete[].
|
||||
char* GetBuffer(size_t* nbytes);
|
||||
|
||||
private:
|
||||
void Expand(size_t amount);
|
||||
void ShrinkToFit();
|
||||
|
||||
size_t capacity_;
|
||||
char* buf_;
|
||||
size_t size_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GrowingArrayByteSink);
|
||||
};
|
||||
|
||||
// Implementation of ByteSink that appends to the given string.
|
||||
// Existing contents of "dest" are not modified; new data is appended.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// string dest = "Hello ";
|
||||
// StringByteSink sink(&dest);
|
||||
// sink.Append("World", 5);
|
||||
// assert(dest == "Hello World");
|
||||
//
|
||||
class PROTOBUF_EXPORT StringByteSink : public ByteSink {
|
||||
public:
|
||||
explicit StringByteSink(std::string* dest) : dest_(dest) {}
|
||||
virtual void Append(const char* data, size_t n) override;
|
||||
|
||||
private:
|
||||
std::string* dest_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringByteSink);
|
||||
};
|
||||
|
||||
// Implementation of ByteSink that discards all data.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// NullByteSink sink;
|
||||
// sink.Append(data, data.size()); // All data ignored.
|
||||
//
|
||||
class PROTOBUF_EXPORT NullByteSink : public ByteSink {
|
||||
public:
|
||||
NullByteSink() {}
|
||||
void Append(const char* /*data*/, size_t /*n*/) override {}
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(NullByteSink);
|
||||
};
|
||||
|
||||
//
|
||||
// Some commonly used implementations of ByteSource
|
||||
//
|
||||
|
||||
// Implementation of ByteSource that reads from a StringPiece.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// string data = "Hello";
|
||||
// ArrayByteSource source(data);
|
||||
// assert(source.Available() == 5);
|
||||
// assert(source.Peek() == "Hello");
|
||||
//
|
||||
class PROTOBUF_EXPORT ArrayByteSource : public ByteSource {
|
||||
public:
|
||||
explicit ArrayByteSource(StringPiece s) : input_(s) {}
|
||||
|
||||
virtual size_t Available() const override;
|
||||
virtual StringPiece Peek() override;
|
||||
virtual void Skip(size_t n) override;
|
||||
|
||||
private:
|
||||
StringPiece input_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayByteSource);
|
||||
};
|
||||
|
||||
// Implementation of ByteSource that wraps another ByteSource, limiting the
|
||||
// number of bytes returned.
|
||||
//
|
||||
// The caller maintains ownership of the underlying source, and may not use the
|
||||
// underlying source while using the LimitByteSource object. The underlying
|
||||
// source's pointer is advanced by n bytes every time this LimitByteSource
|
||||
// object is advanced by n.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// string data = "Hello World";
|
||||
// ArrayByteSource abs(data);
|
||||
// assert(abs.Available() == data.size());
|
||||
//
|
||||
// LimitByteSource limit(abs, 5);
|
||||
// assert(limit.Available() == 5);
|
||||
// assert(limit.Peek() == "Hello");
|
||||
//
|
||||
class PROTOBUF_EXPORT LimitByteSource : public ByteSource {
|
||||
public:
|
||||
// Returns at most "limit" bytes from "source".
|
||||
LimitByteSource(ByteSource* source, size_t limit);
|
||||
|
||||
virtual size_t Available() const override;
|
||||
virtual StringPiece Peek() override;
|
||||
virtual void Skip(size_t n) override;
|
||||
|
||||
// We override CopyTo so that we can forward to the underlying source, in
|
||||
// case it has an efficient implementation of CopyTo.
|
||||
virtual void CopyTo(ByteSink* sink, size_t n) override;
|
||||
|
||||
private:
|
||||
ByteSource* source_;
|
||||
size_t limit_;
|
||||
};
|
||||
|
||||
} // namespace strings
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_BYTESTREAM_H_
|
||||
146
ubuntu/google/protobuf/stubs/bytestream_unittest.cc
Normal file
146
ubuntu/google/protobuf/stubs/bytestream_unittest.cc
Normal file
@@ -0,0 +1,146 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <google/protobuf/stubs/bytestream.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace strings {
|
||||
namespace {
|
||||
|
||||
// We use this class instead of ArrayByteSource to simulate a ByteSource that
|
||||
// contains multiple fragments. ArrayByteSource returns the entire array in
|
||||
// one fragment.
|
||||
class MockByteSource : public ByteSource {
|
||||
public:
|
||||
MockByteSource(StringPiece data, int block_size)
|
||||
: data_(data), block_size_(block_size) {}
|
||||
|
||||
size_t Available() const { return data_.size(); }
|
||||
StringPiece Peek() {
|
||||
return data_.substr(0, block_size_);
|
||||
}
|
||||
void Skip(size_t n) { data_.remove_prefix(n); }
|
||||
|
||||
private:
|
||||
StringPiece data_;
|
||||
int block_size_;
|
||||
};
|
||||
|
||||
TEST(ByteSourceTest, CopyTo) {
|
||||
StringPiece data("Hello world!");
|
||||
MockByteSource source(data, 3);
|
||||
std::string str;
|
||||
StringByteSink sink(&str);
|
||||
|
||||
source.CopyTo(&sink, data.size());
|
||||
EXPECT_EQ(data, str);
|
||||
}
|
||||
|
||||
TEST(ByteSourceTest, CopySubstringTo) {
|
||||
StringPiece data("Hello world!");
|
||||
MockByteSource source(data, 3);
|
||||
source.Skip(1);
|
||||
std::string str;
|
||||
StringByteSink sink(&str);
|
||||
|
||||
source.CopyTo(&sink, data.size() - 2);
|
||||
EXPECT_EQ(data.substr(1, data.size() - 2), str);
|
||||
EXPECT_EQ("!", source.Peek());
|
||||
}
|
||||
|
||||
TEST(ByteSourceTest, LimitByteSource) {
|
||||
StringPiece data("Hello world!");
|
||||
MockByteSource source(data, 3);
|
||||
LimitByteSource limit_source(&source, 6);
|
||||
EXPECT_EQ(6, limit_source.Available());
|
||||
limit_source.Skip(1);
|
||||
EXPECT_EQ(5, limit_source.Available());
|
||||
|
||||
{
|
||||
std::string str;
|
||||
StringByteSink sink(&str);
|
||||
limit_source.CopyTo(&sink, limit_source.Available());
|
||||
EXPECT_EQ("ello ", str);
|
||||
EXPECT_EQ(0, limit_source.Available());
|
||||
EXPECT_EQ(6, source.Available());
|
||||
}
|
||||
|
||||
{
|
||||
std::string str;
|
||||
StringByteSink sink(&str);
|
||||
source.CopyTo(&sink, source.Available());
|
||||
EXPECT_EQ("world!", str);
|
||||
EXPECT_EQ(0, source.Available());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ByteSourceTest, CopyToStringByteSink) {
|
||||
StringPiece data("Hello world!");
|
||||
MockByteSource source(data, 3);
|
||||
std::string str;
|
||||
StringByteSink sink(&str);
|
||||
source.CopyTo(&sink, data.size());
|
||||
EXPECT_EQ(data, str);
|
||||
}
|
||||
|
||||
// Verify that ByteSink is subclassable and Flush() overridable.
|
||||
class FlushingByteSink : public StringByteSink {
|
||||
public:
|
||||
explicit FlushingByteSink(std::string* dest) : StringByteSink(dest) {}
|
||||
virtual void Flush() { Append("z", 1); }
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FlushingByteSink);
|
||||
};
|
||||
|
||||
// Write and Flush via the ByteSink superclass interface.
|
||||
void WriteAndFlush(ByteSink* s) {
|
||||
s->Append("abc", 3);
|
||||
s->Flush();
|
||||
}
|
||||
|
||||
TEST(ByteSinkTest, Flush) {
|
||||
std::string str;
|
||||
FlushingByteSink f_sink(&str);
|
||||
WriteAndFlush(&f_sink);
|
||||
EXPECT_STREQ("abcz", str.c_str());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace strings
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
583
ubuntu/google/protobuf/stubs/callback.h
Normal file
583
ubuntu/google/protobuf/stubs/callback.h
Normal file
@@ -0,0 +1,583 @@
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <google/protobuf/stubs/macros.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
// ===================================================================
|
||||
// emulates google3/base/callback.h
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Abstract interface for a callback. When calling an RPC, you must provide
|
||||
// a Closure to call when the procedure completes. See the Service interface
|
||||
// in service.h.
|
||||
//
|
||||
// To automatically construct a Closure which calls a particular function or
|
||||
// method with a particular set of parameters, use the NewCallback() function.
|
||||
// Example:
|
||||
// void FooDone(const FooResponse* response) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// void CallFoo() {
|
||||
// ...
|
||||
// // When done, call FooDone() and pass it a pointer to the response.
|
||||
// Closure* callback = NewCallback(&FooDone, response);
|
||||
// // Make the call.
|
||||
// service->Foo(controller, request, response, callback);
|
||||
// }
|
||||
//
|
||||
// Example that calls a method:
|
||||
// class Handler {
|
||||
// public:
|
||||
// ...
|
||||
//
|
||||
// void FooDone(const FooResponse* response) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// void CallFoo() {
|
||||
// ...
|
||||
// // When done, call FooDone() and pass it a pointer to the response.
|
||||
// Closure* callback = NewCallback(this, &Handler::FooDone, response);
|
||||
// // Make the call.
|
||||
// service->Foo(controller, request, response, callback);
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// Currently NewCallback() supports binding zero, one, or two arguments.
|
||||
//
|
||||
// Callbacks created with NewCallback() automatically delete themselves when
|
||||
// executed. They should be used when a callback is to be called exactly
|
||||
// once (usually the case with RPC callbacks). If a callback may be called
|
||||
// a different number of times (including zero), create it with
|
||||
// NewPermanentCallback() instead. You are then responsible for deleting the
|
||||
// callback (using the "delete" keyword as normal).
|
||||
//
|
||||
// Note that NewCallback() is a bit touchy regarding argument types. Generally,
|
||||
// the values you provide for the parameter bindings must exactly match the
|
||||
// types accepted by the callback function. For example:
|
||||
// void Foo(std::string s);
|
||||
// NewCallback(&Foo, "foo"); // WON'T WORK: const char* != string
|
||||
// NewCallback(&Foo, std::string("foo")); // WORKS
|
||||
// Also note that the arguments cannot be references:
|
||||
// void Foo(const std::string& s);
|
||||
// std::string my_str;
|
||||
// NewCallback(&Foo, my_str); // WON'T WORK: Can't use references.
|
||||
// However, correctly-typed pointers will work just fine.
|
||||
class PROTOBUF_EXPORT Closure {
|
||||
public:
|
||||
Closure() {}
|
||||
virtual ~Closure();
|
||||
|
||||
virtual void Run() = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure);
|
||||
};
|
||||
|
||||
template<typename R>
|
||||
class ResultCallback {
|
||||
public:
|
||||
ResultCallback() {}
|
||||
virtual ~ResultCallback() {}
|
||||
|
||||
virtual R Run() = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback);
|
||||
};
|
||||
|
||||
template <typename R, typename A1>
|
||||
class PROTOBUF_EXPORT ResultCallback1 {
|
||||
public:
|
||||
ResultCallback1() {}
|
||||
virtual ~ResultCallback1() {}
|
||||
|
||||
virtual R Run(A1) = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback1);
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2>
|
||||
class PROTOBUF_EXPORT ResultCallback2 {
|
||||
public:
|
||||
ResultCallback2() {}
|
||||
virtual ~ResultCallback2() {}
|
||||
|
||||
virtual R Run(A1,A2) = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback2);
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
class PROTOBUF_EXPORT FunctionClosure0 : public Closure {
|
||||
public:
|
||||
typedef void (*FunctionType)();
|
||||
|
||||
FunctionClosure0(FunctionType function, bool self_deleting)
|
||||
: function_(function), self_deleting_(self_deleting) {}
|
||||
~FunctionClosure0();
|
||||
|
||||
void Run() override {
|
||||
bool needs_delete = self_deleting_; // read in case callback deletes
|
||||
function_();
|
||||
if (needs_delete) delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
FunctionType function_;
|
||||
bool self_deleting_;
|
||||
};
|
||||
|
||||
template <typename Class>
|
||||
class MethodClosure0 : public Closure {
|
||||
public:
|
||||
typedef void (Class::*MethodType)();
|
||||
|
||||
MethodClosure0(Class* object, MethodType method, bool self_deleting)
|
||||
: object_(object), method_(method), self_deleting_(self_deleting) {}
|
||||
~MethodClosure0() {}
|
||||
|
||||
void Run() override {
|
||||
bool needs_delete = self_deleting_; // read in case callback deletes
|
||||
(object_->*method_)();
|
||||
if (needs_delete) delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
Class* object_;
|
||||
MethodType method_;
|
||||
bool self_deleting_;
|
||||
};
|
||||
|
||||
template <typename Arg1>
|
||||
class FunctionClosure1 : public Closure {
|
||||
public:
|
||||
typedef void (*FunctionType)(Arg1 arg1);
|
||||
|
||||
FunctionClosure1(FunctionType function, bool self_deleting,
|
||||
Arg1 arg1)
|
||||
: function_(function), self_deleting_(self_deleting),
|
||||
arg1_(arg1) {}
|
||||
~FunctionClosure1() {}
|
||||
|
||||
void Run() override {
|
||||
bool needs_delete = self_deleting_; // read in case callback deletes
|
||||
function_(arg1_);
|
||||
if (needs_delete) delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
FunctionType function_;
|
||||
bool self_deleting_;
|
||||
Arg1 arg1_;
|
||||
};
|
||||
|
||||
template <typename Class, typename Arg1>
|
||||
class MethodClosure1 : public Closure {
|
||||
public:
|
||||
typedef void (Class::*MethodType)(Arg1 arg1);
|
||||
|
||||
MethodClosure1(Class* object, MethodType method, bool self_deleting,
|
||||
Arg1 arg1)
|
||||
: object_(object), method_(method), self_deleting_(self_deleting),
|
||||
arg1_(arg1) {}
|
||||
~MethodClosure1() {}
|
||||
|
||||
void Run() override {
|
||||
bool needs_delete = self_deleting_; // read in case callback deletes
|
||||
(object_->*method_)(arg1_);
|
||||
if (needs_delete) delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
Class* object_;
|
||||
MethodType method_;
|
||||
bool self_deleting_;
|
||||
Arg1 arg1_;
|
||||
};
|
||||
|
||||
template <typename Arg1, typename Arg2>
|
||||
class FunctionClosure2 : public Closure {
|
||||
public:
|
||||
typedef void (*FunctionType)(Arg1 arg1, Arg2 arg2);
|
||||
|
||||
FunctionClosure2(FunctionType function, bool self_deleting,
|
||||
Arg1 arg1, Arg2 arg2)
|
||||
: function_(function), self_deleting_(self_deleting),
|
||||
arg1_(arg1), arg2_(arg2) {}
|
||||
~FunctionClosure2() {}
|
||||
|
||||
void Run() override {
|
||||
bool needs_delete = self_deleting_; // read in case callback deletes
|
||||
function_(arg1_, arg2_);
|
||||
if (needs_delete) delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
FunctionType function_;
|
||||
bool self_deleting_;
|
||||
Arg1 arg1_;
|
||||
Arg2 arg2_;
|
||||
};
|
||||
|
||||
template <typename Class, typename Arg1, typename Arg2>
|
||||
class MethodClosure2 : public Closure {
|
||||
public:
|
||||
typedef void (Class::*MethodType)(Arg1 arg1, Arg2 arg2);
|
||||
|
||||
MethodClosure2(Class* object, MethodType method, bool self_deleting,
|
||||
Arg1 arg1, Arg2 arg2)
|
||||
: object_(object), method_(method), self_deleting_(self_deleting),
|
||||
arg1_(arg1), arg2_(arg2) {}
|
||||
~MethodClosure2() {}
|
||||
|
||||
void Run() override {
|
||||
bool needs_delete = self_deleting_; // read in case callback deletes
|
||||
(object_->*method_)(arg1_, arg2_);
|
||||
if (needs_delete) delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
Class* object_;
|
||||
MethodType method_;
|
||||
bool self_deleting_;
|
||||
Arg1 arg1_;
|
||||
Arg2 arg2_;
|
||||
};
|
||||
|
||||
template<typename R>
|
||||
class FunctionResultCallback_0_0 : public ResultCallback<R> {
|
||||
public:
|
||||
typedef R (*FunctionType)();
|
||||
|
||||
FunctionResultCallback_0_0(FunctionType function, bool self_deleting)
|
||||
: function_(function), self_deleting_(self_deleting) {}
|
||||
~FunctionResultCallback_0_0() {}
|
||||
|
||||
R Run() override {
|
||||
bool needs_delete = self_deleting_; // read in case callback deletes
|
||||
R result = function_();
|
||||
if (needs_delete) delete this;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
FunctionType function_;
|
||||
bool self_deleting_;
|
||||
};
|
||||
|
||||
template<typename R, typename P1>
|
||||
class FunctionResultCallback_1_0 : public ResultCallback<R> {
|
||||
public:
|
||||
typedef R (*FunctionType)(P1);
|
||||
|
||||
FunctionResultCallback_1_0(FunctionType function, bool self_deleting,
|
||||
P1 p1)
|
||||
: function_(function), self_deleting_(self_deleting), p1_(p1) {}
|
||||
~FunctionResultCallback_1_0() {}
|
||||
|
||||
R Run() override {
|
||||
bool needs_delete = self_deleting_; // read in case callback deletes
|
||||
R result = function_(p1_);
|
||||
if (needs_delete) delete this;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
FunctionType function_;
|
||||
bool self_deleting_;
|
||||
P1 p1_;
|
||||
};
|
||||
|
||||
template<typename R, typename Arg1>
|
||||
class FunctionResultCallback_0_1 : public ResultCallback1<R, Arg1> {
|
||||
public:
|
||||
typedef R (*FunctionType)(Arg1 arg1);
|
||||
|
||||
FunctionResultCallback_0_1(FunctionType function, bool self_deleting)
|
||||
: function_(function), self_deleting_(self_deleting) {}
|
||||
~FunctionResultCallback_0_1() {}
|
||||
|
||||
R Run(Arg1 a1) override {
|
||||
bool needs_delete = self_deleting_; // read in case callback deletes
|
||||
R result = function_(a1);
|
||||
if (needs_delete) delete this;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
FunctionType function_;
|
||||
bool self_deleting_;
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename A1>
|
||||
class FunctionResultCallback_1_1 : public ResultCallback1<R, A1> {
|
||||
public:
|
||||
typedef R (*FunctionType)(P1, A1);
|
||||
|
||||
FunctionResultCallback_1_1(FunctionType function, bool self_deleting,
|
||||
P1 p1)
|
||||
: function_(function), self_deleting_(self_deleting), p1_(p1) {}
|
||||
~FunctionResultCallback_1_1() {}
|
||||
|
||||
R Run(A1 a1) override {
|
||||
bool needs_delete = self_deleting_; // read in case callback deletes
|
||||
R result = function_(p1_, a1);
|
||||
if (needs_delete) delete this;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
FunctionType function_;
|
||||
bool self_deleting_;
|
||||
P1 p1_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct InternalConstRef {
|
||||
typedef typename std::remove_reference<T>::type base_type;
|
||||
typedef const base_type& type;
|
||||
};
|
||||
|
||||
template<typename R, typename T>
|
||||
class MethodResultCallback_0_0 : public ResultCallback<R> {
|
||||
public:
|
||||
typedef R (T::*MethodType)();
|
||||
MethodResultCallback_0_0(T* object, MethodType method, bool self_deleting)
|
||||
: object_(object),
|
||||
method_(method),
|
||||
self_deleting_(self_deleting) {}
|
||||
~MethodResultCallback_0_0() {}
|
||||
|
||||
R Run() {
|
||||
bool needs_delete = self_deleting_;
|
||||
R result = (object_->*method_)();
|
||||
if (needs_delete) delete this;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
T* object_;
|
||||
MethodType method_;
|
||||
bool self_deleting_;
|
||||
};
|
||||
|
||||
template <typename R, typename T, typename P1, typename P2, typename P3,
|
||||
typename P4, typename P5, typename P6, typename A1, typename A2>
|
||||
class MethodResultCallback_6_2 : public ResultCallback2<R, A1, A2> {
|
||||
public:
|
||||
typedef R (T::*MethodType)(P1, P2, P3, P4, P5, P6, A1, A2);
|
||||
MethodResultCallback_6_2(T* object, MethodType method, bool self_deleting,
|
||||
P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
|
||||
: object_(object),
|
||||
method_(method),
|
||||
self_deleting_(self_deleting),
|
||||
p1_(p1),
|
||||
p2_(p2),
|
||||
p3_(p3),
|
||||
p4_(p4),
|
||||
p5_(p5),
|
||||
p6_(p6) {}
|
||||
~MethodResultCallback_6_2() {}
|
||||
|
||||
R Run(A1 a1, A2 a2) override {
|
||||
bool needs_delete = self_deleting_;
|
||||
R result = (object_->*method_)(p1_, p2_, p3_, p4_, p5_, p6_, a1, a2);
|
||||
if (needs_delete) delete this;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
T* object_;
|
||||
MethodType method_;
|
||||
bool self_deleting_;
|
||||
typename std::remove_reference<P1>::type p1_;
|
||||
typename std::remove_reference<P2>::type p2_;
|
||||
typename std::remove_reference<P3>::type p3_;
|
||||
typename std::remove_reference<P4>::type p4_;
|
||||
typename std::remove_reference<P5>::type p5_;
|
||||
typename std::remove_reference<P6>::type p6_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// See Closure.
|
||||
inline Closure* NewCallback(void (*function)()) {
|
||||
return new internal::FunctionClosure0(function, true);
|
||||
}
|
||||
|
||||
// See Closure.
|
||||
inline Closure* NewPermanentCallback(void (*function)()) {
|
||||
return new internal::FunctionClosure0(function, false);
|
||||
}
|
||||
|
||||
// See Closure.
|
||||
template <typename Class>
|
||||
inline Closure* NewCallback(Class* object, void (Class::*method)()) {
|
||||
return new internal::MethodClosure0<Class>(object, method, true);
|
||||
}
|
||||
|
||||
// See Closure.
|
||||
template <typename Class>
|
||||
inline Closure* NewPermanentCallback(Class* object, void (Class::*method)()) {
|
||||
return new internal::MethodClosure0<Class>(object, method, false);
|
||||
}
|
||||
|
||||
// See Closure.
|
||||
template <typename Arg1>
|
||||
inline Closure* NewCallback(void (*function)(Arg1),
|
||||
Arg1 arg1) {
|
||||
return new internal::FunctionClosure1<Arg1>(function, true, arg1);
|
||||
}
|
||||
|
||||
// See Closure.
|
||||
template <typename Arg1>
|
||||
inline Closure* NewPermanentCallback(void (*function)(Arg1),
|
||||
Arg1 arg1) {
|
||||
return new internal::FunctionClosure1<Arg1>(function, false, arg1);
|
||||
}
|
||||
|
||||
// See Closure.
|
||||
template <typename Class, typename Arg1>
|
||||
inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1),
|
||||
Arg1 arg1) {
|
||||
return new internal::MethodClosure1<Class, Arg1>(object, method, true, arg1);
|
||||
}
|
||||
|
||||
// See Closure.
|
||||
template <typename Class, typename Arg1>
|
||||
inline Closure* NewPermanentCallback(Class* object, void (Class::*method)(Arg1),
|
||||
Arg1 arg1) {
|
||||
return new internal::MethodClosure1<Class, Arg1>(object, method, false, arg1);
|
||||
}
|
||||
|
||||
// See Closure.
|
||||
template <typename Arg1, typename Arg2>
|
||||
inline Closure* NewCallback(void (*function)(Arg1, Arg2),
|
||||
Arg1 arg1, Arg2 arg2) {
|
||||
return new internal::FunctionClosure2<Arg1, Arg2>(
|
||||
function, true, arg1, arg2);
|
||||
}
|
||||
|
||||
// See Closure.
|
||||
template <typename Arg1, typename Arg2>
|
||||
inline Closure* NewPermanentCallback(void (*function)(Arg1, Arg2),
|
||||
Arg1 arg1, Arg2 arg2) {
|
||||
return new internal::FunctionClosure2<Arg1, Arg2>(
|
||||
function, false, arg1, arg2);
|
||||
}
|
||||
|
||||
// See Closure.
|
||||
template <typename Class, typename Arg1, typename Arg2>
|
||||
inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1, Arg2),
|
||||
Arg1 arg1, Arg2 arg2) {
|
||||
return new internal::MethodClosure2<Class, Arg1, Arg2>(
|
||||
object, method, true, arg1, arg2);
|
||||
}
|
||||
|
||||
// See Closure.
|
||||
template <typename Class, typename Arg1, typename Arg2>
|
||||
inline Closure* NewPermanentCallback(
|
||||
Class* object, void (Class::*method)(Arg1, Arg2),
|
||||
Arg1 arg1, Arg2 arg2) {
|
||||
return new internal::MethodClosure2<Class, Arg1, Arg2>(
|
||||
object, method, false, arg1, arg2);
|
||||
}
|
||||
|
||||
// See ResultCallback
|
||||
template<typename R>
|
||||
inline ResultCallback<R>* NewCallback(R (*function)()) {
|
||||
return new internal::FunctionResultCallback_0_0<R>(function, true);
|
||||
}
|
||||
|
||||
// See ResultCallback
|
||||
template<typename R>
|
||||
inline ResultCallback<R>* NewPermanentCallback(R (*function)()) {
|
||||
return new internal::FunctionResultCallback_0_0<R>(function, false);
|
||||
}
|
||||
|
||||
// See ResultCallback
|
||||
template<typename R, typename P1>
|
||||
inline ResultCallback<R>* NewCallback(R (*function)(P1), P1 p1) {
|
||||
return new internal::FunctionResultCallback_1_0<R, P1>(
|
||||
function, true, p1);
|
||||
}
|
||||
|
||||
// See ResultCallback
|
||||
template<typename R, typename P1>
|
||||
inline ResultCallback<R>* NewPermanentCallback(
|
||||
R (*function)(P1), P1 p1) {
|
||||
return new internal::FunctionResultCallback_1_0<R, P1>(
|
||||
function, false, p1);
|
||||
}
|
||||
|
||||
// See ResultCallback1
|
||||
template<typename R, typename A1>
|
||||
inline ResultCallback1<R, A1>* NewCallback(R (*function)(A1)) {
|
||||
return new internal::FunctionResultCallback_0_1<R, A1>(function, true);
|
||||
}
|
||||
|
||||
// See ResultCallback1
|
||||
template<typename R, typename A1>
|
||||
inline ResultCallback1<R, A1>* NewPermanentCallback(R (*function)(A1)) {
|
||||
return new internal::FunctionResultCallback_0_1<R, A1>(function, false);
|
||||
}
|
||||
|
||||
// See ResultCallback1
|
||||
template<typename R, typename P1, typename A1>
|
||||
inline ResultCallback1<R, A1>* NewCallback(R (*function)(P1, A1), P1 p1) {
|
||||
return new internal::FunctionResultCallback_1_1<R, P1, A1>(
|
||||
function, true, p1);
|
||||
}
|
||||
|
||||
// See ResultCallback1
|
||||
template<typename R, typename P1, typename A1>
|
||||
inline ResultCallback1<R, A1>* NewPermanentCallback(
|
||||
R (*function)(P1, A1), P1 p1) {
|
||||
return new internal::FunctionResultCallback_1_1<R, P1, A1>(
|
||||
function, false, p1);
|
||||
}
|
||||
|
||||
// See MethodResultCallback_0_0
|
||||
template <typename R, typename T1, typename T2>
|
||||
inline ResultCallback<R>* NewPermanentCallback(
|
||||
T1* object, R (T2::*function)()) {
|
||||
return new internal::MethodResultCallback_0_0<R, T1>(object, function, false);
|
||||
}
|
||||
|
||||
// See MethodResultCallback_6_2
|
||||
template <typename R, typename T, typename P1, typename P2, typename P3,
|
||||
typename P4, typename P5, typename P6, typename A1, typename A2>
|
||||
inline ResultCallback2<R, A1, A2>* NewPermanentCallback(
|
||||
T* object, R (T::*function)(P1, P2, P3, P4, P5, P6, A1, A2),
|
||||
typename internal::InternalConstRef<P1>::type p1,
|
||||
typename internal::InternalConstRef<P2>::type p2,
|
||||
typename internal::InternalConstRef<P3>::type p3,
|
||||
typename internal::InternalConstRef<P4>::type p4,
|
||||
typename internal::InternalConstRef<P5>::type p5,
|
||||
typename internal::InternalConstRef<P6>::type p6) {
|
||||
return new internal::MethodResultCallback_6_2<R, T, P1, P2, P3, P4, P5, P6,
|
||||
A1, A2>(object, function, false,
|
||||
p1, p2, p3, p4, p5, p6);
|
||||
}
|
||||
|
||||
// A function which does nothing. Useful for creating no-op callbacks, e.g.:
|
||||
// Closure* nothing = NewCallback(&DoNothing);
|
||||
void PROTOBUF_EXPORT DoNothing();
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_CALLBACK_H_
|
||||
139
ubuntu/google/protobuf/stubs/casts.h
Normal file
139
ubuntu/google/protobuf/stubs/casts.h
Normal file
@@ -0,0 +1,139 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_CASTS_H__
|
||||
#define GOOGLE_PROTOBUF_CASTS_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
#include <type_traits>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Use implicit_cast as a safe version of static_cast or const_cast
|
||||
// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
|
||||
// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
|
||||
// a const pointer to Foo).
|
||||
// When you use implicit_cast, the compiler checks that the cast is safe.
|
||||
// Such explicit implicit_casts are necessary in surprisingly many
|
||||
// situations where C++ demands an exact type match instead of an
|
||||
// argument type convertible to a target type.
|
||||
//
|
||||
// The From type can be inferred, so the preferred syntax for using
|
||||
// implicit_cast is the same as for static_cast etc.:
|
||||
//
|
||||
// implicit_cast<ToType>(expr)
|
||||
//
|
||||
// implicit_cast would have been part of the C++ standard library,
|
||||
// but the proposal was submitted too late. It will probably make
|
||||
// its way into the language in the future.
|
||||
template<typename To, typename From>
|
||||
inline To implicit_cast(From const &f) {
|
||||
return f;
|
||||
}
|
||||
|
||||
// When you upcast (that is, cast a pointer from type Foo to type
|
||||
// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
|
||||
// always succeed. When you downcast (that is, cast a pointer from
|
||||
// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
|
||||
// how do you know the pointer is really of type SubclassOfFoo? It
|
||||
// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus,
|
||||
// when you downcast, you should use this macro. In debug mode, we
|
||||
// use dynamic_cast<> to double-check the downcast is legal (we die
|
||||
// if it's not). In normal mode, we do the efficient static_cast<>
|
||||
// instead. Thus, it's important to test in debug mode to make sure
|
||||
// the cast is legal!
|
||||
// This is the only place in the code we should use dynamic_cast<>.
|
||||
// In particular, you SHOULDN'T be using dynamic_cast<> in order to
|
||||
// do RTTI (eg code like this:
|
||||
// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
|
||||
// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
|
||||
// You should design the code some other way not to need this.
|
||||
|
||||
template<typename To, typename From> // use like this: down_cast<T*>(foo);
|
||||
inline To down_cast(From* f) { // so we only accept pointers
|
||||
// Ensures that To is a sub-type of From *. This test is here only
|
||||
// for compile-time type checking, and has no overhead in an
|
||||
// optimized build at run-time, as it will be optimized away
|
||||
// completely.
|
||||
if (false) {
|
||||
implicit_cast<From*, To>(0);
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) && PROTOBUF_RTTI
|
||||
assert(f == nullptr || dynamic_cast<To>(f) != nullptr); // RTTI: debug mode only!
|
||||
#endif
|
||||
return static_cast<To>(f);
|
||||
}
|
||||
|
||||
template<typename To, typename From> // use like this: down_cast<T&>(foo);
|
||||
inline To down_cast(From& f) {
|
||||
typedef typename std::remove_reference<To>::type* ToAsPointer;
|
||||
// Ensures that To is a sub-type of From *. This test is here only
|
||||
// for compile-time type checking, and has no overhead in an
|
||||
// optimized build at run-time, as it will be optimized away
|
||||
// completely.
|
||||
if (false) {
|
||||
implicit_cast<From*, ToAsPointer>(0);
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) && PROTOBUF_RTTI
|
||||
// RTTI: debug mode only!
|
||||
assert(dynamic_cast<ToAsPointer>(&f) != nullptr);
|
||||
#endif
|
||||
return *static_cast<ToAsPointer>(&f);
|
||||
}
|
||||
|
||||
template<typename To, typename From>
|
||||
inline To bit_cast(const From& from) {
|
||||
GOOGLE_COMPILE_ASSERT(sizeof(From) == sizeof(To),
|
||||
bit_cast_with_different_sizes);
|
||||
To dest;
|
||||
memcpy(&dest, &from, sizeof(dest));
|
||||
return dest;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// We made these internal so that they would show up as such in the docs,
|
||||
// but we don't want to stick "internal::" in front of them everywhere.
|
||||
using internal::implicit_cast;
|
||||
using internal::down_cast;
|
||||
using internal::bit_cast;
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_CASTS_H__
|
||||
329
ubuntu/google/protobuf/stubs/common.cc
Normal file
329
ubuntu/google/protobuf/stubs/common.cc
Normal file
@@ -0,0 +1,329 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <errno.h>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN // We only need minimal includes
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#define snprintf _snprintf // see comment in strutil.cc
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#error "No suitable threading library available."
|
||||
#endif
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/stubs/callback.h>
|
||||
#include <google/protobuf/stubs/logging.h>
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
#include <google/protobuf/stubs/status.h>
|
||||
#include <google/protobuf/stubs/stringpiece.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/int128.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace internal {
|
||||
|
||||
void VerifyVersion(int headerVersion,
|
||||
int minLibraryVersion,
|
||||
const char* filename) {
|
||||
if (GOOGLE_PROTOBUF_VERSION < minLibraryVersion) {
|
||||
// Library is too old for headers.
|
||||
GOOGLE_LOG(FATAL)
|
||||
<< "This program requires version " << VersionString(minLibraryVersion)
|
||||
<< " of the Protocol Buffer runtime library, but the installed version "
|
||||
"is " << VersionString(GOOGLE_PROTOBUF_VERSION) << ". Please update "
|
||||
"your library. If you compiled the program yourself, make sure that "
|
||||
"your headers are from the same version of Protocol Buffers as your "
|
||||
"link-time library. (Version verification failed in \""
|
||||
<< filename << "\".)";
|
||||
}
|
||||
if (headerVersion < kMinHeaderVersionForLibrary) {
|
||||
// Headers are too old for library.
|
||||
GOOGLE_LOG(FATAL)
|
||||
<< "This program was compiled against version "
|
||||
<< VersionString(headerVersion) << " of the Protocol Buffer runtime "
|
||||
"library, which is not compatible with the installed version ("
|
||||
<< VersionString(GOOGLE_PROTOBUF_VERSION) << "). Contact the program "
|
||||
"author for an update. If you compiled the program yourself, make "
|
||||
"sure that your headers are from the same version of Protocol Buffers "
|
||||
"as your link-time library. (Version verification failed in \""
|
||||
<< filename << "\".)";
|
||||
}
|
||||
}
|
||||
|
||||
std::string VersionString(int version) {
|
||||
int major = version / 1000000;
|
||||
int minor = (version / 1000) % 1000;
|
||||
int micro = version % 1000;
|
||||
|
||||
// 128 bytes should always be enough, but we use snprintf() anyway to be
|
||||
// safe.
|
||||
char buffer[128];
|
||||
snprintf(buffer, sizeof(buffer), "%d.%d.%d", major, minor, micro);
|
||||
|
||||
// Guard against broken MSVC snprintf().
|
||||
buffer[sizeof(buffer)-1] = '\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// ===================================================================
|
||||
// emulates google3/base/logging.cc
|
||||
|
||||
// If the minimum logging level is not set, we default to logging messages for
|
||||
// all levels.
|
||||
#ifndef GOOGLE_PROTOBUF_MIN_LOG_LEVEL
|
||||
#define GOOGLE_PROTOBUF_MIN_LOG_LEVEL LOGLEVEL_INFO
|
||||
#endif
|
||||
|
||||
namespace internal {
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
inline void DefaultLogHandler(LogLevel level, const char* filename, int line,
|
||||
const std::string& message) {
|
||||
if (level < GOOGLE_PROTOBUF_MIN_LOG_LEVEL) {
|
||||
return;
|
||||
}
|
||||
static const char* level_names[] = {"INFO", "WARNING", "ERROR", "FATAL"};
|
||||
|
||||
static const int android_log_levels[] = {
|
||||
ANDROID_LOG_INFO, // LOG(INFO),
|
||||
ANDROID_LOG_WARN, // LOG(WARNING)
|
||||
ANDROID_LOG_ERROR, // LOG(ERROR)
|
||||
ANDROID_LOG_FATAL, // LOG(FATAL)
|
||||
};
|
||||
|
||||
// Bound the logging level.
|
||||
const int android_log_level = android_log_levels[level];
|
||||
::std::ostringstream ostr;
|
||||
ostr << "[libprotobuf " << level_names[level] << " " << filename << ":"
|
||||
<< line << "] " << message.c_str();
|
||||
|
||||
// Output the log string the Android log at the appropriate level.
|
||||
__android_log_write(android_log_level, "libprotobuf-native",
|
||||
ostr.str().c_str());
|
||||
// Also output to std::cerr.
|
||||
fprintf(stderr, "%s", ostr.str().c_str());
|
||||
fflush(stderr);
|
||||
|
||||
// Indicate termination if needed.
|
||||
if (android_log_level == ANDROID_LOG_FATAL) {
|
||||
__android_log_write(ANDROID_LOG_FATAL, "libprotobuf-native",
|
||||
"terminating.\n");
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
void DefaultLogHandler(LogLevel level, const char* filename, int line,
|
||||
const std::string& message) {
|
||||
if (level < GOOGLE_PROTOBUF_MIN_LOG_LEVEL) {
|
||||
return;
|
||||
}
|
||||
static const char* level_names[] = { "INFO", "WARNING", "ERROR", "FATAL" };
|
||||
|
||||
// We use fprintf() instead of cerr because we want this to work at static
|
||||
// initialization time.
|
||||
fprintf(stderr, "[libprotobuf %s %s:%d] %s\n",
|
||||
level_names[level], filename, line, message.c_str());
|
||||
fflush(stderr); // Needed on MSVC.
|
||||
}
|
||||
#endif
|
||||
|
||||
void NullLogHandler(LogLevel /* level */, const char* /* filename */,
|
||||
int /* line */, const std::string& /* message */) {
|
||||
// Nothing.
|
||||
}
|
||||
|
||||
static LogHandler* log_handler_ = &DefaultLogHandler;
|
||||
static std::atomic<int> log_silencer_count_ = ATOMIC_VAR_INIT(0);
|
||||
|
||||
LogMessage& LogMessage::operator<<(const std::string& value) {
|
||||
message_ += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogMessage& LogMessage::operator<<(const char* value) {
|
||||
message_ += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogMessage& LogMessage::operator<<(const StringPiece& value) {
|
||||
message_ += value.ToString();
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogMessage& LogMessage::operator<<(const util::Status& status) {
|
||||
message_ += status.ToString();
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogMessage& LogMessage::operator<<(const uint128& value) {
|
||||
std::ostringstream str;
|
||||
str << value;
|
||||
message_ += str.str();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Since this is just for logging, we don't care if the current locale changes
|
||||
// the results -- in fact, we probably prefer that. So we use snprintf()
|
||||
// instead of Simple*toa().
|
||||
#undef DECLARE_STREAM_OPERATOR
|
||||
#define DECLARE_STREAM_OPERATOR(TYPE, FORMAT) \
|
||||
LogMessage& LogMessage::operator<<(TYPE value) { \
|
||||
/* 128 bytes should be big enough for any of the primitive */ \
|
||||
/* values which we print with this, but well use snprintf() */ \
|
||||
/* anyway to be extra safe. */ \
|
||||
char buffer[128]; \
|
||||
snprintf(buffer, sizeof(buffer), FORMAT, value); \
|
||||
/* Guard against broken MSVC snprintf(). */ \
|
||||
buffer[sizeof(buffer)-1] = '\0'; \
|
||||
message_ += buffer; \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
DECLARE_STREAM_OPERATOR(char , "%c" )
|
||||
DECLARE_STREAM_OPERATOR(int , "%d" )
|
||||
DECLARE_STREAM_OPERATOR(unsigned int , "%u" )
|
||||
DECLARE_STREAM_OPERATOR(long , "%ld")
|
||||
DECLARE_STREAM_OPERATOR(unsigned long, "%lu")
|
||||
DECLARE_STREAM_OPERATOR(double , "%g" )
|
||||
DECLARE_STREAM_OPERATOR(void* , "%p" )
|
||||
DECLARE_STREAM_OPERATOR(long long , "%" PROTOBUF_LL_FORMAT "d")
|
||||
DECLARE_STREAM_OPERATOR(unsigned long long, "%" PROTOBUF_LL_FORMAT "u")
|
||||
#undef DECLARE_STREAM_OPERATOR
|
||||
|
||||
LogMessage::LogMessage(LogLevel level, const char* filename, int line)
|
||||
: level_(level), filename_(filename), line_(line) {}
|
||||
LogMessage::~LogMessage() {}
|
||||
|
||||
void LogMessage::Finish() {
|
||||
bool suppress = false;
|
||||
|
||||
if (level_ != LOGLEVEL_FATAL) {
|
||||
suppress = log_silencer_count_ > 0;
|
||||
}
|
||||
|
||||
if (!suppress) {
|
||||
log_handler_(level_, filename_, line_, message_);
|
||||
}
|
||||
|
||||
if (level_ == LOGLEVEL_FATAL) {
|
||||
#if PROTOBUF_USE_EXCEPTIONS
|
||||
throw FatalException(filename_, line_, message_);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void LogFinisher::operator=(LogMessage& other) {
|
||||
other.Finish();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
LogHandler* SetLogHandler(LogHandler* new_func) {
|
||||
LogHandler* old = internal::log_handler_;
|
||||
if (old == &internal::NullLogHandler) {
|
||||
old = nullptr;
|
||||
}
|
||||
if (new_func == nullptr) {
|
||||
internal::log_handler_ = &internal::NullLogHandler;
|
||||
} else {
|
||||
internal::log_handler_ = new_func;
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
LogSilencer::LogSilencer() {
|
||||
++internal::log_silencer_count_;
|
||||
};
|
||||
|
||||
LogSilencer::~LogSilencer() {
|
||||
--internal::log_silencer_count_;
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
// emulates google3/base/callback.cc
|
||||
|
||||
Closure::~Closure() {}
|
||||
|
||||
namespace internal { FunctionClosure0::~FunctionClosure0() {} }
|
||||
|
||||
void DoNothing() {}
|
||||
|
||||
// ===================================================================
|
||||
// emulates google3/util/endian/endian.h
|
||||
//
|
||||
// TODO(xiaofeng): PROTOBUF_LITTLE_ENDIAN is unfortunately defined in
|
||||
// google/protobuf/io/coded_stream.h and therefore can not be used here.
|
||||
// Maybe move that macro definition here in the future.
|
||||
uint32 ghtonl(uint32 x) {
|
||||
union {
|
||||
uint32 result;
|
||||
uint8 result_array[4];
|
||||
};
|
||||
result_array[0] = static_cast<uint8>(x >> 24);
|
||||
result_array[1] = static_cast<uint8>((x >> 16) & 0xFF);
|
||||
result_array[2] = static_cast<uint8>((x >> 8) & 0xFF);
|
||||
result_array[3] = static_cast<uint8>(x & 0xFF);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if PROTOBUF_USE_EXCEPTIONS
|
||||
FatalException::~FatalException() throw() {}
|
||||
|
||||
const char* FatalException::what() const throw() {
|
||||
return message_.c_str();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
202
ubuntu/google/protobuf/stubs/common.h
Normal file
202
ubuntu/google/protobuf/stubs/common.h
Normal file
@@ -0,0 +1,202 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda) and others
|
||||
//
|
||||
// Contains basic types and utilities used by the rest of the library.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMMON_H__
|
||||
#define GOOGLE_PROTOBUF_COMMON_H__
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <google/protobuf/stubs/macros.h>
|
||||
#include <google/protobuf/stubs/platform_macros.h>
|
||||
#include <google/protobuf/stubs/port.h>
|
||||
#include <google/protobuf/stubs/stringpiece.h>
|
||||
|
||||
#ifndef PROTOBUF_USE_EXCEPTIONS
|
||||
#if defined(_MSC_VER) && defined(_CPPUNWIND)
|
||||
#define PROTOBUF_USE_EXCEPTIONS 1
|
||||
#elif defined(__EXCEPTIONS)
|
||||
#define PROTOBUF_USE_EXCEPTIONS 1
|
||||
#else
|
||||
#define PROTOBUF_USE_EXCEPTIONS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PROTOBUF_USE_EXCEPTIONS
|
||||
#include <exception>
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h> // for TARGET_OS_IPHONE
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__) || defined(GOOGLE_PROTOBUF_OS_ANDROID) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || defined(GOOGLE_PROTOBUF_OS_IPHONE)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
namespace std {}
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Some of these constants are macros rather than const ints so that they can
|
||||
// be used in #if directives.
|
||||
|
||||
// The current version, represented as a single integer to make comparison
|
||||
// easier: major * 10^6 + minor * 10^3 + micro
|
||||
#define GOOGLE_PROTOBUF_VERSION 3014000
|
||||
|
||||
// A suffix string for alpha, beta or rc releases. Empty for stable releases.
|
||||
#define GOOGLE_PROTOBUF_VERSION_SUFFIX ""
|
||||
|
||||
// The minimum header version which works with the current version of
|
||||
// the library. This constant should only be used by protoc's C++ code
|
||||
// generator.
|
||||
static const int kMinHeaderVersionForLibrary = 3014000;
|
||||
|
||||
// The minimum protoc version which works with the current version of the
|
||||
// headers.
|
||||
#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 3014000
|
||||
|
||||
// The minimum header version which works with the current version of
|
||||
// protoc. This constant should only be used in VerifyVersion().
|
||||
static const int kMinHeaderVersionForProtoc = 3014000;
|
||||
|
||||
// Verifies that the headers and libraries are compatible. Use the macro
|
||||
// below to call this.
|
||||
void PROTOBUF_EXPORT VerifyVersion(int headerVersion, int minLibraryVersion,
|
||||
const char* filename);
|
||||
|
||||
// Converts a numeric version number to a string.
|
||||
std::string PROTOBUF_EXPORT VersionString(int version);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Place this macro in your main() function (or somewhere before you attempt
|
||||
// to use the protobuf library) to verify that the version you link against
|
||||
// matches the headers you compiled against. If a version mismatch is
|
||||
// detected, the process will abort.
|
||||
#define GOOGLE_PROTOBUF_VERIFY_VERSION \
|
||||
::google::protobuf::internal::VerifyVersion( \
|
||||
GOOGLE_PROTOBUF_VERSION, GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION, \
|
||||
__FILE__)
|
||||
|
||||
|
||||
// ===================================================================
|
||||
// from google3/util/utf8/public/unilib.h
|
||||
|
||||
class StringPiece;
|
||||
namespace internal {
|
||||
|
||||
// Checks if the buffer contains structurally-valid UTF-8. Implemented in
|
||||
// structurally_valid.cc.
|
||||
PROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
|
||||
|
||||
inline bool IsStructurallyValidUTF8(StringPiece str) {
|
||||
return IsStructurallyValidUTF8(str.data(), static_cast<int>(str.length()));
|
||||
}
|
||||
|
||||
// Returns initial number of bytes of structurally valid UTF-8.
|
||||
PROTOBUF_EXPORT int UTF8SpnStructurallyValid(StringPiece str);
|
||||
|
||||
// Coerce UTF-8 byte string in src_str to be
|
||||
// a structurally-valid equal-length string by selectively
|
||||
// overwriting illegal bytes with replace_char (typically ' ' or '?').
|
||||
// replace_char must be legal printable 7-bit Ascii 0x20..0x7e.
|
||||
// src_str is read-only.
|
||||
//
|
||||
// Returns pointer to output buffer, src_str.data() if no changes were made,
|
||||
// or idst if some bytes were changed. idst is allocated by the caller
|
||||
// and must be at least as big as src_str
|
||||
//
|
||||
// Optimized for: all structurally valid and no byte copying is done.
|
||||
//
|
||||
PROTOBUF_EXPORT char* UTF8CoerceToStructurallyValid(StringPiece str, char* dst,
|
||||
char replace_char);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// This lives in message_lite.h now, but we leave this here for any users that
|
||||
// #include common.h and not message_lite.h.
|
||||
PROTOBUF_EXPORT void ShutdownProtobufLibrary();
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Strongly references the given variable such that the linker will be forced
|
||||
// to pull in this variable's translation unit.
|
||||
template <typename T>
|
||||
void StrongReference(const T& var) {
|
||||
auto volatile unused = &var;
|
||||
(void)&unused; // Use address to avoid an extra load of "unused".
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
#if PROTOBUF_USE_EXCEPTIONS
|
||||
class FatalException : public std::exception {
|
||||
public:
|
||||
FatalException(const char* filename, int line, const std::string& message)
|
||||
: filename_(filename), line_(line), message_(message) {}
|
||||
virtual ~FatalException() throw();
|
||||
|
||||
virtual const char* what() const throw();
|
||||
|
||||
const char* filename() const { return filename_; }
|
||||
int line() const { return line_; }
|
||||
const std::string& message() const { return message_; }
|
||||
|
||||
private:
|
||||
const char* filename_;
|
||||
const int line_;
|
||||
const std::string message_;
|
||||
};
|
||||
#endif
|
||||
|
||||
// This is at the end of the file instead of the beginning to work around a bug
|
||||
// in some versions of MSVC.
|
||||
using std::string;
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMMON_H__
|
||||
358
ubuntu/google/protobuf/stubs/common_unittest.cc
Normal file
358
ubuntu/google/protobuf/stubs/common_unittest.cc
Normal file
@@ -0,0 +1,358 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/callback.h>
|
||||
#include <google/protobuf/stubs/casts.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/logging.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
|
||||
// TODO(kenton): More tests.
|
||||
|
||||
#ifdef PACKAGE_VERSION // only defined when using automake, not MSVC
|
||||
|
||||
TEST(VersionTest, VersionMatchesConfig) {
|
||||
// Verify that the version string specified in config.h matches the one
|
||||
// in common.h. The config.h version is a string which may have a suffix
|
||||
// like "beta" or "rc1", so we remove that.
|
||||
std::string version = PACKAGE_VERSION;
|
||||
int pos = 0;
|
||||
while (pos < version.size() &&
|
||||
(ascii_isdigit(version[pos]) || version[pos] == '.')) {
|
||||
++pos;
|
||||
}
|
||||
version.erase(pos);
|
||||
|
||||
EXPECT_EQ(version, internal::VersionString(GOOGLE_PROTOBUF_VERSION));
|
||||
}
|
||||
|
||||
#endif // PACKAGE_VERSION
|
||||
|
||||
TEST(CommonTest, IntMinMaxConstants) {
|
||||
// kint32min was declared incorrectly in the first release of protobufs.
|
||||
// Ugh.
|
||||
EXPECT_LT(kint32min, kint32max);
|
||||
EXPECT_EQ(static_cast<uint32>(kint32min), static_cast<uint32>(kint32max) + 1);
|
||||
EXPECT_LT(kint64min, kint64max);
|
||||
EXPECT_EQ(static_cast<uint64>(kint64min), static_cast<uint64>(kint64max) + 1);
|
||||
EXPECT_EQ(0, kuint32max + 1);
|
||||
EXPECT_EQ(0, kuint64max + 1);
|
||||
}
|
||||
|
||||
std::vector<std::string> captured_messages_;
|
||||
|
||||
void CaptureLog(LogLevel level, const char* filename, int line,
|
||||
const std::string& message) {
|
||||
captured_messages_.push_back(
|
||||
strings::Substitute("$0 $1:$2: $3",
|
||||
implicit_cast<int>(level), filename, line, message));
|
||||
}
|
||||
|
||||
TEST(LoggingTest, DefaultLogging) {
|
||||
CaptureTestStderr();
|
||||
int line = __LINE__;
|
||||
GOOGLE_LOG(INFO ) << "A message.";
|
||||
GOOGLE_LOG(WARNING) << "A warning.";
|
||||
GOOGLE_LOG(ERROR ) << "An error.";
|
||||
|
||||
std::string text = GetCapturedTestStderr();
|
||||
EXPECT_EQ(
|
||||
"[libprotobuf INFO " __FILE__ ":" + SimpleItoa(line + 1) + "] A message.\n"
|
||||
"[libprotobuf WARNING " __FILE__ ":" + SimpleItoa(line + 2) + "] A warning.\n"
|
||||
"[libprotobuf ERROR " __FILE__ ":" + SimpleItoa(line + 3) + "] An error.\n",
|
||||
text);
|
||||
}
|
||||
|
||||
TEST(LoggingTest, NullLogging) {
|
||||
LogHandler* old_handler = SetLogHandler(nullptr);
|
||||
|
||||
CaptureTestStderr();
|
||||
GOOGLE_LOG(INFO ) << "A message.";
|
||||
GOOGLE_LOG(WARNING) << "A warning.";
|
||||
GOOGLE_LOG(ERROR ) << "An error.";
|
||||
|
||||
EXPECT_TRUE(SetLogHandler(old_handler) == nullptr);
|
||||
|
||||
std::string text = GetCapturedTestStderr();
|
||||
EXPECT_EQ("", text);
|
||||
}
|
||||
|
||||
TEST(LoggingTest, CaptureLogging) {
|
||||
captured_messages_.clear();
|
||||
|
||||
LogHandler* old_handler = SetLogHandler(&CaptureLog);
|
||||
|
||||
int start_line = __LINE__;
|
||||
GOOGLE_LOG(ERROR) << "An error.";
|
||||
GOOGLE_LOG(WARNING) << "A warning.";
|
||||
|
||||
EXPECT_TRUE(SetLogHandler(old_handler) == &CaptureLog);
|
||||
|
||||
ASSERT_EQ(2, captured_messages_.size());
|
||||
EXPECT_EQ(
|
||||
"2 " __FILE__ ":" + SimpleItoa(start_line + 1) + ": An error.",
|
||||
captured_messages_[0]);
|
||||
EXPECT_EQ(
|
||||
"1 " __FILE__ ":" + SimpleItoa(start_line + 2) + ": A warning.",
|
||||
captured_messages_[1]);
|
||||
}
|
||||
|
||||
TEST(LoggingTest, SilenceLogging) {
|
||||
captured_messages_.clear();
|
||||
|
||||
LogHandler* old_handler = SetLogHandler(&CaptureLog);
|
||||
|
||||
int line1 = __LINE__; GOOGLE_LOG(INFO) << "Visible1";
|
||||
LogSilencer* silencer1 = new LogSilencer;
|
||||
GOOGLE_LOG(INFO) << "Not visible.";
|
||||
LogSilencer* silencer2 = new LogSilencer;
|
||||
GOOGLE_LOG(INFO) << "Not visible.";
|
||||
delete silencer1;
|
||||
GOOGLE_LOG(INFO) << "Not visible.";
|
||||
delete silencer2;
|
||||
int line2 = __LINE__; GOOGLE_LOG(INFO) << "Visible2";
|
||||
|
||||
EXPECT_TRUE(SetLogHandler(old_handler) == &CaptureLog);
|
||||
|
||||
ASSERT_EQ(2, captured_messages_.size());
|
||||
EXPECT_EQ(
|
||||
"0 " __FILE__ ":" + SimpleItoa(line1) + ": Visible1",
|
||||
captured_messages_[0]);
|
||||
EXPECT_EQ(
|
||||
"0 " __FILE__ ":" + SimpleItoa(line2) + ": Visible2",
|
||||
captured_messages_[1]);
|
||||
}
|
||||
|
||||
class ClosureTest : public testing::Test {
|
||||
public:
|
||||
void SetA123Method() { a_ = 123; }
|
||||
static void SetA123Function() { current_instance_->a_ = 123; }
|
||||
|
||||
void SetAMethod(int a) { a_ = a; }
|
||||
void SetCMethod(std::string c) { c_ = c; }
|
||||
|
||||
static void SetAFunction(int a) { current_instance_->a_ = a; }
|
||||
static void SetCFunction(std::string c) { current_instance_->c_ = c; }
|
||||
|
||||
void SetABMethod(int a, const char* b) { a_ = a; b_ = b; }
|
||||
static void SetABFunction(int a, const char* b) {
|
||||
current_instance_->a_ = a;
|
||||
current_instance_->b_ = b;
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
current_instance_ = this;
|
||||
a_ = 0;
|
||||
b_ = nullptr;
|
||||
c_.clear();
|
||||
permanent_closure_ = nullptr;
|
||||
}
|
||||
|
||||
void DeleteClosureInCallback() {
|
||||
delete permanent_closure_;
|
||||
}
|
||||
|
||||
int a_;
|
||||
const char* b_;
|
||||
std::string c_;
|
||||
Closure* permanent_closure_;
|
||||
|
||||
static ClosureTest* current_instance_;
|
||||
};
|
||||
|
||||
ClosureTest* ClosureTest::current_instance_ = nullptr;
|
||||
|
||||
TEST_F(ClosureTest, TestClosureFunction0) {
|
||||
Closure* closure = NewCallback(&SetA123Function);
|
||||
EXPECT_NE(123, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(123, a_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureMethod0) {
|
||||
Closure* closure = NewCallback(current_instance_,
|
||||
&ClosureTest::SetA123Method);
|
||||
EXPECT_NE(123, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(123, a_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureFunction1) {
|
||||
Closure* closure = NewCallback(&SetAFunction, 456);
|
||||
EXPECT_NE(456, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(456, a_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureMethod1) {
|
||||
Closure* closure = NewCallback(current_instance_,
|
||||
&ClosureTest::SetAMethod, 456);
|
||||
EXPECT_NE(456, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(456, a_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureFunction1String) {
|
||||
Closure* closure = NewCallback(&SetCFunction, std::string("test"));
|
||||
EXPECT_NE("test", c_);
|
||||
closure->Run();
|
||||
EXPECT_EQ("test", c_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureMethod1String) {
|
||||
Closure* closure = NewCallback(current_instance_, &ClosureTest::SetCMethod,
|
||||
std::string("test"));
|
||||
EXPECT_NE("test", c_);
|
||||
closure->Run();
|
||||
EXPECT_EQ("test", c_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureFunction2) {
|
||||
const char* cstr = "hello";
|
||||
Closure* closure = NewCallback(&SetABFunction, 789, cstr);
|
||||
EXPECT_NE(789, a_);
|
||||
EXPECT_NE(cstr, b_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(789, a_);
|
||||
EXPECT_EQ(cstr, b_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureMethod2) {
|
||||
const char* cstr = "hello";
|
||||
Closure* closure = NewCallback(current_instance_,
|
||||
&ClosureTest::SetABMethod, 789, cstr);
|
||||
EXPECT_NE(789, a_);
|
||||
EXPECT_NE(cstr, b_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(789, a_);
|
||||
EXPECT_EQ(cstr, b_);
|
||||
}
|
||||
|
||||
// Repeat all of the above with NewPermanentCallback()
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureFunction0) {
|
||||
Closure* closure = NewPermanentCallback(&SetA123Function);
|
||||
EXPECT_NE(123, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(123, a_);
|
||||
a_ = 0;
|
||||
closure->Run();
|
||||
EXPECT_EQ(123, a_);
|
||||
delete closure;
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureMethod0) {
|
||||
Closure* closure = NewPermanentCallback(current_instance_,
|
||||
&ClosureTest::SetA123Method);
|
||||
EXPECT_NE(123, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(123, a_);
|
||||
a_ = 0;
|
||||
closure->Run();
|
||||
EXPECT_EQ(123, a_);
|
||||
delete closure;
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureFunction1) {
|
||||
Closure* closure = NewPermanentCallback(&SetAFunction, 456);
|
||||
EXPECT_NE(456, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(456, a_);
|
||||
a_ = 0;
|
||||
closure->Run();
|
||||
EXPECT_EQ(456, a_);
|
||||
delete closure;
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureMethod1) {
|
||||
Closure* closure = NewPermanentCallback(current_instance_,
|
||||
&ClosureTest::SetAMethod, 456);
|
||||
EXPECT_NE(456, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(456, a_);
|
||||
a_ = 0;
|
||||
closure->Run();
|
||||
EXPECT_EQ(456, a_);
|
||||
delete closure;
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureFunction2) {
|
||||
const char* cstr = "hello";
|
||||
Closure* closure = NewPermanentCallback(&SetABFunction, 789, cstr);
|
||||
EXPECT_NE(789, a_);
|
||||
EXPECT_NE(cstr, b_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(789, a_);
|
||||
EXPECT_EQ(cstr, b_);
|
||||
a_ = 0;
|
||||
b_ = nullptr;
|
||||
closure->Run();
|
||||
EXPECT_EQ(789, a_);
|
||||
EXPECT_EQ(cstr, b_);
|
||||
delete closure;
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureMethod2) {
|
||||
const char* cstr = "hello";
|
||||
Closure* closure = NewPermanentCallback(current_instance_,
|
||||
&ClosureTest::SetABMethod, 789, cstr);
|
||||
EXPECT_NE(789, a_);
|
||||
EXPECT_NE(cstr, b_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(789, a_);
|
||||
EXPECT_EQ(cstr, b_);
|
||||
a_ = 0;
|
||||
b_ = nullptr;
|
||||
closure->Run();
|
||||
EXPECT_EQ(789, a_);
|
||||
EXPECT_EQ(cstr, b_);
|
||||
delete closure;
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureDeleteInCallback) {
|
||||
permanent_closure_ = NewPermanentCallback((ClosureTest*) this,
|
||||
&ClosureTest::DeleteClosureInCallback);
|
||||
permanent_closure_->Run();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
114
ubuntu/google/protobuf/stubs/hash.h
Normal file
114
ubuntu/google/protobuf/stubs/hash.h
Normal file
@@ -0,0 +1,114 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_HASH_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_HASH_H__
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \
|
||||
namespace google { \
|
||||
namespace protobuf {
|
||||
# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END }}
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
template <typename Key>
|
||||
struct hash : public std::hash<Key> {};
|
||||
|
||||
template <typename Key>
|
||||
struct hash<const Key*> {
|
||||
inline size_t operator()(const Key* key) const {
|
||||
return reinterpret_cast<size_t>(key);
|
||||
}
|
||||
};
|
||||
|
||||
// Unlike the old SGI version, the TR1 "hash" does not special-case char*. So,
|
||||
// we go ahead and provide our own implementation.
|
||||
template <>
|
||||
struct hash<const char*> {
|
||||
inline size_t operator()(const char* str) const {
|
||||
size_t result = 0;
|
||||
for (; *str != '\0'; str++) {
|
||||
result = 5 * result + static_cast<size_t>(*str);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<bool> {
|
||||
size_t operator()(bool x) const {
|
||||
return static_cast<size_t>(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<std::string> {
|
||||
inline size_t operator()(const std::string& key) const {
|
||||
return hash<const char*>()(key.c_str());
|
||||
}
|
||||
|
||||
static const size_t bucket_size = 4;
|
||||
static const size_t min_buckets = 8;
|
||||
inline bool operator()(const std::string& a, const std::string& b) const {
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename First, typename Second>
|
||||
struct hash<std::pair<First, Second> > {
|
||||
inline size_t operator()(const std::pair<First, Second>& key) const {
|
||||
size_t first_hash = hash<First>()(key.first);
|
||||
size_t second_hash = hash<Second>()(key.second);
|
||||
|
||||
// FIXME(kenton): What is the best way to compute this hash? I have
|
||||
// no idea! This seems a bit better than an XOR.
|
||||
return first_hash * ((1 << 16) - 1) + second_hash;
|
||||
}
|
||||
|
||||
static const size_t bucket_size = 4;
|
||||
static const size_t min_buckets = 8;
|
||||
inline bool operator()(const std::pair<First, Second>& a,
|
||||
const std::pair<First, Second>& b) const {
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_HASH_H__
|
||||
192
ubuntu/google/protobuf/stubs/int128.cc
Normal file
192
ubuntu/google/protobuf/stubs/int128.cc
Normal file
@@ -0,0 +1,192 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <google/protobuf/stubs/int128.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <ostream> // NOLINT(readability/streams)
|
||||
#include <sstream>
|
||||
|
||||
#include <google/protobuf/stubs/logging.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
const uint128_pod kuint128max = {
|
||||
static_cast<uint64>(PROTOBUF_LONGLONG(0xFFFFFFFFFFFFFFFF)),
|
||||
static_cast<uint64>(PROTOBUF_LONGLONG(0xFFFFFFFFFFFFFFFF))
|
||||
};
|
||||
|
||||
// Returns the 0-based position of the last set bit (i.e., most significant bit)
|
||||
// in the given uint64. The argument may not be 0.
|
||||
//
|
||||
// For example:
|
||||
// Given: 5 (decimal) == 101 (binary)
|
||||
// Returns: 2
|
||||
#define STEP(T, n, pos, sh) \
|
||||
do { \
|
||||
if ((n) >= (static_cast<T>(1) << (sh))) { \
|
||||
(n) = (n) >> (sh); \
|
||||
(pos) |= (sh); \
|
||||
} \
|
||||
} while (0)
|
||||
static inline int Fls64(uint64 n) {
|
||||
GOOGLE_DCHECK_NE(0, n);
|
||||
int pos = 0;
|
||||
STEP(uint64, n, pos, 0x20);
|
||||
uint32 n32 = n;
|
||||
STEP(uint32, n32, pos, 0x10);
|
||||
STEP(uint32, n32, pos, 0x08);
|
||||
STEP(uint32, n32, pos, 0x04);
|
||||
return pos + ((PROTOBUF_ULONGLONG(0x3333333322221100) >> (n32 << 2)) & 0x3);
|
||||
}
|
||||
#undef STEP
|
||||
|
||||
// Like Fls64() above, but returns the 0-based position of the last set bit
|
||||
// (i.e., most significant bit) in the given uint128. The argument may not be 0.
|
||||
static inline int Fls128(uint128 n) {
|
||||
if (uint64 hi = Uint128High64(n)) {
|
||||
return Fls64(hi) + 64;
|
||||
}
|
||||
return Fls64(Uint128Low64(n));
|
||||
}
|
||||
|
||||
void uint128::DivModImpl(uint128 dividend, uint128 divisor,
|
||||
uint128* quotient_ret, uint128* remainder_ret) {
|
||||
if (divisor == 0) {
|
||||
GOOGLE_LOG(FATAL) << "Division or mod by zero: dividend.hi=" << dividend.hi_
|
||||
<< ", lo=" << dividend.lo_;
|
||||
} else if (dividend < divisor) {
|
||||
*quotient_ret = 0;
|
||||
*remainder_ret = dividend;
|
||||
return;
|
||||
} else {
|
||||
int dividend_bit_length = Fls128(dividend);
|
||||
int divisor_bit_length = Fls128(divisor);
|
||||
int difference = dividend_bit_length - divisor_bit_length;
|
||||
uint128 quotient = 0;
|
||||
while (difference >= 0) {
|
||||
quotient <<= 1;
|
||||
uint128 shifted_divisor = divisor << difference;
|
||||
if (shifted_divisor <= dividend) {
|
||||
dividend -= shifted_divisor;
|
||||
quotient += 1;
|
||||
}
|
||||
difference -= 1;
|
||||
}
|
||||
//record the final quotient and remainder
|
||||
*quotient_ret = quotient;
|
||||
*remainder_ret = dividend;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint128& uint128::operator/=(const uint128& divisor) {
|
||||
uint128 quotient = 0;
|
||||
uint128 remainder = 0;
|
||||
DivModImpl(*this, divisor, "ient, &remainder);
|
||||
*this = quotient;
|
||||
return *this;
|
||||
}
|
||||
uint128& uint128::operator%=(const uint128& divisor) {
|
||||
uint128 quotient = 0;
|
||||
uint128 remainder = 0;
|
||||
DivModImpl(*this, divisor, "ient, &remainder);
|
||||
*this = remainder;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const uint128& b) {
|
||||
std::ios_base::fmtflags flags = o.flags();
|
||||
|
||||
// Select a divisor which is the largest power of the base < 2^64.
|
||||
uint128 div;
|
||||
std::streamsize div_base_log;
|
||||
switch (flags & std::ios::basefield) {
|
||||
case std::ios::hex:
|
||||
div =
|
||||
static_cast<uint64>(PROTOBUF_ULONGLONG(0x1000000000000000)); // 16^15
|
||||
div_base_log = 15;
|
||||
break;
|
||||
case std::ios::oct:
|
||||
div = static_cast<uint64>(
|
||||
PROTOBUF_ULONGLONG(01000000000000000000000)); // 8^21
|
||||
div_base_log = 21;
|
||||
break;
|
||||
default: // std::ios::dec
|
||||
div = static_cast<uint64>(
|
||||
PROTOBUF_ULONGLONG(10000000000000000000)); // 10^19
|
||||
div_base_log = 19;
|
||||
break;
|
||||
}
|
||||
|
||||
// Now piece together the uint128 representation from three chunks of
|
||||
// the original value, each less than "div" and therefore representable
|
||||
// as a uint64.
|
||||
std::ostringstream os;
|
||||
std::ios_base::fmtflags copy_mask =
|
||||
std::ios::basefield | std::ios::showbase | std::ios::uppercase;
|
||||
os.setf(flags & copy_mask, copy_mask);
|
||||
uint128 high = b;
|
||||
uint128 low;
|
||||
uint128::DivModImpl(high, div, &high, &low);
|
||||
uint128 mid;
|
||||
uint128::DivModImpl(high, div, &high, &mid);
|
||||
if (high.lo_ != 0) {
|
||||
os << high.lo_;
|
||||
os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
|
||||
os << mid.lo_;
|
||||
os << std::setw(div_base_log);
|
||||
} else if (mid.lo_ != 0) {
|
||||
os << mid.lo_;
|
||||
os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
|
||||
}
|
||||
os << low.lo_;
|
||||
std::string rep = os.str();
|
||||
|
||||
// Add the requisite padding.
|
||||
std::streamsize width = o.width(0);
|
||||
if (width > rep.size()) {
|
||||
if ((flags & std::ios::adjustfield) == std::ios::left) {
|
||||
rep.append(width - rep.size(), o.fill());
|
||||
} else {
|
||||
rep.insert(static_cast<std::string::size_type>(0),
|
||||
width - rep.size(), o.fill());
|
||||
}
|
||||
}
|
||||
|
||||
// Stream the final representation in a single "<<" call.
|
||||
return o << rep;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
387
ubuntu/google/protobuf/stubs/int128.h
Normal file
387
ubuntu/google/protobuf/stubs/int128.h
Normal file
@@ -0,0 +1,387 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_INT128_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_INT128_H_
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
struct uint128_pod;
|
||||
|
||||
// TODO(xiaofeng): Define GOOGLE_PROTOBUF_HAS_CONSTEXPR when constexpr is
|
||||
// available.
|
||||
#ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR
|
||||
# define UINT128_CONSTEXPR constexpr
|
||||
#else
|
||||
# define UINT128_CONSTEXPR
|
||||
#endif
|
||||
|
||||
// An unsigned 128-bit integer type. Thread-compatible.
|
||||
class PROTOBUF_EXPORT uint128 {
|
||||
public:
|
||||
UINT128_CONSTEXPR uint128(); // Sets to 0, but don't trust on this behavior.
|
||||
UINT128_CONSTEXPR uint128(uint64 top, uint64 bottom);
|
||||
#ifndef SWIG
|
||||
UINT128_CONSTEXPR uint128(int bottom);
|
||||
UINT128_CONSTEXPR uint128(uint32 bottom); // Top 96 bits = 0
|
||||
#endif
|
||||
UINT128_CONSTEXPR uint128(uint64 bottom); // hi_ = 0
|
||||
UINT128_CONSTEXPR uint128(const uint128_pod &val);
|
||||
|
||||
// Trivial copy constructor, assignment operator and destructor.
|
||||
|
||||
void Initialize(uint64 top, uint64 bottom);
|
||||
|
||||
// Arithmetic operators.
|
||||
uint128& operator+=(const uint128& b);
|
||||
uint128& operator-=(const uint128& b);
|
||||
uint128& operator*=(const uint128& b);
|
||||
// Long division/modulo for uint128.
|
||||
uint128& operator/=(const uint128& b);
|
||||
uint128& operator%=(const uint128& b);
|
||||
uint128 operator++(int);
|
||||
uint128 operator--(int);
|
||||
uint128& operator<<=(int);
|
||||
uint128& operator>>=(int);
|
||||
uint128& operator&=(const uint128& b);
|
||||
uint128& operator|=(const uint128& b);
|
||||
uint128& operator^=(const uint128& b);
|
||||
uint128& operator++();
|
||||
uint128& operator--();
|
||||
|
||||
friend uint64 Uint128Low64(const uint128& v);
|
||||
friend uint64 Uint128High64(const uint128& v);
|
||||
|
||||
// We add "std::" to avoid including all of port.h.
|
||||
PROTOBUF_EXPORT friend std::ostream& operator<<(std::ostream& o,
|
||||
const uint128& b);
|
||||
|
||||
private:
|
||||
static void DivModImpl(uint128 dividend, uint128 divisor,
|
||||
uint128* quotient_ret, uint128* remainder_ret);
|
||||
|
||||
// Little-endian memory order optimizations can benefit from
|
||||
// having lo_ first, hi_ last.
|
||||
// See util/endian/endian.h and Load128/Store128 for storing a uint128.
|
||||
uint64 lo_;
|
||||
uint64 hi_;
|
||||
|
||||
// Not implemented, just declared for catching automatic type conversions.
|
||||
uint128(uint8);
|
||||
uint128(uint16);
|
||||
uint128(float v);
|
||||
uint128(double v);
|
||||
};
|
||||
|
||||
// This is a POD form of uint128 which can be used for static variables which
|
||||
// need to be operated on as uint128.
|
||||
struct uint128_pod {
|
||||
// Note: The ordering of fields is different than 'class uint128' but the
|
||||
// same as its 2-arg constructor. This enables more obvious initialization
|
||||
// of static instances, which is the primary reason for this struct in the
|
||||
// first place. This does not seem to defeat any optimizations wrt
|
||||
// operations involving this struct.
|
||||
uint64 hi;
|
||||
uint64 lo;
|
||||
};
|
||||
|
||||
PROTOBUF_EXPORT extern const uint128_pod kuint128max;
|
||||
|
||||
// allow uint128 to be logged
|
||||
PROTOBUF_EXPORT extern std::ostream& operator<<(std::ostream& o,
|
||||
const uint128& b);
|
||||
|
||||
// Methods to access low and high pieces of 128-bit value.
|
||||
// Defined externally from uint128 to facilitate conversion
|
||||
// to native 128-bit types when compilers support them.
|
||||
inline uint64 Uint128Low64(const uint128& v) { return v.lo_; }
|
||||
inline uint64 Uint128High64(const uint128& v) { return v.hi_; }
|
||||
|
||||
// TODO: perhaps it would be nice to have int128, a signed 128-bit type?
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Implementation details follow
|
||||
// --------------------------------------------------------------------------
|
||||
inline bool operator==(const uint128& lhs, const uint128& rhs) {
|
||||
return (Uint128Low64(lhs) == Uint128Low64(rhs) &&
|
||||
Uint128High64(lhs) == Uint128High64(rhs));
|
||||
}
|
||||
inline bool operator!=(const uint128& lhs, const uint128& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline UINT128_CONSTEXPR uint128::uint128() : lo_(0), hi_(0) {}
|
||||
inline UINT128_CONSTEXPR uint128::uint128(uint64 top, uint64 bottom)
|
||||
: lo_(bottom), hi_(top) {}
|
||||
inline UINT128_CONSTEXPR uint128::uint128(const uint128_pod& v)
|
||||
: lo_(v.lo), hi_(v.hi) {}
|
||||
inline UINT128_CONSTEXPR uint128::uint128(uint64 bottom)
|
||||
: lo_(bottom), hi_(0) {}
|
||||
#ifndef SWIG
|
||||
inline UINT128_CONSTEXPR uint128::uint128(uint32 bottom)
|
||||
: lo_(bottom), hi_(0) {}
|
||||
inline UINT128_CONSTEXPR uint128::uint128(int bottom)
|
||||
: lo_(bottom), hi_(static_cast<int64>((bottom < 0) ? -1 : 0)) {}
|
||||
#endif
|
||||
|
||||
#undef UINT128_CONSTEXPR
|
||||
|
||||
inline void uint128::Initialize(uint64 top, uint64 bottom) {
|
||||
hi_ = top;
|
||||
lo_ = bottom;
|
||||
}
|
||||
|
||||
// Comparison operators.
|
||||
|
||||
#define CMP128(op) \
|
||||
inline bool operator op(const uint128& lhs, const uint128& rhs) { \
|
||||
return (Uint128High64(lhs) == Uint128High64(rhs)) ? \
|
||||
(Uint128Low64(lhs) op Uint128Low64(rhs)) : \
|
||||
(Uint128High64(lhs) op Uint128High64(rhs)); \
|
||||
}
|
||||
|
||||
CMP128(<)
|
||||
CMP128(>)
|
||||
CMP128(>=)
|
||||
CMP128(<=)
|
||||
|
||||
#undef CMP128
|
||||
|
||||
// Unary operators
|
||||
|
||||
inline uint128 operator-(const uint128& val) {
|
||||
const uint64 hi_flip = ~Uint128High64(val);
|
||||
const uint64 lo_flip = ~Uint128Low64(val);
|
||||
const uint64 lo_add = lo_flip + 1;
|
||||
if (lo_add < lo_flip) {
|
||||
return uint128(hi_flip + 1, lo_add);
|
||||
}
|
||||
return uint128(hi_flip, lo_add);
|
||||
}
|
||||
|
||||
inline bool operator!(const uint128& val) {
|
||||
return !Uint128High64(val) && !Uint128Low64(val);
|
||||
}
|
||||
|
||||
// Logical operators.
|
||||
|
||||
inline uint128 operator~(const uint128& val) {
|
||||
return uint128(~Uint128High64(val), ~Uint128Low64(val));
|
||||
}
|
||||
|
||||
#define LOGIC128(op) \
|
||||
inline uint128 operator op(const uint128& lhs, const uint128& rhs) { \
|
||||
return uint128(Uint128High64(lhs) op Uint128High64(rhs), \
|
||||
Uint128Low64(lhs) op Uint128Low64(rhs)); \
|
||||
}
|
||||
|
||||
LOGIC128(|)
|
||||
LOGIC128(&)
|
||||
LOGIC128(^)
|
||||
|
||||
#undef LOGIC128
|
||||
|
||||
#define LOGICASSIGN128(op) \
|
||||
inline uint128& uint128::operator op(const uint128& other) { \
|
||||
hi_ op other.hi_; \
|
||||
lo_ op other.lo_; \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
LOGICASSIGN128(|=)
|
||||
LOGICASSIGN128(&=)
|
||||
LOGICASSIGN128(^=)
|
||||
|
||||
#undef LOGICASSIGN128
|
||||
|
||||
// Shift operators.
|
||||
|
||||
inline uint128 operator<<(const uint128& val, int amount) {
|
||||
// uint64 shifts of >= 64 are undefined, so we will need some special-casing.
|
||||
if (amount < 64) {
|
||||
if (amount == 0) {
|
||||
return val;
|
||||
}
|
||||
uint64 new_hi = (Uint128High64(val) << amount) |
|
||||
(Uint128Low64(val) >> (64 - amount));
|
||||
uint64 new_lo = Uint128Low64(val) << amount;
|
||||
return uint128(new_hi, new_lo);
|
||||
} else if (amount < 128) {
|
||||
return uint128(Uint128Low64(val) << (amount - 64), 0);
|
||||
} else {
|
||||
return uint128(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
inline uint128 operator>>(const uint128& val, int amount) {
|
||||
// uint64 shifts of >= 64 are undefined, so we will need some special-casing.
|
||||
if (amount < 64) {
|
||||
if (amount == 0) {
|
||||
return val;
|
||||
}
|
||||
uint64 new_hi = Uint128High64(val) >> amount;
|
||||
uint64 new_lo = (Uint128Low64(val) >> amount) |
|
||||
(Uint128High64(val) << (64 - amount));
|
||||
return uint128(new_hi, new_lo);
|
||||
} else if (amount < 128) {
|
||||
return uint128(0, Uint128High64(val) >> (amount - 64));
|
||||
} else {
|
||||
return uint128(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator<<=(int amount) {
|
||||
// uint64 shifts of >= 64 are undefined, so we will need some special-casing.
|
||||
if (amount < 64) {
|
||||
if (amount != 0) {
|
||||
hi_ = (hi_ << amount) | (lo_ >> (64 - amount));
|
||||
lo_ = lo_ << amount;
|
||||
}
|
||||
} else if (amount < 128) {
|
||||
hi_ = lo_ << (amount - 64);
|
||||
lo_ = 0;
|
||||
} else {
|
||||
hi_ = 0;
|
||||
lo_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator>>=(int amount) {
|
||||
// uint64 shifts of >= 64 are undefined, so we will need some special-casing.
|
||||
if (amount < 64) {
|
||||
if (amount != 0) {
|
||||
lo_ = (lo_ >> amount) | (hi_ << (64 - amount));
|
||||
hi_ = hi_ >> amount;
|
||||
}
|
||||
} else if (amount < 128) {
|
||||
lo_ = hi_ >> (amount - 64);
|
||||
hi_ = 0;
|
||||
} else {
|
||||
lo_ = 0;
|
||||
hi_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128 operator+(const uint128& lhs, const uint128& rhs) {
|
||||
return uint128(lhs) += rhs;
|
||||
}
|
||||
|
||||
inline uint128 operator-(const uint128& lhs, const uint128& rhs) {
|
||||
return uint128(lhs) -= rhs;
|
||||
}
|
||||
|
||||
inline uint128 operator*(const uint128& lhs, const uint128& rhs) {
|
||||
return uint128(lhs) *= rhs;
|
||||
}
|
||||
|
||||
inline uint128 operator/(const uint128& lhs, const uint128& rhs) {
|
||||
return uint128(lhs) /= rhs;
|
||||
}
|
||||
|
||||
inline uint128 operator%(const uint128& lhs, const uint128& rhs) {
|
||||
return uint128(lhs) %= rhs;
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator+=(const uint128& b) {
|
||||
hi_ += b.hi_;
|
||||
uint64 lolo = lo_ + b.lo_;
|
||||
if (lolo < lo_)
|
||||
++hi_;
|
||||
lo_ = lolo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator-=(const uint128& b) {
|
||||
hi_ -= b.hi_;
|
||||
if (b.lo_ > lo_)
|
||||
--hi_;
|
||||
lo_ -= b.lo_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator*=(const uint128& b) {
|
||||
uint64 a96 = hi_ >> 32;
|
||||
uint64 a64 = hi_ & 0xffffffffu;
|
||||
uint64 a32 = lo_ >> 32;
|
||||
uint64 a00 = lo_ & 0xffffffffu;
|
||||
uint64 b96 = b.hi_ >> 32;
|
||||
uint64 b64 = b.hi_ & 0xffffffffu;
|
||||
uint64 b32 = b.lo_ >> 32;
|
||||
uint64 b00 = b.lo_ & 0xffffffffu;
|
||||
// multiply [a96 .. a00] x [b96 .. b00]
|
||||
// terms higher than c96 disappear off the high side
|
||||
// terms c96 and c64 are safe to ignore carry bit
|
||||
uint64 c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96;
|
||||
uint64 c64 = a64 * b00 + a32 * b32 + a00 * b64;
|
||||
this->hi_ = (c96 << 32) + c64;
|
||||
this->lo_ = 0;
|
||||
// add terms after this one at a time to capture carry
|
||||
*this += uint128(a32 * b00) << 32;
|
||||
*this += uint128(a00 * b32) << 32;
|
||||
*this += a00 * b00;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128 uint128::operator++(int) {
|
||||
uint128 tmp(*this);
|
||||
*this += 1;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline uint128 uint128::operator--(int) {
|
||||
uint128 tmp(*this);
|
||||
*this -= 1;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator++() {
|
||||
*this += 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator--() {
|
||||
*this -= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_INT128_H_
|
||||
517
ubuntu/google/protobuf/stubs/int128_unittest.cc
Normal file
517
ubuntu/google/protobuf/stubs/int128_unittest.cc
Normal file
@@ -0,0 +1,517 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <google/protobuf/stubs/int128.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
TEST(Int128, AllTests) {
|
||||
uint128 zero(0);
|
||||
uint128 one(1);
|
||||
uint128 one_2arg(0, 1);
|
||||
uint128 two(0, 2);
|
||||
uint128 three(0, 3);
|
||||
uint128 big(2000, 2);
|
||||
uint128 big_minus_one(2000, 1);
|
||||
uint128 bigger(2001, 1);
|
||||
uint128 biggest(kuint128max);
|
||||
uint128 high_low(1, 0);
|
||||
uint128 low_high(0, kuint64max);
|
||||
EXPECT_LT(one, two);
|
||||
EXPECT_GT(two, one);
|
||||
EXPECT_LT(one, big);
|
||||
EXPECT_LT(one, big);
|
||||
EXPECT_EQ(one, one_2arg);
|
||||
EXPECT_NE(one, two);
|
||||
EXPECT_GT(big, one);
|
||||
EXPECT_GE(big, two);
|
||||
EXPECT_GE(big, big_minus_one);
|
||||
EXPECT_GT(big, big_minus_one);
|
||||
EXPECT_LT(big_minus_one, big);
|
||||
EXPECT_LE(big_minus_one, big);
|
||||
EXPECT_NE(big_minus_one, big);
|
||||
EXPECT_LT(big, biggest);
|
||||
EXPECT_LE(big, biggest);
|
||||
EXPECT_GT(biggest, big);
|
||||
EXPECT_GE(biggest, big);
|
||||
EXPECT_EQ(big, ~~big);
|
||||
EXPECT_EQ(one, one | one);
|
||||
EXPECT_EQ(big, big | big);
|
||||
EXPECT_EQ(one, one | zero);
|
||||
EXPECT_EQ(one, one & one);
|
||||
EXPECT_EQ(big, big & big);
|
||||
EXPECT_EQ(zero, one & zero);
|
||||
EXPECT_EQ(zero, big & ~big);
|
||||
EXPECT_EQ(zero, one ^ one);
|
||||
EXPECT_EQ(zero, big ^ big);
|
||||
EXPECT_EQ(one, one ^ zero);
|
||||
|
||||
// Shift operators.
|
||||
EXPECT_EQ(big, big << 0);
|
||||
EXPECT_EQ(big, big >> 0);
|
||||
EXPECT_GT(big << 1, big);
|
||||
EXPECT_LT(big >> 1, big);
|
||||
EXPECT_EQ(big, (big << 10) >> 10);
|
||||
EXPECT_EQ(big, (big >> 1) << 1);
|
||||
EXPECT_EQ(one, (one << 80) >> 80);
|
||||
EXPECT_EQ(zero, (one >> 80) << 80);
|
||||
EXPECT_EQ(zero, big >> 128);
|
||||
EXPECT_EQ(zero, big << 128);
|
||||
|
||||
// Shift assignments.
|
||||
uint128 big_copy = big;
|
||||
EXPECT_EQ(big << 0, big_copy <<= 0);
|
||||
big_copy = big;
|
||||
EXPECT_EQ(big >> 0, big_copy >>= 0);
|
||||
big_copy = big;
|
||||
EXPECT_EQ(big << 1, big_copy <<= 1);
|
||||
big_copy = big;
|
||||
EXPECT_EQ(big >> 1, big_copy >>= 1);
|
||||
big_copy = big;
|
||||
EXPECT_EQ(big << 10, big_copy <<= 10);
|
||||
big_copy = big;
|
||||
EXPECT_EQ(big >> 10, big_copy >>= 10);
|
||||
big_copy = big;
|
||||
EXPECT_EQ(big << 64, big_copy <<= 64);
|
||||
big_copy = big;
|
||||
EXPECT_EQ(big >> 64, big_copy >>= 64);
|
||||
big_copy = big;
|
||||
EXPECT_EQ(big << 73, big_copy <<= 73);
|
||||
big_copy = big;
|
||||
EXPECT_EQ(big >> 73, big_copy >>= 73);
|
||||
big_copy = big;
|
||||
EXPECT_EQ(big << 128, big_copy <<= 128);
|
||||
big_copy = big;
|
||||
EXPECT_EQ(big >> 128, big_copy >>= 128);
|
||||
|
||||
EXPECT_EQ(Uint128High64(biggest), kuint64max);
|
||||
EXPECT_EQ(Uint128Low64(biggest), kuint64max);
|
||||
EXPECT_EQ(zero + one, one);
|
||||
EXPECT_EQ(one + one, two);
|
||||
EXPECT_EQ(big_minus_one + one, big);
|
||||
EXPECT_EQ(one - one, zero);
|
||||
EXPECT_EQ(one - zero, one);
|
||||
EXPECT_EQ(zero - one, biggest);
|
||||
EXPECT_EQ(big - big, zero);
|
||||
EXPECT_EQ(big - one, big_minus_one);
|
||||
EXPECT_EQ(big + kuint64max, bigger);
|
||||
EXPECT_EQ(biggest + 1, zero);
|
||||
EXPECT_EQ(zero - 1, biggest);
|
||||
EXPECT_EQ(high_low - one, low_high);
|
||||
EXPECT_EQ(low_high + one, high_low);
|
||||
EXPECT_EQ(Uint128High64((uint128(1) << 64) - 1), 0);
|
||||
EXPECT_EQ(Uint128Low64((uint128(1) << 64) - 1), kuint64max);
|
||||
EXPECT_TRUE(!!one);
|
||||
EXPECT_TRUE(!!high_low);
|
||||
EXPECT_FALSE(!!zero);
|
||||
EXPECT_FALSE(!one);
|
||||
EXPECT_FALSE(!high_low);
|
||||
EXPECT_TRUE(!zero);
|
||||
EXPECT_TRUE(zero == 0);
|
||||
EXPECT_FALSE(zero != 0);
|
||||
EXPECT_FALSE(one == 0);
|
||||
EXPECT_TRUE(one != 0);
|
||||
|
||||
uint128 test = zero;
|
||||
EXPECT_EQ(++test, one);
|
||||
EXPECT_EQ(test, one);
|
||||
EXPECT_EQ(test++, one);
|
||||
EXPECT_EQ(test, two);
|
||||
EXPECT_EQ(test -= 2, zero);
|
||||
EXPECT_EQ(test, zero);
|
||||
EXPECT_EQ(test += 2, two);
|
||||
EXPECT_EQ(test, two);
|
||||
EXPECT_EQ(--test, one);
|
||||
EXPECT_EQ(test, one);
|
||||
EXPECT_EQ(test--, one);
|
||||
EXPECT_EQ(test, zero);
|
||||
EXPECT_EQ(test |= three, three);
|
||||
EXPECT_EQ(test &= one, one);
|
||||
EXPECT_EQ(test ^= three, two);
|
||||
EXPECT_EQ(test >>= 1, one);
|
||||
EXPECT_EQ(test <<= 1, two);
|
||||
|
||||
EXPECT_EQ(big, -(-big));
|
||||
EXPECT_EQ(two, -((-one) - 1));
|
||||
EXPECT_EQ(kuint128max, -one);
|
||||
EXPECT_EQ(zero, -zero);
|
||||
|
||||
GOOGLE_LOG(INFO) << one;
|
||||
GOOGLE_LOG(INFO) << big_minus_one;
|
||||
}
|
||||
|
||||
TEST(Int128, PodTests) {
|
||||
uint128_pod pod = { 12345, 67890 };
|
||||
uint128 from_pod(pod);
|
||||
EXPECT_EQ(12345, Uint128High64(from_pod));
|
||||
EXPECT_EQ(67890, Uint128Low64(from_pod));
|
||||
|
||||
uint128 zero(0);
|
||||
uint128_pod zero_pod = {0, 0};
|
||||
uint128 one(1);
|
||||
uint128_pod one_pod = {0, 1};
|
||||
uint128 two(2);
|
||||
uint128_pod two_pod = {0, 2};
|
||||
uint128 three(3);
|
||||
uint128_pod three_pod = {0, 3};
|
||||
uint128 big(1, 0);
|
||||
uint128_pod big_pod = {1, 0};
|
||||
|
||||
EXPECT_EQ(zero, zero_pod);
|
||||
EXPECT_EQ(zero_pod, zero);
|
||||
EXPECT_EQ(zero_pod, zero_pod);
|
||||
EXPECT_EQ(one, one_pod);
|
||||
EXPECT_EQ(one_pod, one);
|
||||
EXPECT_EQ(one_pod, one_pod);
|
||||
EXPECT_EQ(two, two_pod);
|
||||
EXPECT_EQ(two_pod, two);
|
||||
EXPECT_EQ(two_pod, two_pod);
|
||||
|
||||
EXPECT_NE(one, two_pod);
|
||||
EXPECT_NE(one_pod, two);
|
||||
EXPECT_NE(one_pod, two_pod);
|
||||
|
||||
EXPECT_LT(one, two_pod);
|
||||
EXPECT_LT(one_pod, two);
|
||||
EXPECT_LT(one_pod, two_pod);
|
||||
EXPECT_LE(one, one_pod);
|
||||
EXPECT_LE(one_pod, one);
|
||||
EXPECT_LE(one_pod, one_pod);
|
||||
EXPECT_LE(one, two_pod);
|
||||
EXPECT_LE(one_pod, two);
|
||||
EXPECT_LE(one_pod, two_pod);
|
||||
|
||||
EXPECT_GT(two, one_pod);
|
||||
EXPECT_GT(two_pod, one);
|
||||
EXPECT_GT(two_pod, one_pod);
|
||||
EXPECT_GE(two, two_pod);
|
||||
EXPECT_GE(two_pod, two);
|
||||
EXPECT_GE(two_pod, two_pod);
|
||||
EXPECT_GE(two, one_pod);
|
||||
EXPECT_GE(two_pod, one);
|
||||
EXPECT_GE(two_pod, one_pod);
|
||||
|
||||
EXPECT_EQ(three, one | two_pod);
|
||||
EXPECT_EQ(three, one_pod | two);
|
||||
EXPECT_EQ(three, one_pod | two_pod);
|
||||
EXPECT_EQ(one, three & one_pod);
|
||||
EXPECT_EQ(one, three_pod & one);
|
||||
EXPECT_EQ(one, three_pod & one_pod);
|
||||
EXPECT_EQ(two, three ^ one_pod);
|
||||
EXPECT_EQ(two, three_pod ^ one);
|
||||
EXPECT_EQ(two, three_pod ^ one_pod);
|
||||
EXPECT_EQ(two, three & (~one));
|
||||
EXPECT_EQ(three, ~~three);
|
||||
|
||||
EXPECT_EQ(two, two_pod << 0);
|
||||
EXPECT_EQ(two, one_pod << 1);
|
||||
EXPECT_EQ(big, one_pod << 64);
|
||||
EXPECT_EQ(zero, one_pod << 128);
|
||||
EXPECT_EQ(two, two_pod >> 0);
|
||||
EXPECT_EQ(one, two_pod >> 1);
|
||||
EXPECT_EQ(one, big_pod >> 64);
|
||||
|
||||
EXPECT_EQ(one, zero + one_pod);
|
||||
EXPECT_EQ(one, zero_pod + one);
|
||||
EXPECT_EQ(one, zero_pod + one_pod);
|
||||
EXPECT_EQ(one, two - one_pod);
|
||||
EXPECT_EQ(one, two_pod - one);
|
||||
EXPECT_EQ(one, two_pod - one_pod);
|
||||
}
|
||||
|
||||
TEST(Int128, OperatorAssignReturnRef) {
|
||||
uint128 v(1);
|
||||
(v += 4) -= 3;
|
||||
EXPECT_EQ(2, v);
|
||||
}
|
||||
|
||||
TEST(Int128, Multiply) {
|
||||
uint128 a, b, c;
|
||||
|
||||
// Zero test.
|
||||
a = 0;
|
||||
b = 0;
|
||||
c = a * b;
|
||||
EXPECT_EQ(0, c);
|
||||
|
||||
// Max carries.
|
||||
a = uint128(0) - 1;
|
||||
b = uint128(0) - 1;
|
||||
c = a * b;
|
||||
EXPECT_EQ(1, c);
|
||||
|
||||
// Self-operation with max carries.
|
||||
c = uint128(0) - 1;
|
||||
c *= c;
|
||||
EXPECT_EQ(1, c);
|
||||
|
||||
// 1-bit x 1-bit.
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
for (int j = 0; j < 64; ++j) {
|
||||
a = uint128(1) << i;
|
||||
b = uint128(1) << j;
|
||||
c = a * b;
|
||||
EXPECT_EQ(uint128(1) << (i+j), c);
|
||||
}
|
||||
}
|
||||
|
||||
// Verified with dc.
|
||||
a = uint128(PROTOBUF_ULONGLONG(0xffffeeeeddddcccc),
|
||||
PROTOBUF_ULONGLONG(0xbbbbaaaa99998888));
|
||||
b = uint128(PROTOBUF_ULONGLONG(0x7777666655554444),
|
||||
PROTOBUF_ULONGLONG(0x3333222211110000));
|
||||
c = a * b;
|
||||
EXPECT_EQ(uint128(PROTOBUF_ULONGLONG(0x530EDA741C71D4C3),
|
||||
PROTOBUF_ULONGLONG(0xBF25975319080000)),
|
||||
c);
|
||||
EXPECT_EQ(0, c - b * a);
|
||||
EXPECT_EQ(a * a - b * b, (a + b) * (a - b));
|
||||
|
||||
// Verified with dc.
|
||||
a = uint128(PROTOBUF_ULONGLONG(0x0123456789abcdef),
|
||||
PROTOBUF_ULONGLONG(0xfedcba9876543210));
|
||||
b = uint128(PROTOBUF_ULONGLONG(0x02468ace13579bdf),
|
||||
PROTOBUF_ULONGLONG(0xfdb97531eca86420));
|
||||
c = a * b;
|
||||
EXPECT_EQ(uint128(PROTOBUF_ULONGLONG(0x97a87f4f261ba3f2),
|
||||
PROTOBUF_ULONGLONG(0x342d0bbf48948200)),
|
||||
c);
|
||||
EXPECT_EQ(0, c - b * a);
|
||||
EXPECT_EQ(a*a - b*b, (a+b) * (a-b));
|
||||
}
|
||||
|
||||
TEST(Int128, AliasTests) {
|
||||
uint128 x1(1, 2);
|
||||
uint128 x2(2, 4);
|
||||
x1 += x1;
|
||||
EXPECT_EQ(x2, x1);
|
||||
|
||||
uint128 x3(1, static_cast<uint64>(1) << 63);
|
||||
uint128 x4(3, 0);
|
||||
x3 += x3;
|
||||
EXPECT_EQ(x4, x3);
|
||||
}
|
||||
|
||||
#ifdef PROTOBUF_HAS_DEATH_TEST
|
||||
TEST(Int128, DivideByZeroCheckFails) {
|
||||
uint128 a = 0;
|
||||
uint128 b = 0;
|
||||
EXPECT_DEATH(a / b, "Division or mod by zero:");
|
||||
a = 123;
|
||||
EXPECT_DEATH(a / b, "Division or mod by zero:");
|
||||
}
|
||||
|
||||
TEST(Int128, ModByZeroCheckFails) {
|
||||
uint128 a = 0;
|
||||
uint128 b = 0;
|
||||
EXPECT_DEATH(a % b, "Division or mod by zero:");
|
||||
a = 123;
|
||||
EXPECT_DEATH(a % b, "Division or mod by zero:");
|
||||
}
|
||||
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||
|
||||
TEST(Int128, DivideAndMod) {
|
||||
// a := q * b + r
|
||||
uint128 a, b, q, r;
|
||||
|
||||
// Zero test.
|
||||
a = 0;
|
||||
b = 123;
|
||||
q = a / b;
|
||||
r = a % b;
|
||||
EXPECT_EQ(0, q);
|
||||
EXPECT_EQ(0, r);
|
||||
|
||||
a = uint128(PROTOBUF_ULONGLONG(0x530eda741c71d4c3),
|
||||
PROTOBUF_ULONGLONG(0xbf25975319080000));
|
||||
q = uint128(PROTOBUF_ULONGLONG(0x4de2cab081),
|
||||
PROTOBUF_ULONGLONG(0x14c34ab4676e4bab));
|
||||
b = uint128(0x1110001);
|
||||
r = uint128(0x3eb455);
|
||||
ASSERT_EQ(a, q * b + r); // Sanity-check.
|
||||
|
||||
uint128 result_q, result_r;
|
||||
result_q = a / b;
|
||||
result_r = a % b;
|
||||
EXPECT_EQ(q, result_q);
|
||||
EXPECT_EQ(r, result_r);
|
||||
|
||||
// Try the other way around.
|
||||
std::swap(q, b);
|
||||
result_q = a / b;
|
||||
result_r = a % b;
|
||||
EXPECT_EQ(q, result_q);
|
||||
EXPECT_EQ(r, result_r);
|
||||
// Restore.
|
||||
std::swap(b, q);
|
||||
|
||||
// Dividend < divisor; result should be q:0 r:<dividend>.
|
||||
std::swap(a, b);
|
||||
result_q = a / b;
|
||||
result_r = a % b;
|
||||
EXPECT_EQ(0, result_q);
|
||||
EXPECT_EQ(a, result_r);
|
||||
// Try the other way around.
|
||||
std::swap(a, q);
|
||||
result_q = a / b;
|
||||
result_r = a % b;
|
||||
EXPECT_EQ(0, result_q);
|
||||
EXPECT_EQ(a, result_r);
|
||||
// Restore.
|
||||
std::swap(q, a);
|
||||
std::swap(b, a);
|
||||
|
||||
// Try a large remainder.
|
||||
b = a / 2 + 1;
|
||||
uint128 expected_r(PROTOBUF_ULONGLONG(0x29876d3a0e38ea61),
|
||||
PROTOBUF_ULONGLONG(0xdf92cba98c83ffff));
|
||||
// Sanity checks.
|
||||
ASSERT_EQ(a / 2 - 1, expected_r);
|
||||
ASSERT_EQ(a, b + expected_r);
|
||||
result_q = a / b;
|
||||
result_r = a % b;
|
||||
EXPECT_EQ(1, result_q);
|
||||
EXPECT_EQ(expected_r, result_r);
|
||||
}
|
||||
|
||||
static uint64 RandomUint64() {
|
||||
uint64 v1 = rand();
|
||||
uint64 v2 = rand();
|
||||
uint64 v3 = rand();
|
||||
return v1 * v2 + v3;
|
||||
}
|
||||
|
||||
TEST(Int128, DivideAndModRandomInputs) {
|
||||
const int kNumIters = 1 << 18;
|
||||
for (int i = 0; i < kNumIters; ++i) {
|
||||
const uint128 a(RandomUint64(), RandomUint64());
|
||||
const uint128 b(RandomUint64(), RandomUint64());
|
||||
if (b == 0) {
|
||||
continue; // Avoid a div-by-zero.
|
||||
}
|
||||
const uint128 q = a / b;
|
||||
const uint128 r = a % b;
|
||||
ASSERT_EQ(a, b * q + r);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR
|
||||
TEST(Int128, ConstexprTest) {
|
||||
constexpr uint128 zero;
|
||||
constexpr uint128 one = 1;
|
||||
constexpr uint128_pod pod = {2, 3};
|
||||
constexpr uint128 from_pod = pod;
|
||||
constexpr uint128 minus_two = -2;
|
||||
EXPECT_EQ(one, uint128(1));
|
||||
EXPECT_EQ(from_pod, uint128(2, 3));
|
||||
EXPECT_EQ(minus_two, uint128(-1ULL, -2ULL));
|
||||
}
|
||||
|
||||
TEST(Int128, Traits) {
|
||||
EXPECT_TRUE(std::is_trivially_copy_constructible<uint128>::value);
|
||||
EXPECT_TRUE(std::is_trivially_copy_assignable<uint128>::value);
|
||||
EXPECT_TRUE(std::is_trivially_destructible<uint128>::value);
|
||||
}
|
||||
#endif // GOOGLE_PROTOBUF_HAS_CONSTEXPR
|
||||
|
||||
TEST(Int128, OStream) {
|
||||
struct {
|
||||
uint128 val;
|
||||
std::ios_base::fmtflags flags;
|
||||
std::streamsize width;
|
||||
char fill;
|
||||
const char* rep;
|
||||
} cases[] = {
|
||||
// zero with different bases
|
||||
{uint128(0), std::ios::dec, 0, '_', "0"},
|
||||
{uint128(0), std::ios::oct, 0, '_', "0"},
|
||||
{uint128(0), std::ios::hex, 0, '_', "0"},
|
||||
// crossover between lo_ and hi_
|
||||
{uint128(0, -1), std::ios::dec, 0, '_', "18446744073709551615"},
|
||||
{uint128(0, -1), std::ios::oct, 0, '_', "1777777777777777777777"},
|
||||
{uint128(0, -1), std::ios::hex, 0, '_', "ffffffffffffffff"},
|
||||
{uint128(1, 0), std::ios::dec, 0, '_', "18446744073709551616"},
|
||||
{uint128(1, 0), std::ios::oct, 0, '_', "2000000000000000000000"},
|
||||
{uint128(1, 0), std::ios::hex, 0, '_', "10000000000000000"},
|
||||
// just the top bit
|
||||
{uint128(PROTOBUF_ULONGLONG(0x8000000000000000), 0), std::ios::dec, 0,
|
||||
'_', "170141183460469231731687303715884105728"},
|
||||
{uint128(PROTOBUF_ULONGLONG(0x8000000000000000), 0), std::ios::oct, 0,
|
||||
'_', "2000000000000000000000000000000000000000000"},
|
||||
{uint128(PROTOBUF_ULONGLONG(0x8000000000000000), 0), std::ios::hex, 0,
|
||||
'_', "80000000000000000000000000000000"},
|
||||
// maximum uint128 value
|
||||
{uint128(-1, -1), std::ios::dec, 0, '_',
|
||||
"340282366920938463463374607431768211455"},
|
||||
{uint128(-1, -1), std::ios::oct, 0, '_',
|
||||
"3777777777777777777777777777777777777777777"},
|
||||
{uint128(-1, -1), std::ios::hex, 0, '_',
|
||||
"ffffffffffffffffffffffffffffffff"},
|
||||
// uppercase
|
||||
{uint128(-1, -1), std::ios::hex | std::ios::uppercase, 0, '_',
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"},
|
||||
// showbase
|
||||
{uint128(1), std::ios::dec | std::ios::showbase, 0, '_', "1"},
|
||||
{uint128(1), std::ios::oct | std::ios::showbase, 0, '_', "01"},
|
||||
{uint128(1), std::ios::hex | std::ios::showbase, 0, '_', "0x1"},
|
||||
// showbase does nothing on zero
|
||||
{uint128(0), std::ios::dec | std::ios::showbase, 0, '_', "0"},
|
||||
{uint128(0), std::ios::oct | std::ios::showbase, 0, '_', "0"},
|
||||
{uint128(0), std::ios::hex | std::ios::showbase, 0, '_', "0"},
|
||||
// showpos does nothing on unsigned types
|
||||
{uint128(1), std::ios::dec | std::ios::showpos, 0, '_', "1"},
|
||||
// padding
|
||||
{uint128(9), std::ios::dec, 6, '_', "_____9"},
|
||||
{uint128(12345), std::ios::dec, 6, '_', "_12345"},
|
||||
// left adjustment
|
||||
{uint128(9), std::ios::dec | std::ios::left, 6, '_', "9_____"},
|
||||
{uint128(12345), std::ios::dec | std::ios::left, 6, '_', "12345_"},
|
||||
};
|
||||
for (size_t i = 0; i < GOOGLE_ARRAYSIZE(cases); ++i) {
|
||||
std::ostringstream os;
|
||||
os.flags(cases[i].flags);
|
||||
os.width(cases[i].width);
|
||||
os.fill(cases[i].fill);
|
||||
os << cases[i].val;
|
||||
EXPECT_EQ(cases[i].rep, os.str());
|
||||
}
|
||||
}
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
241
ubuntu/google/protobuf/stubs/logging.h
Normal file
241
ubuntu/google/protobuf/stubs/logging.h
Normal file
@@ -0,0 +1,241 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_LOGGING_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_LOGGING_H_
|
||||
|
||||
#include <google/protobuf/stubs/macros.h>
|
||||
#include <google/protobuf/stubs/port.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
// ===================================================================
|
||||
// emulates google3/base/logging.h
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
enum LogLevel {
|
||||
LOGLEVEL_INFO, // Informational. This is never actually used by
|
||||
// libprotobuf.
|
||||
LOGLEVEL_WARNING, // Warns about issues that, although not technically a
|
||||
// problem now, could cause problems in the future. For
|
||||
// example, a // warning will be printed when parsing a
|
||||
// message that is near the message size limit.
|
||||
LOGLEVEL_ERROR, // An error occurred which should never happen during
|
||||
// normal use.
|
||||
LOGLEVEL_FATAL, // An error occurred from which the library cannot
|
||||
// recover. This usually indicates a programming error
|
||||
// in the code which calls the library, especially when
|
||||
// compiled in debug mode.
|
||||
|
||||
#ifdef NDEBUG
|
||||
LOGLEVEL_DFATAL = LOGLEVEL_ERROR
|
||||
#else
|
||||
LOGLEVEL_DFATAL = LOGLEVEL_FATAL
|
||||
#endif
|
||||
};
|
||||
|
||||
class StringPiece;
|
||||
namespace util {
|
||||
class Status;
|
||||
}
|
||||
class uint128;
|
||||
namespace internal {
|
||||
|
||||
class LogFinisher;
|
||||
|
||||
class PROTOBUF_EXPORT LogMessage {
|
||||
public:
|
||||
LogMessage(LogLevel level, const char* filename, int line);
|
||||
~LogMessage();
|
||||
|
||||
LogMessage& operator<<(const std::string& value);
|
||||
LogMessage& operator<<(const char* value);
|
||||
LogMessage& operator<<(char value);
|
||||
LogMessage& operator<<(int value);
|
||||
LogMessage& operator<<(uint value);
|
||||
LogMessage& operator<<(long value);
|
||||
LogMessage& operator<<(unsigned long value);
|
||||
LogMessage& operator<<(long long value);
|
||||
LogMessage& operator<<(unsigned long long value);
|
||||
LogMessage& operator<<(double value);
|
||||
LogMessage& operator<<(void* value);
|
||||
LogMessage& operator<<(const StringPiece& value);
|
||||
LogMessage& operator<<(const util::Status& status);
|
||||
LogMessage& operator<<(const uint128& value);
|
||||
|
||||
private:
|
||||
friend class LogFinisher;
|
||||
void Finish();
|
||||
|
||||
LogLevel level_;
|
||||
const char* filename_;
|
||||
int line_;
|
||||
std::string message_;
|
||||
};
|
||||
|
||||
// Used to make the entire "LOG(BLAH) << etc." expression have a void return
|
||||
// type and print a newline after each message.
|
||||
class PROTOBUF_EXPORT LogFinisher {
|
||||
public:
|
||||
void operator=(LogMessage& other);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool IsOk(T status) { return status.ok(); }
|
||||
template<>
|
||||
inline bool IsOk(bool status) { return status; }
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Undef everything in case we're being mixed with some other Google library
|
||||
// which already defined them itself. Presumably all Google libraries will
|
||||
// support the same syntax for these so it should not be a big deal if they
|
||||
// end up using our definitions instead.
|
||||
#undef GOOGLE_LOG
|
||||
#undef GOOGLE_LOG_IF
|
||||
|
||||
#undef GOOGLE_CHECK
|
||||
#undef GOOGLE_CHECK_OK
|
||||
#undef GOOGLE_CHECK_EQ
|
||||
#undef GOOGLE_CHECK_NE
|
||||
#undef GOOGLE_CHECK_LT
|
||||
#undef GOOGLE_CHECK_LE
|
||||
#undef GOOGLE_CHECK_GT
|
||||
#undef GOOGLE_CHECK_GE
|
||||
#undef GOOGLE_CHECK_NOTNULL
|
||||
|
||||
#undef GOOGLE_DLOG
|
||||
#undef GOOGLE_DCHECK
|
||||
#undef GOOGLE_DCHECK_OK
|
||||
#undef GOOGLE_DCHECK_EQ
|
||||
#undef GOOGLE_DCHECK_NE
|
||||
#undef GOOGLE_DCHECK_LT
|
||||
#undef GOOGLE_DCHECK_LE
|
||||
#undef GOOGLE_DCHECK_GT
|
||||
#undef GOOGLE_DCHECK_GE
|
||||
|
||||
#define GOOGLE_LOG(LEVEL) \
|
||||
::google::protobuf::internal::LogFinisher() = \
|
||||
::google::protobuf::internal::LogMessage( \
|
||||
::google::protobuf::LOGLEVEL_##LEVEL, __FILE__, __LINE__)
|
||||
#define GOOGLE_LOG_IF(LEVEL, CONDITION) \
|
||||
!(CONDITION) ? (void)0 : GOOGLE_LOG(LEVEL)
|
||||
|
||||
#define GOOGLE_CHECK(EXPRESSION) \
|
||||
GOOGLE_LOG_IF(FATAL, !(EXPRESSION)) << "CHECK failed: " #EXPRESSION ": "
|
||||
#define GOOGLE_CHECK_OK(A) GOOGLE_CHECK(::google::protobuf::internal::IsOk(A))
|
||||
#define GOOGLE_CHECK_EQ(A, B) GOOGLE_CHECK((A) == (B))
|
||||
#define GOOGLE_CHECK_NE(A, B) GOOGLE_CHECK((A) != (B))
|
||||
#define GOOGLE_CHECK_LT(A, B) GOOGLE_CHECK((A) < (B))
|
||||
#define GOOGLE_CHECK_LE(A, B) GOOGLE_CHECK((A) <= (B))
|
||||
#define GOOGLE_CHECK_GT(A, B) GOOGLE_CHECK((A) > (B))
|
||||
#define GOOGLE_CHECK_GE(A, B) GOOGLE_CHECK((A) >= (B))
|
||||
|
||||
namespace internal {
|
||||
template<typename T>
|
||||
T* CheckNotNull(const char* /* file */, int /* line */,
|
||||
const char* name, T* val) {
|
||||
if (val == nullptr) {
|
||||
GOOGLE_LOG(FATAL) << name;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
} // namespace internal
|
||||
#define GOOGLE_CHECK_NOTNULL(A) \
|
||||
::google::protobuf::internal::CheckNotNull( \
|
||||
__FILE__, __LINE__, "'" #A "' must not be nullptr", (A))
|
||||
|
||||
#ifdef NDEBUG
|
||||
|
||||
#define GOOGLE_DLOG(LEVEL) GOOGLE_LOG_IF(LEVEL, false)
|
||||
|
||||
#define GOOGLE_DCHECK(EXPRESSION) while(false) GOOGLE_CHECK(EXPRESSION)
|
||||
#define GOOGLE_DCHECK_OK(E) GOOGLE_DCHECK(::google::protobuf::internal::IsOk(E))
|
||||
#define GOOGLE_DCHECK_EQ(A, B) GOOGLE_DCHECK((A) == (B))
|
||||
#define GOOGLE_DCHECK_NE(A, B) GOOGLE_DCHECK((A) != (B))
|
||||
#define GOOGLE_DCHECK_LT(A, B) GOOGLE_DCHECK((A) < (B))
|
||||
#define GOOGLE_DCHECK_LE(A, B) GOOGLE_DCHECK((A) <= (B))
|
||||
#define GOOGLE_DCHECK_GT(A, B) GOOGLE_DCHECK((A) > (B))
|
||||
#define GOOGLE_DCHECK_GE(A, B) GOOGLE_DCHECK((A) >= (B))
|
||||
|
||||
#else // NDEBUG
|
||||
|
||||
#define GOOGLE_DLOG GOOGLE_LOG
|
||||
|
||||
#define GOOGLE_DCHECK GOOGLE_CHECK
|
||||
#define GOOGLE_DCHECK_OK GOOGLE_CHECK_OK
|
||||
#define GOOGLE_DCHECK_EQ GOOGLE_CHECK_EQ
|
||||
#define GOOGLE_DCHECK_NE GOOGLE_CHECK_NE
|
||||
#define GOOGLE_DCHECK_LT GOOGLE_CHECK_LT
|
||||
#define GOOGLE_DCHECK_LE GOOGLE_CHECK_LE
|
||||
#define GOOGLE_DCHECK_GT GOOGLE_CHECK_GT
|
||||
#define GOOGLE_DCHECK_GE GOOGLE_CHECK_GE
|
||||
|
||||
#endif // !NDEBUG
|
||||
|
||||
typedef void LogHandler(LogLevel level, const char* filename, int line,
|
||||
const std::string& message);
|
||||
|
||||
// The protobuf library sometimes writes warning and error messages to
|
||||
// stderr. These messages are primarily useful for developers, but may
|
||||
// also help end users figure out a problem. If you would prefer that
|
||||
// these messages be sent somewhere other than stderr, call SetLogHandler()
|
||||
// to set your own handler. This returns the old handler. Set the handler
|
||||
// to nullptr to ignore log messages (but see also LogSilencer, below).
|
||||
//
|
||||
// Obviously, SetLogHandler is not thread-safe. You should only call it
|
||||
// at initialization time, and probably not from library code. If you
|
||||
// simply want to suppress log messages temporarily (e.g. because you
|
||||
// have some code that tends to trigger them frequently and you know
|
||||
// the warnings are not important to you), use the LogSilencer class
|
||||
// below.
|
||||
PROTOBUF_EXPORT LogHandler* SetLogHandler(LogHandler* new_func);
|
||||
|
||||
// Create a LogSilencer if you want to temporarily suppress all log
|
||||
// messages. As long as any LogSilencer objects exist, non-fatal
|
||||
// log messages will be discarded (the current LogHandler will *not*
|
||||
// be called). Constructing a LogSilencer is thread-safe. You may
|
||||
// accidentally suppress log messages occurring in another thread, but
|
||||
// since messages are generally for debugging purposes only, this isn't
|
||||
// a big deal. If you want to intercept log messages, use SetLogHandler().
|
||||
class PROTOBUF_EXPORT LogSilencer {
|
||||
public:
|
||||
LogSilencer();
|
||||
~LogSilencer();
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_LOGGING_H_
|
||||
120
ubuntu/google/protobuf/stubs/macros.h
Normal file
120
ubuntu/google/protobuf/stubs/macros.h
Normal file
@@ -0,0 +1,120 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_MACROS_H__
|
||||
#define GOOGLE_PROTOBUF_MACROS_H__
|
||||
|
||||
#include <google/protobuf/stubs/port.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
#undef GOOGLE_DISALLOW_EVIL_CONSTRUCTORS
|
||||
#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
#undef GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS
|
||||
#define GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
|
||||
TypeName(); \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
// ===================================================================
|
||||
// from google3/base/basictypes.h
|
||||
|
||||
// The GOOGLE_ARRAYSIZE(arr) macro returns the # of elements in an array arr.
|
||||
// The expression is a compile-time constant, and therefore can be
|
||||
// used in defining new arrays, for example.
|
||||
//
|
||||
// GOOGLE_ARRAYSIZE catches a few type errors. If you see a compiler error
|
||||
//
|
||||
// "warning: division by zero in ..."
|
||||
//
|
||||
// when using GOOGLE_ARRAYSIZE, you are (wrongfully) giving it a pointer.
|
||||
// You should only use GOOGLE_ARRAYSIZE on statically allocated arrays.
|
||||
//
|
||||
// The following comments are on the implementation details, and can
|
||||
// be ignored by the users.
|
||||
//
|
||||
// ARRAYSIZE(arr) works by inspecting sizeof(arr) (the # of bytes in
|
||||
// the array) and sizeof(*(arr)) (the # of bytes in one array
|
||||
// element). If the former is divisible by the latter, perhaps arr is
|
||||
// indeed an array, in which case the division result is the # of
|
||||
// elements in the array. Otherwise, arr cannot possibly be an array,
|
||||
// and we generate a compiler error to prevent the code from
|
||||
// compiling.
|
||||
//
|
||||
// Since the size of bool is implementation-defined, we need to cast
|
||||
// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
|
||||
// result has type size_t.
|
||||
//
|
||||
// This macro is not perfect as it wrongfully accepts certain
|
||||
// pointers, namely where the pointer size is divisible by the pointee
|
||||
// size. Since all our code has to go through a 32-bit compiler,
|
||||
// where a pointer is 4 bytes, this means all pointers to a type whose
|
||||
// size is 3 or greater than 4 will be (righteously) rejected.
|
||||
//
|
||||
// Kudos to Jorg Brown for this simple and elegant implementation.
|
||||
|
||||
#undef GOOGLE_ARRAYSIZE
|
||||
#define GOOGLE_ARRAYSIZE(a) \
|
||||
((sizeof(a) / sizeof(*(a))) / \
|
||||
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
|
||||
|
||||
// The COMPILE_ASSERT macro can be used to verify that a compile time
|
||||
// expression is true. For example, you could use it to verify the
|
||||
// size of a static array:
|
||||
//
|
||||
// COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
|
||||
// content_type_names_incorrect_size);
|
||||
//
|
||||
// or to make sure a struct is smaller than a certain size:
|
||||
//
|
||||
// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
|
||||
//
|
||||
// The second argument to the macro is the name of the variable. If
|
||||
// the expression is false, most compilers will issue a warning/error
|
||||
// containing the name of the variable.
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <bool>
|
||||
struct CompileAssert {
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
#define GOOGLE_COMPILE_ASSERT(expr, msg) static_assert(expr, #msg)
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_MACROS_H__
|
||||
769
ubuntu/google/protobuf/stubs/map_util.h
Normal file
769
ubuntu/google/protobuf/stubs/map_util.h
Normal file
@@ -0,0 +1,769 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// from google3/util/gtl/map_util.h
|
||||
// Author: Anton Carver
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
// Local implementation of RemoveConst to avoid including base/type_traits.h.
|
||||
template <class T> struct RemoveConst { typedef T type; };
|
||||
template <class T> struct RemoveConst<const T> : RemoveConst<T> {};
|
||||
} // namespace internal
|
||||
|
||||
//
|
||||
// Find*()
|
||||
//
|
||||
|
||||
// Returns a const reference to the value associated with the given key if it
|
||||
// exists. Crashes otherwise.
|
||||
//
|
||||
// This is intended as a replacement for operator[] as an rvalue (for reading)
|
||||
// when the key is guaranteed to exist.
|
||||
//
|
||||
// operator[] for lookup is discouraged for several reasons:
|
||||
// * It has a side-effect of inserting missing keys
|
||||
// * It is not thread-safe (even when it is not inserting, it can still
|
||||
// choose to resize the underlying storage)
|
||||
// * It invalidates iterators (when it chooses to resize)
|
||||
// * It default constructs a value object even if it doesn't need to
|
||||
//
|
||||
// This version assumes the key is printable, and includes it in the fatal log
|
||||
// message.
|
||||
template <class Collection>
|
||||
const typename Collection::value_type::second_type&
|
||||
FindOrDie(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
GOOGLE_CHECK(it != collection.end()) << "Map key not found: " << key;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Same as above, but returns a non-const reference.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type&
|
||||
FindOrDie(Collection& collection, // NOLINT
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::iterator it = collection.find(key);
|
||||
GOOGLE_CHECK(it != collection.end()) << "Map key not found: " << key;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Same as FindOrDie above, but doesn't log the key on failure.
|
||||
template <class Collection>
|
||||
const typename Collection::value_type::second_type&
|
||||
FindOrDieNoPrint(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
GOOGLE_CHECK(it != collection.end()) << "Map key not found";
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Same as above, but returns a non-const reference.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type&
|
||||
FindOrDieNoPrint(Collection& collection, // NOLINT
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::iterator it = collection.find(key);
|
||||
GOOGLE_CHECK(it != collection.end()) << "Map key not found";
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Returns a const reference to the value associated with the given key if it
|
||||
// exists, otherwise returns a const reference to the provided default value.
|
||||
//
|
||||
// WARNING: If a temporary object is passed as the default "value,"
|
||||
// this function will return a reference to that temporary object,
|
||||
// which will be destroyed at the end of the statement. A common
|
||||
// example: if you have a map with string values, and you pass a char*
|
||||
// as the default "value," either use the returned value immediately
|
||||
// or store it in a string (not string&).
|
||||
// Details: http://go/findwithdefault
|
||||
template <class Collection>
|
||||
const typename Collection::value_type::second_type&
|
||||
FindWithDefault(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const typename Collection::value_type::second_type& value) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return value;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Returns a pointer to the const value associated with the given key if it
|
||||
// exists, or nullptr otherwise.
|
||||
template <class Collection>
|
||||
const typename Collection::value_type::second_type*
|
||||
FindOrNull(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return 0;
|
||||
}
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
// Same as above but returns a pointer to the non-const value.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type*
|
||||
FindOrNull(Collection& collection, // NOLINT
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return 0;
|
||||
}
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
// Returns the pointer value associated with the given key. If none is found,
|
||||
// nullptr is returned. The function is designed to be used with a map of keys to
|
||||
// pointers.
|
||||
//
|
||||
// This function does not distinguish between a missing key and a key mapped
|
||||
// to nullptr.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type
|
||||
FindPtrOrNull(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return typename Collection::value_type::second_type();
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Same as above, except takes non-const reference to collection.
|
||||
//
|
||||
// This function is needed for containers that propagate constness to the
|
||||
// pointee, such as boost::ptr_map.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type
|
||||
FindPtrOrNull(Collection& collection, // NOLINT
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return typename Collection::value_type::second_type();
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Finds the pointer value associated with the given key in a map whose values
|
||||
// are linked_ptrs. Returns nullptr if key is not found.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type::element_type*
|
||||
FindLinkedPtrOrNull(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return 0;
|
||||
}
|
||||
// Since linked_ptr::get() is a const member returning a non const,
|
||||
// we do not need a version of this function taking a non const collection.
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
// Same as above, but dies if the key is not found.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type::element_type&
|
||||
FindLinkedPtrOrDie(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
GOOGLE_CHECK(it != collection.end()) << "key not found: " << key;
|
||||
// Since linked_ptr::operator*() is a const member returning a non const,
|
||||
// we do not need a version of this function taking a non const collection.
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
// Finds the value associated with the given key and copies it to *value (if not
|
||||
// nullptr). Returns false if the key was not found, true otherwise.
|
||||
template <class Collection, class Key, class Value>
|
||||
bool FindCopy(const Collection& collection,
|
||||
const Key& key,
|
||||
Value* const value) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return false;
|
||||
}
|
||||
if (value) {
|
||||
*value = it->second;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Contains*()
|
||||
//
|
||||
|
||||
// Returns true if and only if the given collection contains the given key.
|
||||
template <class Collection, class Key>
|
||||
bool ContainsKey(const Collection& collection, const Key& key) {
|
||||
return collection.find(key) != collection.end();
|
||||
}
|
||||
|
||||
// Returns true if and only if the given collection contains the given key-value
|
||||
// pair.
|
||||
template <class Collection, class Key, class Value>
|
||||
bool ContainsKeyValuePair(const Collection& collection,
|
||||
const Key& key,
|
||||
const Value& value) {
|
||||
typedef typename Collection::const_iterator const_iterator;
|
||||
std::pair<const_iterator, const_iterator> range = collection.equal_range(key);
|
||||
for (const_iterator it = range.first; it != range.second; ++it) {
|
||||
if (it->second == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Insert*()
|
||||
//
|
||||
|
||||
// Inserts the given key-value pair into the collection. Returns true if and
|
||||
// only if the key from the given pair didn't previously exist. Otherwise, the
|
||||
// value in the map is replaced with the value from the given pair.
|
||||
template <class Collection>
|
||||
bool InsertOrUpdate(Collection* const collection,
|
||||
const typename Collection::value_type& vt) {
|
||||
std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
|
||||
if (!ret.second) {
|
||||
// update
|
||||
ret.first->second = vt.second;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Same as above, except that the key and value are passed separately.
|
||||
template <class Collection>
|
||||
bool InsertOrUpdate(Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const typename Collection::value_type::second_type& value) {
|
||||
return InsertOrUpdate(
|
||||
collection, typename Collection::value_type(key, value));
|
||||
}
|
||||
|
||||
// Inserts/updates all the key-value pairs from the range defined by the
|
||||
// iterators "first" and "last" into the given collection.
|
||||
template <class Collection, class InputIterator>
|
||||
void InsertOrUpdateMany(Collection* const collection,
|
||||
InputIterator first, InputIterator last) {
|
||||
for (; first != last; ++first) {
|
||||
InsertOrUpdate(collection, *first);
|
||||
}
|
||||
}
|
||||
|
||||
// Change the value associated with a particular key in a map or hash_map
|
||||
// of the form map<Key, Value*> which owns the objects pointed to by the
|
||||
// value pointers. If there was an existing value for the key, it is deleted.
|
||||
// True indicates an insert took place, false indicates an update + delete.
|
||||
template <class Collection>
|
||||
bool InsertAndDeleteExisting(
|
||||
Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const typename Collection::value_type::second_type& value) {
|
||||
std::pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(key, value));
|
||||
if (!ret.second) {
|
||||
delete ret.first->second;
|
||||
ret.first->second = value;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Inserts the given key and value into the given collection if and only if the
|
||||
// given key did NOT already exist in the collection. If the key previously
|
||||
// existed in the collection, the value is not changed. Returns true if the
|
||||
// key-value pair was inserted; returns false if the key was already present.
|
||||
template <class Collection>
|
||||
bool InsertIfNotPresent(Collection* const collection,
|
||||
const typename Collection::value_type& vt) {
|
||||
return collection->insert(vt).second;
|
||||
}
|
||||
|
||||
// Same as above except the key and value are passed separately.
|
||||
template <class Collection>
|
||||
bool InsertIfNotPresent(
|
||||
Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const typename Collection::value_type::second_type& value) {
|
||||
return InsertIfNotPresent(
|
||||
collection, typename Collection::value_type(key, value));
|
||||
}
|
||||
|
||||
// Same as above except dies if the key already exists in the collection.
|
||||
template <class Collection>
|
||||
void InsertOrDie(Collection* const collection,
|
||||
const typename Collection::value_type& value) {
|
||||
GOOGLE_CHECK(InsertIfNotPresent(collection, value))
|
||||
<< "duplicate value: " << value;
|
||||
}
|
||||
|
||||
// Same as above except doesn't log the value on error.
|
||||
template <class Collection>
|
||||
void InsertOrDieNoPrint(Collection* const collection,
|
||||
const typename Collection::value_type& value) {
|
||||
GOOGLE_CHECK(InsertIfNotPresent(collection, value)) << "duplicate value.";
|
||||
}
|
||||
|
||||
// Inserts the key-value pair into the collection. Dies if key was already
|
||||
// present.
|
||||
template <class Collection>
|
||||
void InsertOrDie(Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const typename Collection::value_type::second_type& data) {
|
||||
GOOGLE_CHECK(InsertIfNotPresent(collection, key, data))
|
||||
<< "duplicate key: " << key;
|
||||
}
|
||||
|
||||
// Same as above except doesn't log the key on error.
|
||||
template <class Collection>
|
||||
void InsertOrDieNoPrint(
|
||||
Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const typename Collection::value_type::second_type& data) {
|
||||
GOOGLE_CHECK(InsertIfNotPresent(collection, key, data)) << "duplicate key.";
|
||||
}
|
||||
|
||||
// Inserts a new key and default-initialized value. Dies if the key was already
|
||||
// present. Returns a reference to the value. Example usage:
|
||||
//
|
||||
// map<int, SomeProto> m;
|
||||
// SomeProto& proto = InsertKeyOrDie(&m, 3);
|
||||
// proto.set_field("foo");
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type& InsertKeyOrDie(
|
||||
Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typedef typename Collection::value_type value_type;
|
||||
std::pair<typename Collection::iterator, bool> res =
|
||||
collection->insert(value_type(key, typename value_type::second_type()));
|
||||
GOOGLE_CHECK(res.second) << "duplicate key: " << key;
|
||||
return res.first->second;
|
||||
}
|
||||
|
||||
//
|
||||
// Lookup*()
|
||||
//
|
||||
|
||||
// Looks up a given key and value pair in a collection and inserts the key-value
|
||||
// pair if it's not already present. Returns a reference to the value associated
|
||||
// with the key.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type&
|
||||
LookupOrInsert(Collection* const collection,
|
||||
const typename Collection::value_type& vt) {
|
||||
return collection->insert(vt).first->second;
|
||||
}
|
||||
|
||||
// Same as above except the key-value are passed separately.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type&
|
||||
LookupOrInsert(Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const typename Collection::value_type::second_type& value) {
|
||||
return LookupOrInsert(
|
||||
collection, typename Collection::value_type(key, value));
|
||||
}
|
||||
|
||||
// Counts the number of equivalent elements in the given "sequence", and stores
|
||||
// the results in "count_map" with element as the key and count as the value.
|
||||
//
|
||||
// Example:
|
||||
// vector<string> v = {"a", "b", "c", "a", "b"};
|
||||
// map<string, int> m;
|
||||
// AddTokenCounts(v, 1, &m);
|
||||
// assert(m["a"] == 2);
|
||||
// assert(m["b"] == 2);
|
||||
// assert(m["c"] == 1);
|
||||
template <typename Sequence, typename Collection>
|
||||
void AddTokenCounts(
|
||||
const Sequence& sequence,
|
||||
const typename Collection::value_type::second_type& increment,
|
||||
Collection* const count_map) {
|
||||
for (typename Sequence::const_iterator it = sequence.begin();
|
||||
it != sequence.end(); ++it) {
|
||||
typename Collection::value_type::second_type& value =
|
||||
LookupOrInsert(count_map, *it,
|
||||
typename Collection::value_type::second_type());
|
||||
value += increment;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a reference to the value associated with key. If not found, a value
|
||||
// is default constructed on the heap and added to the map.
|
||||
//
|
||||
// This function is useful for containers of the form map<Key, Value*>, where
|
||||
// inserting a new key, value pair involves constructing a new heap-allocated
|
||||
// Value, and storing a pointer to that in the collection.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type&
|
||||
LookupOrInsertNew(Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typedef typename std::iterator_traits<
|
||||
typename Collection::value_type::second_type>::value_type Element;
|
||||
std::pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(
|
||||
key,
|
||||
static_cast<typename Collection::value_type::second_type>(nullptr)));
|
||||
if (ret.second) {
|
||||
ret.first->second = new Element();
|
||||
}
|
||||
return ret.first->second;
|
||||
}
|
||||
|
||||
// Same as above but constructs the value using the single-argument constructor
|
||||
// and the given "arg".
|
||||
template <class Collection, class Arg>
|
||||
typename Collection::value_type::second_type&
|
||||
LookupOrInsertNew(Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const Arg& arg) {
|
||||
typedef typename std::iterator_traits<
|
||||
typename Collection::value_type::second_type>::value_type Element;
|
||||
std::pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(
|
||||
key,
|
||||
static_cast<typename Collection::value_type::second_type>(nullptr)));
|
||||
if (ret.second) {
|
||||
ret.first->second = new Element(arg);
|
||||
}
|
||||
return ret.first->second;
|
||||
}
|
||||
|
||||
// Lookup of linked/shared pointers is used in two scenarios:
|
||||
//
|
||||
// Use LookupOrInsertNewLinkedPtr if the container owns the elements.
|
||||
// In this case it is fine working with the raw pointer as long as it is
|
||||
// guaranteed that no other thread can delete/update an accessed element.
|
||||
// A mutex will need to lock the container operation as well as the use
|
||||
// of the returned elements. Finding an element may be performed using
|
||||
// FindLinkedPtr*().
|
||||
//
|
||||
// Use LookupOrInsertNewSharedPtr if the container does not own the elements
|
||||
// for their whole lifetime. This is typically the case when a reader allows
|
||||
// parallel updates to the container. In this case a Mutex only needs to lock
|
||||
// container operations, but all element operations must be performed on the
|
||||
// shared pointer. Finding an element must be performed using FindPtr*() and
|
||||
// cannot be done with FindLinkedPtr*() even though it compiles.
|
||||
|
||||
// Lookup a key in a map or hash_map whose values are linked_ptrs. If it is
|
||||
// missing, set collection[key].reset(new Value::element_type) and return that.
|
||||
// Value::element_type must be default constructable.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type::element_type*
|
||||
LookupOrInsertNewLinkedPtr(
|
||||
Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typedef typename Collection::value_type::second_type Value;
|
||||
std::pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(key, Value()));
|
||||
if (ret.second) {
|
||||
ret.first->second.reset(new typename Value::element_type);
|
||||
}
|
||||
return ret.first->second.get();
|
||||
}
|
||||
|
||||
// A variant of LookupOrInsertNewLinkedPtr where the value is constructed using
|
||||
// a single-parameter constructor. Note: the constructor argument is computed
|
||||
// even if it will not be used, so only values cheap to compute should be passed
|
||||
// here. On the other hand it does not matter how expensive the construction of
|
||||
// the actual stored value is, as that only occurs if necessary.
|
||||
template <class Collection, class Arg>
|
||||
typename Collection::value_type::second_type::element_type*
|
||||
LookupOrInsertNewLinkedPtr(
|
||||
Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const Arg& arg) {
|
||||
typedef typename Collection::value_type::second_type Value;
|
||||
std::pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(key, Value()));
|
||||
if (ret.second) {
|
||||
ret.first->second.reset(new typename Value::element_type(arg));
|
||||
}
|
||||
return ret.first->second.get();
|
||||
}
|
||||
|
||||
// Lookup a key in a map or hash_map whose values are shared_ptrs. If it is
|
||||
// missing, set collection[key].reset(new Value::element_type). Unlike
|
||||
// LookupOrInsertNewLinkedPtr, this function returns the shared_ptr instead of
|
||||
// the raw pointer. Value::element_type must be default constructable.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type&
|
||||
LookupOrInsertNewSharedPtr(
|
||||
Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typedef typename Collection::value_type::second_type SharedPtr;
|
||||
typedef typename Collection::value_type::second_type::element_type Element;
|
||||
std::pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(key, SharedPtr()));
|
||||
if (ret.second) {
|
||||
ret.first->second.reset(new Element());
|
||||
}
|
||||
return ret.first->second;
|
||||
}
|
||||
|
||||
// A variant of LookupOrInsertNewSharedPtr where the value is constructed using
|
||||
// a single-parameter constructor. Note: the constructor argument is computed
|
||||
// even if it will not be used, so only values cheap to compute should be passed
|
||||
// here. On the other hand it does not matter how expensive the construction of
|
||||
// the actual stored value is, as that only occurs if necessary.
|
||||
template <class Collection, class Arg>
|
||||
typename Collection::value_type::second_type&
|
||||
LookupOrInsertNewSharedPtr(
|
||||
Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const Arg& arg) {
|
||||
typedef typename Collection::value_type::second_type SharedPtr;
|
||||
typedef typename Collection::value_type::second_type::element_type Element;
|
||||
std::pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(key, SharedPtr()));
|
||||
if (ret.second) {
|
||||
ret.first->second.reset(new Element(arg));
|
||||
}
|
||||
return ret.first->second;
|
||||
}
|
||||
|
||||
//
|
||||
// Misc Utility Functions
|
||||
//
|
||||
|
||||
// Updates the value associated with the given key. If the key was not already
|
||||
// present, then the key-value pair are inserted and "previous" is unchanged. If
|
||||
// the key was already present, the value is updated and "*previous" will
|
||||
// contain a copy of the old value.
|
||||
//
|
||||
// InsertOrReturnExisting has complementary behavior that returns the
|
||||
// address of an already existing value, rather than updating it.
|
||||
template <class Collection>
|
||||
bool UpdateReturnCopy(Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const typename Collection::value_type::second_type& value,
|
||||
typename Collection::value_type::second_type* previous) {
|
||||
std::pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(key, value));
|
||||
if (!ret.second) {
|
||||
// update
|
||||
if (previous) {
|
||||
*previous = ret.first->second;
|
||||
}
|
||||
ret.first->second = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Same as above except that the key and value are passed as a pair.
|
||||
template <class Collection>
|
||||
bool UpdateReturnCopy(Collection* const collection,
|
||||
const typename Collection::value_type& vt,
|
||||
typename Collection::value_type::second_type* previous) {
|
||||
std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
|
||||
if (!ret.second) {
|
||||
// update
|
||||
if (previous) {
|
||||
*previous = ret.first->second;
|
||||
}
|
||||
ret.first->second = vt.second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Tries to insert the given key-value pair into the collection. Returns nullptr if
|
||||
// the insert succeeds. Otherwise, returns a pointer to the existing value.
|
||||
//
|
||||
// This complements UpdateReturnCopy in that it allows to update only after
|
||||
// verifying the old value and still insert quickly without having to look up
|
||||
// twice. Unlike UpdateReturnCopy this also does not come with the issue of an
|
||||
// undefined previous* in case new data was inserted.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type* InsertOrReturnExisting(
|
||||
Collection* const collection, const typename Collection::value_type& vt) {
|
||||
std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
|
||||
if (ret.second) {
|
||||
return nullptr; // Inserted, no existing previous value.
|
||||
} else {
|
||||
return &ret.first->second; // Return address of already existing value.
|
||||
}
|
||||
}
|
||||
|
||||
// Same as above, except for explicit key and data.
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type* InsertOrReturnExisting(
|
||||
Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const typename Collection::value_type::second_type& data) {
|
||||
return InsertOrReturnExisting(collection,
|
||||
typename Collection::value_type(key, data));
|
||||
}
|
||||
|
||||
// Erases the collection item identified by the given key, and returns the value
|
||||
// associated with that key. It is assumed that the value (i.e., the
|
||||
// mapped_type) is a pointer. Returns nullptr if the key was not found in the
|
||||
// collection.
|
||||
//
|
||||
// Examples:
|
||||
// map<string, MyType*> my_map;
|
||||
//
|
||||
// One line cleanup:
|
||||
// delete EraseKeyReturnValuePtr(&my_map, "abc");
|
||||
//
|
||||
// Use returned value:
|
||||
// std::unique_ptr<MyType> value_ptr(
|
||||
// EraseKeyReturnValuePtr(&my_map, "abc"));
|
||||
// if (value_ptr.get())
|
||||
// value_ptr->DoSomething();
|
||||
//
|
||||
template <class Collection>
|
||||
typename Collection::value_type::second_type EraseKeyReturnValuePtr(
|
||||
Collection* const collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::iterator it = collection->find(key);
|
||||
if (it == collection->end()) {
|
||||
return nullptr;
|
||||
}
|
||||
typename Collection::value_type::second_type v = it->second;
|
||||
collection->erase(it);
|
||||
return v;
|
||||
}
|
||||
|
||||
// Inserts all the keys from map_container into key_container, which must
|
||||
// support insert(MapContainer::key_type).
|
||||
//
|
||||
// Note: any initial contents of the key_container are not cleared.
|
||||
template <class MapContainer, class KeyContainer>
|
||||
void InsertKeysFromMap(const MapContainer& map_container,
|
||||
KeyContainer* key_container) {
|
||||
GOOGLE_CHECK(key_container != nullptr);
|
||||
for (typename MapContainer::const_iterator it = map_container.begin();
|
||||
it != map_container.end(); ++it) {
|
||||
key_container->insert(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
// Appends all the keys from map_container into key_container, which must
|
||||
// support push_back(MapContainer::key_type).
|
||||
//
|
||||
// Note: any initial contents of the key_container are not cleared.
|
||||
template <class MapContainer, class KeyContainer>
|
||||
void AppendKeysFromMap(const MapContainer& map_container,
|
||||
KeyContainer* key_container) {
|
||||
GOOGLE_CHECK(key_container != nullptr);
|
||||
for (typename MapContainer::const_iterator it = map_container.begin();
|
||||
it != map_container.end(); ++it) {
|
||||
key_container->push_back(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
// A more specialized overload of AppendKeysFromMap to optimize reallocations
|
||||
// for the common case in which we're appending keys to a vector and hence can
|
||||
// (and sometimes should) call reserve() first.
|
||||
//
|
||||
// (It would be possible to play SFINAE games to call reserve() for any
|
||||
// container that supports it, but this seems to get us 99% of what we need
|
||||
// without the complexity of a SFINAE-based solution.)
|
||||
template <class MapContainer, class KeyType>
|
||||
void AppendKeysFromMap(const MapContainer& map_container,
|
||||
std::vector<KeyType>* key_container) {
|
||||
GOOGLE_CHECK(key_container != nullptr);
|
||||
// We now have the opportunity to call reserve(). Calling reserve() every
|
||||
// time is a bad idea for some use cases: libstdc++'s implementation of
|
||||
// vector<>::reserve() resizes the vector's backing store to exactly the
|
||||
// given size (unless it's already at least that big). Because of this,
|
||||
// the use case that involves appending a lot of small maps (total size
|
||||
// N) one by one to a vector would be O(N^2). But never calling reserve()
|
||||
// loses the opportunity to improve the use case of adding from a large
|
||||
// map to an empty vector (this improves performance by up to 33%). A
|
||||
// number of heuristics are possible; see the discussion in
|
||||
// cl/34081696. Here we use the simplest one.
|
||||
if (key_container->empty()) {
|
||||
key_container->reserve(map_container.size());
|
||||
}
|
||||
for (typename MapContainer::const_iterator it = map_container.begin();
|
||||
it != map_container.end(); ++it) {
|
||||
key_container->push_back(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
// Inserts all the values from map_container into value_container, which must
|
||||
// support push_back(MapContainer::mapped_type).
|
||||
//
|
||||
// Note: any initial contents of the value_container are not cleared.
|
||||
template <class MapContainer, class ValueContainer>
|
||||
void AppendValuesFromMap(const MapContainer& map_container,
|
||||
ValueContainer* value_container) {
|
||||
GOOGLE_CHECK(value_container != nullptr);
|
||||
for (typename MapContainer::const_iterator it = map_container.begin();
|
||||
it != map_container.end(); ++it) {
|
||||
value_container->push_back(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
// A more specialized overload of AppendValuesFromMap to optimize reallocations
|
||||
// for the common case in which we're appending values to a vector and hence
|
||||
// can (and sometimes should) call reserve() first.
|
||||
//
|
||||
// (It would be possible to play SFINAE games to call reserve() for any
|
||||
// container that supports it, but this seems to get us 99% of what we need
|
||||
// without the complexity of a SFINAE-based solution.)
|
||||
template <class MapContainer, class ValueType>
|
||||
void AppendValuesFromMap(const MapContainer& map_container,
|
||||
std::vector<ValueType>* value_container) {
|
||||
GOOGLE_CHECK(value_container != nullptr);
|
||||
// See AppendKeysFromMap for why this is done.
|
||||
if (value_container->empty()) {
|
||||
value_container->reserve(map_container.size());
|
||||
}
|
||||
for (typename MapContainer::const_iterator it = map_container.begin();
|
||||
it != map_container.end(); ++it) {
|
||||
value_container->push_back(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
|
||||
162
ubuntu/google/protobuf/stubs/mathutil.h
Normal file
162
ubuntu/google/protobuf/stubs/mathutil.h
Normal file
@@ -0,0 +1,162 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_MATHUTIL_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_MATHUTIL_H_
|
||||
|
||||
#include <cmath>
|
||||
#include <float.h>
|
||||
#include <limits>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/logging.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Like std::make_unsigned_t except floating point types map to themselves.
|
||||
template <typename T>
|
||||
using MakeUnsignedT =
|
||||
typename std::conditional<std::is_integral<T>::value, std::make_unsigned<T>,
|
||||
std::common_type<T>>::type::type;
|
||||
|
||||
// Like std::isnan() except a template function that is defined for all numeric
|
||||
// types.
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
|
||||
bool IsNan(T val) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
|
||||
int>::type = 0>
|
||||
bool IsNan(T val) {
|
||||
return std::isnan(val);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool AlmostEquals(T a, T b) {
|
||||
return a == b;
|
||||
}
|
||||
template<>
|
||||
inline bool AlmostEquals(float a, float b) {
|
||||
return fabs(a - b) < 32 * FLT_EPSILON;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool AlmostEquals(double a, double b) {
|
||||
return fabs(a - b) < 32 * DBL_EPSILON;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
class MathUtil {
|
||||
public:
|
||||
template <typename T>
|
||||
static T Sign(T value) {
|
||||
if (value == T(0) || internal::IsNan(value)) {
|
||||
return value;
|
||||
}
|
||||
return value > T(0) ? 1 : -1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool AlmostEquals(T a, T b) {
|
||||
return internal::AlmostEquals(a, b);
|
||||
}
|
||||
|
||||
// Largest of two values.
|
||||
// Works correctly for special floating point values.
|
||||
// Note: 0.0 and -0.0 are not differentiated by Max (Max(0.0, -0.0) is -0.0),
|
||||
// which should be OK because, although they (can) have different
|
||||
// bit representation, they are observably the same when examined
|
||||
// with arithmetic and (in)equality operators.
|
||||
template <typename T>
|
||||
static T Max(const T x, const T y) {
|
||||
return internal::IsNan(x) || x > y ? x : y;
|
||||
}
|
||||
|
||||
// Absolute value of x
|
||||
// Works correctly for unsigned types and
|
||||
// for special floating point values.
|
||||
// Note: 0.0 and -0.0 are not differentiated by Abs (Abs(0.0) is -0.0),
|
||||
// which should be OK: see the comment for Max above.
|
||||
template<typename T>
|
||||
static T Abs(const T x) {
|
||||
return x > T(0) ? x : -x;
|
||||
}
|
||||
|
||||
// Absolute value of the difference between two numbers.
|
||||
// Works correctly for signed types and special floating point values.
|
||||
template <typename T>
|
||||
static typename internal::MakeUnsignedT<T> AbsDiff(const T x, const T y) {
|
||||
// Carries out arithmetic as unsigned to avoid overflow.
|
||||
typedef typename internal::MakeUnsignedT<T> R;
|
||||
return x > y ? R(x) - R(y) : R(y) - R(x);
|
||||
}
|
||||
|
||||
// If two (usually floating point) numbers are within a certain
|
||||
// fraction of their magnitude or within a certain absolute margin of error.
|
||||
// This is the same as the following but faster:
|
||||
// WithinFraction(x, y, fraction) || WithinMargin(x, y, margin)
|
||||
// E.g. WithinFraction(0.0, 1e-10, 1e-5) is false but
|
||||
// WithinFractionOrMargin(0.0, 1e-10, 1e-5, 1e-5) is true.
|
||||
template<typename T>
|
||||
static bool WithinFractionOrMargin(const T x, const T y,
|
||||
const T fraction, const T margin);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool MathUtil::WithinFractionOrMargin(const T x, const T y,
|
||||
const T fraction, const T margin) {
|
||||
// Not just "0 <= fraction" to fool the compiler for unsigned types.
|
||||
GOOGLE_DCHECK((T(0) < fraction || T(0) == fraction) &&
|
||||
fraction < T(1) &&
|
||||
margin >= T(0));
|
||||
|
||||
// Template specialization will convert the if() condition to a constant,
|
||||
// which will cause the compiler to generate code for either the "if" part
|
||||
// or the "then" part. In this way we avoid a compiler warning
|
||||
// about a potential integer overflow in crosstool v12 (gcc 4.3.1).
|
||||
if (std::numeric_limits<T>::is_integer) {
|
||||
return x == y;
|
||||
} else {
|
||||
if (!std::isfinite(x) || !std::isfinite(y)) {
|
||||
return false;
|
||||
}
|
||||
T relative_margin = static_cast<T>(fraction * Max(Abs(x), Abs(y)));
|
||||
return AbsDiff(x, y) <= Max(margin, relative_margin);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_MATHUTIL_H_
|
||||
186
ubuntu/google/protobuf/stubs/mutex.h
Normal file
186
ubuntu/google/protobuf/stubs/mutex.h
Normal file
@@ -0,0 +1,186 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_MUTEX_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_MUTEX_H_
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#ifdef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// GetMessage conflicts with GeneratedMessageReflection::GetMessage().
|
||||
#ifdef GetMessage
|
||||
#undef GetMessage
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/stubs/macros.h>
|
||||
|
||||
// Define thread-safety annotations for use below, if we are building with
|
||||
// Clang.
|
||||
#if defined(__clang__) && !defined(SWIG)
|
||||
#define GOOGLE_PROTOBUF_ACQUIRE(...) \
|
||||
__attribute__((acquire_capability(__VA_ARGS__)))
|
||||
#define GOOGLE_PROTOBUF_RELEASE(...) \
|
||||
__attribute__((release_capability(__VA_ARGS__)))
|
||||
#define GOOGLE_PROTOBUF_CAPABILITY(x) __attribute__((capability(x)))
|
||||
#else
|
||||
#define GOOGLE_PROTOBUF_ACQUIRE(...)
|
||||
#define GOOGLE_PROTOBUF_RELEASE(...)
|
||||
#define GOOGLE_PROTOBUF_CAPABILITY(x)
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
// ===================================================================
|
||||
// emulates google3/base/mutex.h
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
#define GOOGLE_PROTOBUF_LINKER_INITIALIZED
|
||||
|
||||
#ifdef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
|
||||
|
||||
// This class is a lightweight replacement for std::mutex on Windows platforms.
|
||||
// std::mutex does not work on Windows XP SP2 with the latest VC++ libraries,
|
||||
// because it utilizes the Concurrency Runtime that is only supported on Windows
|
||||
// XP SP3 and above.
|
||||
class PROTOBUF_EXPORT CriticalSectionLock {
|
||||
public:
|
||||
CriticalSectionLock() { InitializeCriticalSection(&critical_section_); }
|
||||
~CriticalSectionLock() { DeleteCriticalSection(&critical_section_); }
|
||||
void lock() { EnterCriticalSection(&critical_section_); }
|
||||
void unlock() { LeaveCriticalSection(&critical_section_); }
|
||||
|
||||
private:
|
||||
CRITICAL_SECTION critical_section_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CriticalSectionLock);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// Mutex is a natural type to wrap. As both google and other organization have
|
||||
// specialized mutexes. gRPC also provides an injection mechanism for custom
|
||||
// mutexes.
|
||||
class GOOGLE_PROTOBUF_CAPABILITY("mutex") PROTOBUF_EXPORT WrappedMutex {
|
||||
public:
|
||||
WrappedMutex() = default;
|
||||
void Lock() GOOGLE_PROTOBUF_ACQUIRE() { mu_.lock(); }
|
||||
void Unlock() GOOGLE_PROTOBUF_RELEASE() { mu_.unlock(); }
|
||||
// Crash if this Mutex is not held exclusively by this thread.
|
||||
// May fail to crash when it should; will never crash when it should not.
|
||||
void AssertHeld() const {}
|
||||
|
||||
private:
|
||||
#ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
|
||||
std::mutex mu_;
|
||||
#else // ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
|
||||
CriticalSectionLock mu_;
|
||||
#endif // #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
|
||||
};
|
||||
|
||||
using Mutex = WrappedMutex;
|
||||
|
||||
// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
|
||||
class PROTOBUF_EXPORT MutexLock {
|
||||
public:
|
||||
explicit MutexLock(Mutex *mu) : mu_(mu) { this->mu_->Lock(); }
|
||||
~MutexLock() { this->mu_->Unlock(); }
|
||||
private:
|
||||
Mutex *const mu_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock);
|
||||
};
|
||||
|
||||
// TODO(kenton): Implement these? Hard to implement portably.
|
||||
typedef MutexLock ReaderMutexLock;
|
||||
typedef MutexLock WriterMutexLock;
|
||||
|
||||
// MutexLockMaybe is like MutexLock, but is a no-op when mu is nullptr.
|
||||
class PROTOBUF_EXPORT MutexLockMaybe {
|
||||
public:
|
||||
explicit MutexLockMaybe(Mutex *mu) :
|
||||
mu_(mu) { if (this->mu_ != nullptr) { this->mu_->Lock(); } }
|
||||
~MutexLockMaybe() { if (this->mu_ != nullptr) { this->mu_->Unlock(); } }
|
||||
private:
|
||||
Mutex *const mu_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe);
|
||||
};
|
||||
|
||||
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
|
||||
template<typename T>
|
||||
class ThreadLocalStorage {
|
||||
public:
|
||||
ThreadLocalStorage() {
|
||||
pthread_key_create(&key_, &ThreadLocalStorage::Delete);
|
||||
}
|
||||
~ThreadLocalStorage() {
|
||||
pthread_key_delete(key_);
|
||||
}
|
||||
T* Get() {
|
||||
T* result = static_cast<T*>(pthread_getspecific(key_));
|
||||
if (result == nullptr) {
|
||||
result = new T();
|
||||
pthread_setspecific(key_, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private:
|
||||
static void Delete(void* value) {
|
||||
delete static_cast<T*>(value);
|
||||
}
|
||||
pthread_key_t key_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadLocalStorage);
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// We made these internal so that they would show up as such in the docs,
|
||||
// but we don't want to stick "internal::" in front of them everywhere.
|
||||
using internal::Mutex;
|
||||
using internal::MutexLock;
|
||||
using internal::ReaderMutexLock;
|
||||
using internal::WriterMutexLock;
|
||||
using internal::MutexLockMaybe;
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#undef GOOGLE_PROTOBUF_ACQUIRE
|
||||
#undef GOOGLE_PROTOBUF_RELEASE
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_MUTEX_H_
|
||||
55
ubuntu/google/protobuf/stubs/once.h
Normal file
55
ubuntu/google/protobuf/stubs/once.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_ONCE_H__
|
||||
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
using once_flag = std::once_flag;
|
||||
template <typename... Args>
|
||||
void call_once(Args&&... args ) {
|
||||
std::call_once(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_ONCE_H__
|
||||
134
ubuntu/google/protobuf/stubs/platform_macros.h
Normal file
134
ubuntu/google/protobuf/stubs/platform_macros.h
Normal file
@@ -0,0 +1,134 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2012 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
|
||||
#define GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
|
||||
|
||||
#define GOOGLE_PROTOBUF_PLATFORM_ERROR \
|
||||
#error "Host platform was not detected as supported by protobuf"
|
||||
|
||||
// Processor architecture detection. For more info on what's defined, see:
|
||||
// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
|
||||
// http://www.agner.org/optimize/calling_conventions.pdf
|
||||
// or with gcc, run: "echo | gcc -E -dM -"
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define GOOGLE_PROTOBUF_ARCH_X64 1
|
||||
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
|
||||
#elif defined(_M_IX86) || defined(__i386__)
|
||||
#define GOOGLE_PROTOBUF_ARCH_IA32 1
|
||||
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
|
||||
#elif defined(__QNX__)
|
||||
#define GOOGLE_PROTOBUF_ARCH_ARM_QNX 1
|
||||
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
|
||||
#elif defined(_M_ARM) || defined(__ARMEL__)
|
||||
#define GOOGLE_PROTOBUF_ARCH_ARM 1
|
||||
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
|
||||
#elif defined(_M_ARM64)
|
||||
#define GOOGLE_PROTOBUF_ARCH_ARM 1
|
||||
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
|
||||
#elif defined(__aarch64__)
|
||||
#define GOOGLE_PROTOBUF_ARCH_AARCH64 1
|
||||
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
|
||||
#elif defined(__mips__)
|
||||
#if defined(__LP64__)
|
||||
#define GOOGLE_PROTOBUF_ARCH_MIPS64 1
|
||||
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
|
||||
#else
|
||||
#define GOOGLE_PROTOBUF_ARCH_MIPS 1
|
||||
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
|
||||
#endif
|
||||
#elif defined(__pnacl__)
|
||||
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
|
||||
#elif defined(sparc)
|
||||
#define GOOGLE_PROTOBUF_ARCH_SPARC 1
|
||||
#if defined(__sparc_v9__) || defined(__sparcv9) || defined(__arch64__)
|
||||
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
|
||||
#else
|
||||
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
|
||||
#endif
|
||||
#elif defined(_POWER) || defined(__powerpc64__) || defined(__PPC64__)
|
||||
#define GOOGLE_PROTOBUF_ARCH_POWER 1
|
||||
#define GOOGLE_PROTOBUF_ARCH_64_BIT 1
|
||||
#elif defined(__PPC__)
|
||||
#define GOOGLE_PROTOBUF_ARCH_PPC 1
|
||||
#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
|
||||
#elif defined(__GNUC__)
|
||||
# if (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))
|
||||
// We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h
|
||||
# elif defined(__clang__)
|
||||
# if !__has_extension(c_atomic)
|
||||
GOOGLE_PROTOBUF_PLATFORM_ERROR
|
||||
# endif
|
||||
// We fallback to the generic Clang/GCC >= 4.7 implementation in atomicops.h
|
||||
# endif
|
||||
# if __LP64__
|
||||
# define GOOGLE_PROTOBUF_ARCH_64_BIT 1
|
||||
# else
|
||||
# define GOOGLE_PROTOBUF_ARCH_32_BIT 1
|
||||
# endif
|
||||
#else
|
||||
GOOGLE_PROTOBUF_PLATFORM_ERROR
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define GOOGLE_PROTOBUF_OS_APPLE
|
||||
#include <Availability.h>
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_IPHONE
|
||||
#define GOOGLE_PROTOBUF_OS_IPHONE
|
||||
#endif
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#define GOOGLE_PROTOBUF_OS_EMSCRIPTEN
|
||||
#elif defined(__native_client__)
|
||||
#define GOOGLE_PROTOBUF_OS_NACL
|
||||
#elif defined(sun)
|
||||
#define GOOGLE_PROTOBUF_OS_SOLARIS
|
||||
#elif defined(_AIX)
|
||||
#define GOOGLE_PROTOBUF_OS_AIX
|
||||
#elif defined(__ANDROID__)
|
||||
#define GOOGLE_PROTOBUF_OS_ANDROID
|
||||
#endif
|
||||
|
||||
#undef GOOGLE_PROTOBUF_PLATFORM_ERROR
|
||||
|
||||
#if defined(GOOGLE_PROTOBUF_OS_ANDROID) || defined(GOOGLE_PROTOBUF_OS_IPHONE) || defined(__OpenBSD__)
|
||||
// Android ndk does not support the __thread keyword very well yet. Here
|
||||
// we use pthread_key_create()/pthread_getspecific()/... methods for
|
||||
// TLS support on android.
|
||||
// iOS and OpenBSD also do not support the __thread keyword.
|
||||
#define GOOGLE_PROTOBUF_NO_THREADLOCAL
|
||||
#endif
|
||||
|
||||
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1070
|
||||
// __thread keyword requires at least 10.7
|
||||
#define GOOGLE_PROTOBUF_NO_THREADLOCAL
|
||||
#endif
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_PLATFORM_MACROS_H_
|
||||
405
ubuntu/google/protobuf/stubs/port.h
Normal file
405
ubuntu/google/protobuf/stubs/port.h
Normal file
@@ -0,0 +1,405 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_PORT_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_PORT_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <cstdint>
|
||||
#include <stdlib.h>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
#include <google/protobuf/stubs/platform_macros.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
#undef PROTOBUF_LITTLE_ENDIAN
|
||||
#ifdef _WIN32
|
||||
// Assuming windows is always little-endian.
|
||||
// TODO(xiaofeng): The PROTOBUF_LITTLE_ENDIAN is not only used for
|
||||
// optimization but also for correctness. We should define an
|
||||
// different macro to test the big-endian code path in coded_stream.
|
||||
#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
|
||||
#define PROTOBUF_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1300 && !defined(__INTEL_COMPILER)
|
||||
// If MSVC has "/RTCc" set, it will complain about truncating casts at
|
||||
// runtime. This file contains some intentional truncating casts.
|
||||
#pragma runtime_checks("c", off)
|
||||
#endif
|
||||
#else
|
||||
#include <sys/param.h> // __BYTE_ORDER
|
||||
#if defined(__OpenBSD__)
|
||||
#include <endian.h>
|
||||
#endif
|
||||
#if ((defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) || \
|
||||
(defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || \
|
||||
(defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN)) && \
|
||||
!defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
|
||||
#define PROTOBUF_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// These #includes are for the byte swap functions declared later on.
|
||||
#ifdef _MSC_VER
|
||||
#include <stdlib.h> // NOLINT(build/include)
|
||||
#include <intrin.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#elif defined(__GLIBC__) || defined(__BIONIC__) || defined(__CYGWIN__)
|
||||
#include <byteswap.h> // IWYU pragma: export
|
||||
#endif
|
||||
|
||||
// Legacy: some users reference these (internal-only) macros even though we
|
||||
// don't need them any more.
|
||||
#if defined(_MSC_VER) && defined(PROTOBUF_USE_DLLS)
|
||||
#ifdef LIBPROTOBUF_EXPORTS
|
||||
#define LIBPROTOBUF_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define LIBPROTOBUF_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#ifdef LIBPROTOC_EXPORTS
|
||||
#define LIBPROTOC_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define LIBPROTOC_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define LIBPROTOBUF_EXPORT
|
||||
#define LIBPROTOC_EXPORT
|
||||
#endif
|
||||
|
||||
#define PROTOBUF_RUNTIME_DEPRECATED(message) PROTOBUF_DEPRECATED_MSG(message)
|
||||
#define GOOGLE_PROTOBUF_RUNTIME_DEPRECATED(message) \
|
||||
PROTOBUF_DEPRECATED_MSG(message)
|
||||
|
||||
// ===================================================================
|
||||
// from google3/base/port.h
|
||||
|
||||
#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \
|
||||
(defined(_MSC_VER) && _MSC_VER >= 1900))
|
||||
// Define this to 1 if the code is compiled in C++11 mode; leave it
|
||||
// undefined otherwise. Do NOT define it to 0 -- that causes
|
||||
// '#ifdef LANG_CXX11' to behave differently from '#if LANG_CXX11'.
|
||||
#define LANG_CXX11 1
|
||||
#else
|
||||
#error "Protobuf requires at least C++11."
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
using ConstStringParam = const std::string &;
|
||||
|
||||
typedef unsigned int uint;
|
||||
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
static const int32 kint32max = 0x7FFFFFFF;
|
||||
static const int32 kint32min = -kint32max - 1;
|
||||
static const int64 kint64max = PROTOBUF_LONGLONG(0x7FFFFFFFFFFFFFFF);
|
||||
static const int64 kint64min = -kint64max - 1;
|
||||
static const uint32 kuint32max = 0xFFFFFFFFu;
|
||||
static const uint64 kuint64max = PROTOBUF_ULONGLONG(0xFFFFFFFFFFFFFFFF);
|
||||
|
||||
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\
|
||||
defined(MEMORY_SANITIZER)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
uint16_t __sanitizer_unaligned_load16(const void *p);
|
||||
uint32_t __sanitizer_unaligned_load32(const void *p);
|
||||
uint64_t __sanitizer_unaligned_load64(const void *p);
|
||||
void __sanitizer_unaligned_store16(void *p, uint16_t v);
|
||||
void __sanitizer_unaligned_store32(void *p, uint32_t v);
|
||||
void __sanitizer_unaligned_store64(void *p, uint64_t v);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
inline uint16 GOOGLE_UNALIGNED_LOAD16(const void *p) {
|
||||
return __sanitizer_unaligned_load16(p);
|
||||
}
|
||||
|
||||
inline uint32 GOOGLE_UNALIGNED_LOAD32(const void *p) {
|
||||
return __sanitizer_unaligned_load32(p);
|
||||
}
|
||||
|
||||
inline uint64 GOOGLE_UNALIGNED_LOAD64(const void *p) {
|
||||
return __sanitizer_unaligned_load64(p);
|
||||
}
|
||||
|
||||
inline void GOOGLE_UNALIGNED_STORE16(void *p, uint16 v) {
|
||||
__sanitizer_unaligned_store16(p, v);
|
||||
}
|
||||
|
||||
inline void GOOGLE_UNALIGNED_STORE32(void *p, uint32 v) {
|
||||
__sanitizer_unaligned_store32(p, v);
|
||||
}
|
||||
|
||||
inline void GOOGLE_UNALIGNED_STORE64(void *p, uint64 v) {
|
||||
__sanitizer_unaligned_store64(p, v);
|
||||
}
|
||||
|
||||
#elif defined(GOOGLE_PROTOBUF_USE_UNALIGNED) && GOOGLE_PROTOBUF_USE_UNALIGNED
|
||||
|
||||
#define GOOGLE_UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16 *>(_p))
|
||||
#define GOOGLE_UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32 *>(_p))
|
||||
#define GOOGLE_UNALIGNED_LOAD64(_p) (*reinterpret_cast<const uint64 *>(_p))
|
||||
|
||||
#define GOOGLE_UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16 *>(_p) = (_val))
|
||||
#define GOOGLE_UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32 *>(_p) = (_val))
|
||||
#define GOOGLE_UNALIGNED_STORE64(_p, _val) (*reinterpret_cast<uint64 *>(_p) = (_val))
|
||||
|
||||
#else
|
||||
inline uint16 GOOGLE_UNALIGNED_LOAD16(const void *p) {
|
||||
uint16 t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
|
||||
inline uint32 GOOGLE_UNALIGNED_LOAD32(const void *p) {
|
||||
uint32 t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
|
||||
inline uint64 GOOGLE_UNALIGNED_LOAD64(const void *p) {
|
||||
uint64 t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
|
||||
inline void GOOGLE_UNALIGNED_STORE16(void *p, uint16 v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
|
||||
inline void GOOGLE_UNALIGNED_STORE32(void *p, uint32 v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
|
||||
inline void GOOGLE_UNALIGNED_STORE64(void *p, uint64 v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GOOGLE_PROTOBUF_OS_NACL) \
|
||||
|| (defined(__ANDROID__) && defined(__clang__) \
|
||||
&& (__clang_major__ == 3 && __clang_minor__ == 8) \
|
||||
&& (__clang_patchlevel__ < 275480))
|
||||
# define GOOGLE_PROTOBUF_USE_PORTABLE_LOG2
|
||||
#endif
|
||||
|
||||
// The following guarantees declaration of the byte swap functions.
|
||||
#ifdef _MSC_VER
|
||||
#define bswap_16(x) _byteswap_ushort(x)
|
||||
#define bswap_32(x) _byteswap_ulong(x)
|
||||
#define bswap_64(x) _byteswap_uint64(x)
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
// Mac OS X / Darwin features
|
||||
#define bswap_16(x) OSSwapInt16(x)
|
||||
#define bswap_32(x) OSSwapInt32(x)
|
||||
#define bswap_64(x) OSSwapInt64(x)
|
||||
|
||||
#elif !defined(__GLIBC__) && !defined(__BIONIC__) && !defined(__CYGWIN__)
|
||||
|
||||
#ifndef bswap_16
|
||||
static inline uint16 bswap_16(uint16 x) {
|
||||
return static_cast<uint16>(((x & 0xFF) << 8) | ((x & 0xFF00) >> 8));
|
||||
}
|
||||
#define bswap_16(x) bswap_16(x)
|
||||
#endif
|
||||
|
||||
#ifndef bswap_32
|
||||
static inline uint32 bswap_32(uint32 x) {
|
||||
return (((x & 0xFF) << 24) |
|
||||
((x & 0xFF00) << 8) |
|
||||
((x & 0xFF0000) >> 8) |
|
||||
((x & 0xFF000000) >> 24));
|
||||
}
|
||||
#define bswap_32(x) bswap_32(x)
|
||||
#endif
|
||||
|
||||
#ifndef bswap_64
|
||||
static inline uint64 bswap_64(uint64 x) {
|
||||
return (((x & PROTOBUF_ULONGLONG(0xFF)) << 56) |
|
||||
((x & PROTOBUF_ULONGLONG(0xFF00)) << 40) |
|
||||
((x & PROTOBUF_ULONGLONG(0xFF0000)) << 24) |
|
||||
((x & PROTOBUF_ULONGLONG(0xFF000000)) << 8) |
|
||||
((x & PROTOBUF_ULONGLONG(0xFF00000000)) >> 8) |
|
||||
((x & PROTOBUF_ULONGLONG(0xFF0000000000)) >> 24) |
|
||||
((x & PROTOBUF_ULONGLONG(0xFF000000000000)) >> 40) |
|
||||
((x & PROTOBUF_ULONGLONG(0xFF00000000000000)) >> 56));
|
||||
}
|
||||
#define bswap_64(x) bswap_64(x)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// ===================================================================
|
||||
// from google3/util/bits/bits.h
|
||||
|
||||
class Bits {
|
||||
public:
|
||||
static uint32 Log2FloorNonZero(uint32 n) {
|
||||
#if defined(__GNUC__)
|
||||
return 31 ^ static_cast<uint32>(__builtin_clz(n));
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long where;
|
||||
_BitScanReverse(&where, n);
|
||||
return where;
|
||||
#else
|
||||
return Log2FloorNonZero_Portable(n);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32 Log2FloorNonZero64(uint64 n) {
|
||||
// Older versions of clang run into an instruction-selection failure when
|
||||
// it encounters __builtin_clzll:
|
||||
// https://bugs.chromium.org/p/nativeclient/issues/detail?id=4395
|
||||
// This includes arm-nacl-clang and clang in older Android NDK versions.
|
||||
// To work around this, when we build with those we use the portable
|
||||
// implementation instead.
|
||||
#if defined(__GNUC__) && !defined(GOOGLE_PROTOBUF_USE_PORTABLE_LOG2)
|
||||
return 63 ^ static_cast<uint32>(__builtin_clzll(n));
|
||||
#elif defined(_MSC_VER) && defined(_M_X64)
|
||||
unsigned long where;
|
||||
_BitScanReverse64(&where, n);
|
||||
return where;
|
||||
#else
|
||||
return Log2FloorNonZero64_Portable(n);
|
||||
#endif
|
||||
}
|
||||
private:
|
||||
static int Log2FloorNonZero_Portable(uint32 n) {
|
||||
if (n == 0)
|
||||
return -1;
|
||||
int log = 0;
|
||||
uint32 value = n;
|
||||
for (int i = 4; i >= 0; --i) {
|
||||
int shift = (1 << i);
|
||||
uint32 x = value >> shift;
|
||||
if (x != 0) {
|
||||
value = x;
|
||||
log += shift;
|
||||
}
|
||||
}
|
||||
assert(value == 1);
|
||||
return log;
|
||||
}
|
||||
|
||||
static int Log2FloorNonZero64_Portable(uint64 n) {
|
||||
const uint32 topbits = static_cast<uint32>(n >> 32);
|
||||
if (topbits == 0) {
|
||||
// Top bits are zero, so scan in bottom bits
|
||||
return static_cast<int>(Log2FloorNonZero(static_cast<uint32>(n)));
|
||||
} else {
|
||||
return 32 + static_cast<int>(Log2FloorNonZero(topbits));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
// from google3/util/endian/endian.h
|
||||
PROTOBUF_EXPORT uint32 ghtonl(uint32 x);
|
||||
|
||||
class BigEndian {
|
||||
public:
|
||||
#ifdef PROTOBUF_LITTLE_ENDIAN
|
||||
|
||||
static uint16 FromHost16(uint16 x) { return bswap_16(x); }
|
||||
static uint16 ToHost16(uint16 x) { return bswap_16(x); }
|
||||
|
||||
static uint32 FromHost32(uint32 x) { return bswap_32(x); }
|
||||
static uint32 ToHost32(uint32 x) { return bswap_32(x); }
|
||||
|
||||
static uint64 FromHost64(uint64 x) { return bswap_64(x); }
|
||||
static uint64 ToHost64(uint64 x) { return bswap_64(x); }
|
||||
|
||||
static bool IsLittleEndian() { return true; }
|
||||
|
||||
#else
|
||||
|
||||
static uint16 FromHost16(uint16 x) { return x; }
|
||||
static uint16 ToHost16(uint16 x) { return x; }
|
||||
|
||||
static uint32 FromHost32(uint32 x) { return x; }
|
||||
static uint32 ToHost32(uint32 x) { return x; }
|
||||
|
||||
static uint64 FromHost64(uint64 x) { return x; }
|
||||
static uint64 ToHost64(uint64 x) { return x; }
|
||||
|
||||
static bool IsLittleEndian() { return false; }
|
||||
|
||||
#endif /* ENDIAN */
|
||||
|
||||
// Functions to do unaligned loads and stores in big-endian order.
|
||||
static uint16 Load16(const void *p) {
|
||||
return ToHost16(GOOGLE_UNALIGNED_LOAD16(p));
|
||||
}
|
||||
|
||||
static void Store16(void *p, uint16 v) {
|
||||
GOOGLE_UNALIGNED_STORE16(p, FromHost16(v));
|
||||
}
|
||||
|
||||
static uint32 Load32(const void *p) {
|
||||
return ToHost32(GOOGLE_UNALIGNED_LOAD32(p));
|
||||
}
|
||||
|
||||
static void Store32(void *p, uint32 v) {
|
||||
GOOGLE_UNALIGNED_STORE32(p, FromHost32(v));
|
||||
}
|
||||
|
||||
static uint64 Load64(const void *p) {
|
||||
return ToHost64(GOOGLE_UNALIGNED_LOAD64(p));
|
||||
}
|
||||
|
||||
static void Store64(void *p, uint64 v) {
|
||||
GOOGLE_UNALIGNED_STORE64(p, FromHost64(v));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_PORT_H_
|
||||
134
ubuntu/google/protobuf/stubs/status.cc
Normal file
134
ubuntu/google/protobuf/stubs/status.cc
Normal file
@@ -0,0 +1,134 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <google/protobuf/stubs/status.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace util {
|
||||
namespace error {
|
||||
inline std::string CodeEnumToString(error::Code code) {
|
||||
switch (code) {
|
||||
case OK:
|
||||
return "OK";
|
||||
case CANCELLED:
|
||||
return "CANCELLED";
|
||||
case UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
case INVALID_ARGUMENT:
|
||||
return "INVALID_ARGUMENT";
|
||||
case DEADLINE_EXCEEDED:
|
||||
return "DEADLINE_EXCEEDED";
|
||||
case NOT_FOUND:
|
||||
return "NOT_FOUND";
|
||||
case ALREADY_EXISTS:
|
||||
return "ALREADY_EXISTS";
|
||||
case PERMISSION_DENIED:
|
||||
return "PERMISSION_DENIED";
|
||||
case UNAUTHENTICATED:
|
||||
return "UNAUTHENTICATED";
|
||||
case RESOURCE_EXHAUSTED:
|
||||
return "RESOURCE_EXHAUSTED";
|
||||
case FAILED_PRECONDITION:
|
||||
return "FAILED_PRECONDITION";
|
||||
case ABORTED:
|
||||
return "ABORTED";
|
||||
case OUT_OF_RANGE:
|
||||
return "OUT_OF_RANGE";
|
||||
case UNIMPLEMENTED:
|
||||
return "UNIMPLEMENTED";
|
||||
case INTERNAL:
|
||||
return "INTERNAL";
|
||||
case UNAVAILABLE:
|
||||
return "UNAVAILABLE";
|
||||
case DATA_LOSS:
|
||||
return "DATA_LOSS";
|
||||
}
|
||||
|
||||
// No default clause, clang will abort if a code is missing from
|
||||
// above switch.
|
||||
return "UNKNOWN";
|
||||
}
|
||||
} // namespace error.
|
||||
|
||||
const Status Status::OK = Status();
|
||||
const Status Status::CANCELLED = Status(error::CANCELLED, "");
|
||||
const Status Status::UNKNOWN = Status(error::UNKNOWN, "");
|
||||
|
||||
Status::Status() : error_code_(error::OK) {
|
||||
}
|
||||
|
||||
Status::Status(error::Code error_code, StringPiece error_message)
|
||||
: error_code_(error_code) {
|
||||
if (error_code != error::OK) {
|
||||
error_message_ = error_message.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
Status::Status(const Status& other)
|
||||
: error_code_(other.error_code_), error_message_(other.error_message_) {
|
||||
}
|
||||
|
||||
Status& Status::operator=(const Status& other) {
|
||||
error_code_ = other.error_code_;
|
||||
error_message_ = other.error_message_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Status::operator==(const Status& x) const {
|
||||
return error_code_ == x.error_code_ &&
|
||||
error_message_ == x.error_message_;
|
||||
}
|
||||
|
||||
std::string Status::ToString() const {
|
||||
if (error_code_ == error::OK) {
|
||||
return "OK";
|
||||
} else {
|
||||
if (error_message_.empty()) {
|
||||
return error::CodeEnumToString(error_code_);
|
||||
} else {
|
||||
return error::CodeEnumToString(error_code_) + ":" +
|
||||
error_message_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Status& x) {
|
||||
os << x.ToString();
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
125
ubuntu/google/protobuf/stubs/status.h
Normal file
125
ubuntu/google/protobuf/stubs/status.h
Normal file
@@ -0,0 +1,125 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_STATUS_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_STATUS_H_
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stringpiece.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace util {
|
||||
namespace error {
|
||||
// These values must match error codes defined in google/rpc/code.proto.
|
||||
enum Code {
|
||||
OK = 0,
|
||||
CANCELLED = 1,
|
||||
UNKNOWN = 2,
|
||||
INVALID_ARGUMENT = 3,
|
||||
DEADLINE_EXCEEDED = 4,
|
||||
NOT_FOUND = 5,
|
||||
ALREADY_EXISTS = 6,
|
||||
PERMISSION_DENIED = 7,
|
||||
UNAUTHENTICATED = 16,
|
||||
RESOURCE_EXHAUSTED = 8,
|
||||
FAILED_PRECONDITION = 9,
|
||||
ABORTED = 10,
|
||||
OUT_OF_RANGE = 11,
|
||||
UNIMPLEMENTED = 12,
|
||||
INTERNAL = 13,
|
||||
UNAVAILABLE = 14,
|
||||
DATA_LOSS = 15,
|
||||
};
|
||||
} // namespace error
|
||||
|
||||
class PROTOBUF_EXPORT Status {
|
||||
public:
|
||||
// Creates a "successful" status.
|
||||
Status();
|
||||
|
||||
// Create a status in the canonical error space with the specified
|
||||
// code, and error message. If "code == 0", error_message is
|
||||
// ignored and a Status object identical to Status::OK is
|
||||
// constructed.
|
||||
Status(error::Code error_code, StringPiece error_message);
|
||||
Status(const Status&);
|
||||
Status& operator=(const Status& x);
|
||||
~Status() {}
|
||||
|
||||
// Some pre-defined Status objects
|
||||
static const Status OK; // Identical to 0-arg constructor
|
||||
static const Status CANCELLED;
|
||||
static const Status UNKNOWN;
|
||||
|
||||
// Accessor
|
||||
bool ok() const {
|
||||
return error_code_ == error::OK;
|
||||
}
|
||||
int error_code() const {
|
||||
return error_code_;
|
||||
}
|
||||
error::Code code() const {
|
||||
return error_code_;
|
||||
}
|
||||
StringPiece error_message() const {
|
||||
return error_message_;
|
||||
}
|
||||
StringPiece message() const {
|
||||
return error_message_;
|
||||
}
|
||||
|
||||
bool operator==(const Status& x) const;
|
||||
bool operator!=(const Status& x) const {
|
||||
return !operator==(x);
|
||||
}
|
||||
|
||||
// Return a combination of the error code name and message.
|
||||
std::string ToString() const;
|
||||
|
||||
private:
|
||||
error::Code error_code_;
|
||||
std::string error_message_;
|
||||
};
|
||||
|
||||
// Prints a human-readable representation of 'x' to 'os'.
|
||||
PROTOBUF_EXPORT std::ostream& operator<<(std::ostream& os, const Status& x);
|
||||
|
||||
} // namespace util
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_STATUS_H_
|
||||
89
ubuntu/google/protobuf/stubs/status_macros.h
Normal file
89
ubuntu/google/protobuf/stubs/status_macros.h
Normal file
@@ -0,0 +1,89 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// From: util/task/contrib/status_macros/status_macros.h
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_STATUS_MACROS_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_STATUS_MACROS_H_
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/status.h>
|
||||
#include <google/protobuf/stubs/statusor.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace util {
|
||||
|
||||
// Run a command that returns a util::Status. If the called code returns an
|
||||
// error status, return that status up out of this method too.
|
||||
//
|
||||
// Example:
|
||||
// RETURN_IF_ERROR(DoThings(4));
|
||||
#define RETURN_IF_ERROR(expr) \
|
||||
do { \
|
||||
/* Using _status below to avoid capture problems if expr is "status". */ \
|
||||
const PROTOBUF_NAMESPACE_ID::util::Status _status = (expr); \
|
||||
if (PROTOBUF_PREDICT_FALSE(!_status.ok())) return _status; \
|
||||
} while (0)
|
||||
|
||||
// Internal helper for concatenating macro values.
|
||||
#define STATUS_MACROS_CONCAT_NAME_INNER(x, y) x##y
|
||||
#define STATUS_MACROS_CONCAT_NAME(x, y) STATUS_MACROS_CONCAT_NAME_INNER(x, y)
|
||||
|
||||
template<typename T>
|
||||
Status DoAssignOrReturn(T& lhs, StatusOr<T> result) {
|
||||
if (result.ok()) {
|
||||
lhs = result.ValueOrDie();
|
||||
}
|
||||
return result.status();
|
||||
}
|
||||
|
||||
#define ASSIGN_OR_RETURN_IMPL(status, lhs, rexpr) \
|
||||
Status status = DoAssignOrReturn(lhs, (rexpr)); \
|
||||
if (PROTOBUF_PREDICT_FALSE(!status.ok())) return status;
|
||||
|
||||
// Executes an expression that returns a util::StatusOr, extracting its value
|
||||
// into the variable defined by lhs (or returning on error).
|
||||
//
|
||||
// Example: Assigning to an existing value
|
||||
// ValueType value;
|
||||
// ASSIGN_OR_RETURN(value, MaybeGetValue(arg));
|
||||
//
|
||||
// WARNING: ASSIGN_OR_RETURN expands into multiple statements; it cannot be used
|
||||
// in a single statement (e.g. as the body of an if statement without {})!
|
||||
#define ASSIGN_OR_RETURN(lhs, rexpr) \
|
||||
ASSIGN_OR_RETURN_IMPL( \
|
||||
STATUS_MACROS_CONCAT_NAME(_status_or_value, __COUNTER__), lhs, rexpr);
|
||||
|
||||
} // namespace util
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_STATUS_H_
|
||||
138
ubuntu/google/protobuf/stubs/status_test.cc
Normal file
138
ubuntu/google/protobuf/stubs/status_test.cc
Normal file
@@ -0,0 +1,138 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <google/protobuf/stubs/status.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
TEST(Status, Empty) {
|
||||
util::Status status;
|
||||
EXPECT_EQ(util::error::OK, util::Status::OK.error_code());
|
||||
EXPECT_EQ(util::error::OK, util::Status::OK.code());
|
||||
EXPECT_EQ("OK", util::Status::OK.ToString());
|
||||
}
|
||||
|
||||
TEST(Status, GenericCodes) {
|
||||
EXPECT_EQ(util::error::OK, util::Status::OK.error_code());
|
||||
EXPECT_EQ(util::error::OK, util::Status::OK.code());
|
||||
EXPECT_EQ(util::error::CANCELLED, util::Status::CANCELLED.error_code());
|
||||
EXPECT_EQ(util::error::CANCELLED, util::Status::CANCELLED.code());
|
||||
EXPECT_EQ(util::error::UNKNOWN, util::Status::UNKNOWN.error_code());
|
||||
EXPECT_EQ(util::error::UNKNOWN, util::Status::UNKNOWN.code());
|
||||
}
|
||||
|
||||
TEST(Status, ConstructorZero) {
|
||||
util::Status status(util::error::OK, "msg");
|
||||
EXPECT_TRUE(status.ok());
|
||||
EXPECT_EQ("OK", status.ToString());
|
||||
}
|
||||
|
||||
TEST(Status, CheckOK) {
|
||||
util::Status status;
|
||||
GOOGLE_CHECK_OK(status);
|
||||
GOOGLE_CHECK_OK(status) << "Failed";
|
||||
GOOGLE_DCHECK_OK(status) << "Failed";
|
||||
}
|
||||
|
||||
TEST(Status, ErrorMessage) {
|
||||
util::Status status(util::error::INVALID_ARGUMENT, "");
|
||||
EXPECT_FALSE(status.ok());
|
||||
EXPECT_EQ("", status.error_message().ToString());
|
||||
EXPECT_EQ("", status.message().ToString());
|
||||
EXPECT_EQ("INVALID_ARGUMENT", status.ToString());
|
||||
status = util::Status(util::error::INVALID_ARGUMENT, "msg");
|
||||
EXPECT_FALSE(status.ok());
|
||||
EXPECT_EQ("msg", status.error_message().ToString());
|
||||
EXPECT_EQ("msg", status.message().ToString());
|
||||
EXPECT_EQ("INVALID_ARGUMENT:msg", status.ToString());
|
||||
status = util::Status(util::error::OK, "msg");
|
||||
EXPECT_TRUE(status.ok());
|
||||
EXPECT_EQ("", status.error_message().ToString());
|
||||
EXPECT_EQ("", status.message().ToString());
|
||||
EXPECT_EQ("OK", status.ToString());
|
||||
}
|
||||
|
||||
TEST(Status, Copy) {
|
||||
util::Status a(util::error::UNKNOWN, "message");
|
||||
util::Status b(a);
|
||||
ASSERT_EQ(a.ToString(), b.ToString());
|
||||
}
|
||||
|
||||
TEST(Status, Assign) {
|
||||
util::Status a(util::error::UNKNOWN, "message");
|
||||
util::Status b;
|
||||
b = a;
|
||||
ASSERT_EQ(a.ToString(), b.ToString());
|
||||
}
|
||||
|
||||
TEST(Status, AssignEmpty) {
|
||||
util::Status a(util::error::UNKNOWN, "message");
|
||||
util::Status b;
|
||||
a = b;
|
||||
ASSERT_EQ(std::string("OK"), a.ToString());
|
||||
ASSERT_TRUE(b.ok());
|
||||
ASSERT_TRUE(a.ok());
|
||||
}
|
||||
|
||||
TEST(Status, EqualsOK) {
|
||||
ASSERT_EQ(util::Status::OK, util::Status());
|
||||
}
|
||||
|
||||
TEST(Status, EqualsSame) {
|
||||
const util::Status a = util::Status(util::error::CANCELLED, "message");
|
||||
const util::Status b = util::Status(util::error::CANCELLED, "message");
|
||||
ASSERT_EQ(a, b);
|
||||
}
|
||||
|
||||
TEST(Status, EqualsCopy) {
|
||||
const util::Status a = util::Status(util::error::CANCELLED, "message");
|
||||
const util::Status b = a;
|
||||
ASSERT_EQ(a, b);
|
||||
}
|
||||
|
||||
TEST(Status, EqualsDifferentCode) {
|
||||
const util::Status a = util::Status(util::error::CANCELLED, "message");
|
||||
const util::Status b = util::Status(util::error::UNKNOWN, "message");
|
||||
ASSERT_NE(a, b);
|
||||
}
|
||||
|
||||
TEST(Status, EqualsDifferentMessage) {
|
||||
const util::Status a = util::Status(util::error::CANCELLED, "message");
|
||||
const util::Status b = util::Status(util::error::CANCELLED, "another");
|
||||
ASSERT_NE(a, b);
|
||||
}
|
||||
} // namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
48
ubuntu/google/protobuf/stubs/statusor.cc
Normal file
48
ubuntu/google/protobuf/stubs/statusor.cc
Normal file
@@ -0,0 +1,48 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <google/protobuf/stubs/statusor.h>
|
||||
|
||||
#include <google/protobuf/stubs/logging.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace util {
|
||||
namespace internal {
|
||||
|
||||
void StatusOrHelper::Crash(const Status& status) {
|
||||
GOOGLE_LOG(FATAL) << "Attempting to fetch value instead of handling error "
|
||||
<< status.ToString();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace util
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
272
ubuntu/google/protobuf/stubs/statusor.h
Normal file
272
ubuntu/google/protobuf/stubs/statusor.h
Normal file
@@ -0,0 +1,272 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// StatusOr<T> is the union of a Status object and a T
|
||||
// object. StatusOr models the concept of an object that is either a
|
||||
// usable value, or an error Status explaining why such a value is
|
||||
// not present. To this end, StatusOr<T> does not allow its Status
|
||||
// value to be Status::OK. Further, StatusOr<T*> does not allow the
|
||||
// contained pointer to be nullptr.
|
||||
//
|
||||
// The primary use-case for StatusOr<T> is as the return value of a
|
||||
// function which may fail.
|
||||
//
|
||||
// Example client usage for a StatusOr<T>, where T is not a pointer:
|
||||
//
|
||||
// StatusOr<float> result = DoBigCalculationThatCouldFail();
|
||||
// if (result.ok()) {
|
||||
// float answer = result.ValueOrDie();
|
||||
// printf("Big calculation yielded: %f", answer);
|
||||
// } else {
|
||||
// LOG(ERROR) << result.status();
|
||||
// }
|
||||
//
|
||||
// Example client usage for a StatusOr<T*>:
|
||||
//
|
||||
// StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg);
|
||||
// if (result.ok()) {
|
||||
// std::unique_ptr<Foo> foo(result.ValueOrDie());
|
||||
// foo->DoSomethingCool();
|
||||
// } else {
|
||||
// LOG(ERROR) << result.status();
|
||||
// }
|
||||
//
|
||||
// Example client usage for a StatusOr<std::unique_ptr<T>>:
|
||||
//
|
||||
// StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
|
||||
// if (result.ok()) {
|
||||
// std::unique_ptr<Foo> foo = result.ConsumeValueOrDie();
|
||||
// foo->DoSomethingCool();
|
||||
// } else {
|
||||
// LOG(ERROR) << result.status();
|
||||
// }
|
||||
//
|
||||
// Example factory implementation returning StatusOr<T*>:
|
||||
//
|
||||
// StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
|
||||
// if (arg <= 0) {
|
||||
// return ::util::Status(::util::error::INVALID_ARGUMENT,
|
||||
// "Arg must be positive");
|
||||
// } else {
|
||||
// return new Foo(arg);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
|
||||
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <google/protobuf/stubs/status.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace util {
|
||||
|
||||
template<typename T>
|
||||
class StatusOr {
|
||||
template<typename U> friend class StatusOr;
|
||||
|
||||
public:
|
||||
// Construct a new StatusOr with Status::UNKNOWN status
|
||||
StatusOr();
|
||||
|
||||
// Construct a new StatusOr with the given non-ok status. After calling
|
||||
// this constructor, calls to ValueOrDie() will CHECK-fail.
|
||||
//
|
||||
// NOTE: Not explicit - we want to use StatusOr<T> as a return
|
||||
// value, so it is convenient and sensible to be able to do 'return
|
||||
// Status()' when the return type is StatusOr<T>.
|
||||
//
|
||||
// REQUIRES: status != Status::OK. This requirement is DCHECKed.
|
||||
// In optimized builds, passing Status::OK here will have the effect
|
||||
// of passing PosixErrorSpace::EINVAL as a fallback.
|
||||
StatusOr(const Status& status); // NOLINT
|
||||
|
||||
// Construct a new StatusOr with the given value. If T is a plain pointer,
|
||||
// value must not be nullptr. After calling this constructor, calls to
|
||||
// ValueOrDie() will succeed, and calls to status() will return OK.
|
||||
//
|
||||
// NOTE: Not explicit - we want to use StatusOr<T> as a return type
|
||||
// so it is convenient and sensible to be able to do 'return T()'
|
||||
// when when the return type is StatusOr<T>.
|
||||
//
|
||||
// REQUIRES: if T is a plain pointer, value != nullptr. This requirement is
|
||||
// DCHECKed. In optimized builds, passing a null pointer here will have
|
||||
// the effect of passing PosixErrorSpace::EINVAL as a fallback.
|
||||
StatusOr(const T& value); // NOLINT
|
||||
|
||||
// Copy constructor.
|
||||
StatusOr(const StatusOr& other);
|
||||
|
||||
// Conversion copy constructor, T must be copy constructible from U
|
||||
template<typename U>
|
||||
StatusOr(const StatusOr<U>& other);
|
||||
|
||||
// Assignment operator.
|
||||
StatusOr& operator=(const StatusOr& other);
|
||||
|
||||
// Conversion assignment operator, T must be assignable from U
|
||||
template<typename U>
|
||||
StatusOr& operator=(const StatusOr<U>& other);
|
||||
|
||||
// Returns a reference to our status. If this contains a T, then
|
||||
// returns Status::OK.
|
||||
const Status& status() const;
|
||||
|
||||
// Returns this->status().ok()
|
||||
bool ok() const;
|
||||
|
||||
// Returns a reference to our current value, or CHECK-fails if !this->ok().
|
||||
// If you need to initialize a T object from the stored value,
|
||||
// ConsumeValueOrDie() may be more efficient.
|
||||
const T& ValueOrDie() const;
|
||||
const T& value () const;
|
||||
|
||||
private:
|
||||
Status status_;
|
||||
T value_;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation details for StatusOr<T>
|
||||
|
||||
namespace internal {
|
||||
|
||||
class PROTOBUF_EXPORT StatusOrHelper {
|
||||
public:
|
||||
// Move type-agnostic error handling to the .cc.
|
||||
static void Crash(const util::Status& status);
|
||||
|
||||
// Customized behavior for StatusOr<T> vs. StatusOr<T*>
|
||||
template<typename T>
|
||||
struct Specialize;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct StatusOrHelper::Specialize {
|
||||
// For non-pointer T, a reference can never be nullptr.
|
||||
static inline bool IsValueNull(const T& t) { return false; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct StatusOrHelper::Specialize<T*> {
|
||||
static inline bool IsValueNull(const T* t) { return t == nullptr; }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template<typename T>
|
||||
inline StatusOr<T>::StatusOr()
|
||||
: status_(util::Status::UNKNOWN) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline StatusOr<T>::StatusOr(const Status& status) {
|
||||
if (status.ok()) {
|
||||
status_ = Status(error::INTERNAL, "Status::OK is not a valid argument.");
|
||||
} else {
|
||||
status_ = status;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline StatusOr<T>::StatusOr(const T& value) {
|
||||
if (internal::StatusOrHelper::Specialize<T>::IsValueNull(value)) {
|
||||
status_ = Status(error::INTERNAL, "nullptr is not a valid argument.");
|
||||
} else {
|
||||
status_ = Status::OK;
|
||||
value_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline StatusOr<T>::StatusOr(const StatusOr<T>& other)
|
||||
: status_(other.status_), value_(other.value_) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) {
|
||||
status_ = other.status_;
|
||||
value_ = other.value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
|
||||
: status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
|
||||
status_ = other.status_;
|
||||
if (status_.ok()) value_ = other.value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const Status& StatusOr<T>::status() const {
|
||||
return status_;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool StatusOr<T>::ok() const {
|
||||
return status().ok();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T& StatusOr<T>::ValueOrDie() const {
|
||||
if (!status_.ok()) {
|
||||
internal::StatusOrHelper::Crash(status_);
|
||||
}
|
||||
return value_;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T& StatusOr<T>::value() const {
|
||||
if (!status_.ok()) {
|
||||
internal::StatusOrHelper::Crash(status_);
|
||||
}
|
||||
return value_;
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
|
||||
274
ubuntu/google/protobuf/stubs/statusor_test.cc
Normal file
274
ubuntu/google/protobuf/stubs/statusor_test.cc
Normal file
@@ -0,0 +1,274 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <google/protobuf/stubs/statusor.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <memory>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace util {
|
||||
namespace {
|
||||
|
||||
class Base1 {
|
||||
public:
|
||||
virtual ~Base1() {}
|
||||
int pad;
|
||||
};
|
||||
|
||||
class Base2 {
|
||||
public:
|
||||
virtual ~Base2() {}
|
||||
int yetotherpad;
|
||||
};
|
||||
|
||||
class Derived : public Base1, public Base2 {
|
||||
public:
|
||||
virtual ~Derived() {}
|
||||
int evenmorepad;
|
||||
};
|
||||
|
||||
class CopyNoAssign {
|
||||
public:
|
||||
explicit CopyNoAssign(int value) : foo(value) {}
|
||||
CopyNoAssign(const CopyNoAssign& other) : foo(other.foo) {}
|
||||
int foo;
|
||||
private:
|
||||
const CopyNoAssign& operator=(const CopyNoAssign&);
|
||||
};
|
||||
|
||||
TEST(StatusOr, TestDefaultCtor) {
|
||||
StatusOr<int> thing;
|
||||
EXPECT_FALSE(thing.ok());
|
||||
EXPECT_EQ(Status::UNKNOWN, thing.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestStatusCtor) {
|
||||
StatusOr<int> thing(Status::CANCELLED);
|
||||
EXPECT_FALSE(thing.ok());
|
||||
EXPECT_EQ(Status::CANCELLED, thing.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestValueCtor) {
|
||||
const int kI = 4;
|
||||
StatusOr<int> thing(kI);
|
||||
EXPECT_TRUE(thing.ok());
|
||||
EXPECT_EQ(kI, thing.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestCopyCtorStatusOk) {
|
||||
const int kI = 4;
|
||||
StatusOr<int> original(kI);
|
||||
StatusOr<int> copy(original);
|
||||
EXPECT_EQ(original.status(), copy.status());
|
||||
EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestCopyCtorStatusNotOk) {
|
||||
StatusOr<int> original(Status::CANCELLED);
|
||||
StatusOr<int> copy(original);
|
||||
EXPECT_EQ(original.status(), copy.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestCopyCtorStatusOKConverting) {
|
||||
const int kI = 4;
|
||||
StatusOr<int> original(kI);
|
||||
StatusOr<double> copy(original);
|
||||
EXPECT_EQ(original.status(), copy.status());
|
||||
EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestCopyCtorStatusNotOkConverting) {
|
||||
StatusOr<int> original(Status::CANCELLED);
|
||||
StatusOr<double> copy(original);
|
||||
EXPECT_EQ(original.status(), copy.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestAssignmentStatusOk) {
|
||||
const int kI = 4;
|
||||
StatusOr<int> source(kI);
|
||||
StatusOr<int> target;
|
||||
target = source;
|
||||
EXPECT_EQ(source.status(), target.status());
|
||||
EXPECT_EQ(source.ValueOrDie(), target.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestAssignmentStatusNotOk) {
|
||||
StatusOr<int> source(Status::CANCELLED);
|
||||
StatusOr<int> target;
|
||||
target = source;
|
||||
EXPECT_EQ(source.status(), target.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestAssignmentStatusOKConverting) {
|
||||
const int kI = 4;
|
||||
StatusOr<int> source(kI);
|
||||
StatusOr<double> target;
|
||||
target = source;
|
||||
EXPECT_EQ(source.status(), target.status());
|
||||
EXPECT_DOUBLE_EQ(source.ValueOrDie(), target.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestAssignmentStatusNotOkConverting) {
|
||||
StatusOr<int> source(Status::CANCELLED);
|
||||
StatusOr<double> target;
|
||||
target = source;
|
||||
EXPECT_EQ(source.status(), target.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestStatus) {
|
||||
StatusOr<int> good(4);
|
||||
EXPECT_TRUE(good.ok());
|
||||
StatusOr<int> bad(Status::CANCELLED);
|
||||
EXPECT_FALSE(bad.ok());
|
||||
EXPECT_EQ(Status::CANCELLED, bad.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestValue) {
|
||||
const int kI = 4;
|
||||
StatusOr<int> thing(kI);
|
||||
EXPECT_EQ(kI, thing.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestValueConst) {
|
||||
const int kI = 4;
|
||||
const StatusOr<int> thing(kI);
|
||||
EXPECT_EQ(kI, thing.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerDefaultCtor) {
|
||||
StatusOr<int*> thing;
|
||||
EXPECT_FALSE(thing.ok());
|
||||
EXPECT_EQ(Status::UNKNOWN, thing.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerStatusCtor) {
|
||||
StatusOr<int*> thing(Status::CANCELLED);
|
||||
EXPECT_FALSE(thing.ok());
|
||||
EXPECT_EQ(Status::CANCELLED, thing.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerValueCtor) {
|
||||
const int kI = 4;
|
||||
StatusOr<const int*> thing(&kI);
|
||||
EXPECT_TRUE(thing.ok());
|
||||
EXPECT_EQ(&kI, thing.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerCopyCtorStatusOk) {
|
||||
const int kI = 0;
|
||||
StatusOr<const int*> original(&kI);
|
||||
StatusOr<const int*> copy(original);
|
||||
EXPECT_EQ(original.status(), copy.status());
|
||||
EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerCopyCtorStatusNotOk) {
|
||||
StatusOr<int*> original(Status::CANCELLED);
|
||||
StatusOr<int*> copy(original);
|
||||
EXPECT_EQ(original.status(), copy.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerCopyCtorStatusOKConverting) {
|
||||
Derived derived;
|
||||
StatusOr<Derived*> original(&derived);
|
||||
StatusOr<Base2*> copy(original);
|
||||
EXPECT_EQ(original.status(), copy.status());
|
||||
EXPECT_EQ(static_cast<const Base2*>(original.ValueOrDie()),
|
||||
copy.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerCopyCtorStatusNotOkConverting) {
|
||||
StatusOr<Derived*> original(Status::CANCELLED);
|
||||
StatusOr<Base2*> copy(original);
|
||||
EXPECT_EQ(original.status(), copy.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerAssignmentStatusOk) {
|
||||
const int kI = 0;
|
||||
StatusOr<const int*> source(&kI);
|
||||
StatusOr<const int*> target;
|
||||
target = source;
|
||||
EXPECT_EQ(source.status(), target.status());
|
||||
EXPECT_EQ(source.ValueOrDie(), target.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerAssignmentStatusNotOk) {
|
||||
StatusOr<int*> source(Status::CANCELLED);
|
||||
StatusOr<int*> target;
|
||||
target = source;
|
||||
EXPECT_EQ(source.status(), target.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerAssignmentStatusOKConverting) {
|
||||
Derived derived;
|
||||
StatusOr<Derived*> source(&derived);
|
||||
StatusOr<Base2*> target;
|
||||
target = source;
|
||||
EXPECT_EQ(source.status(), target.status());
|
||||
EXPECT_EQ(static_cast<const Base2*>(source.ValueOrDie()),
|
||||
target.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerAssignmentStatusNotOkConverting) {
|
||||
StatusOr<Derived*> source(Status::CANCELLED);
|
||||
StatusOr<Base2*> target;
|
||||
target = source;
|
||||
EXPECT_EQ(source.status(), target.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerStatus) {
|
||||
const int kI = 0;
|
||||
StatusOr<const int*> good(&kI);
|
||||
EXPECT_TRUE(good.ok());
|
||||
StatusOr<const int*> bad(Status::CANCELLED);
|
||||
EXPECT_EQ(Status::CANCELLED, bad.status());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerValue) {
|
||||
const int kI = 0;
|
||||
StatusOr<const int*> thing(&kI);
|
||||
EXPECT_EQ(&kI, thing.ValueOrDie());
|
||||
}
|
||||
|
||||
TEST(StatusOr, TestPointerValueConst) {
|
||||
const int kI = 0;
|
||||
const StatusOr<const int*> thing(&kI);
|
||||
EXPECT_EQ(&kI, thing.ValueOrDie());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace util
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
71
ubuntu/google/protobuf/stubs/stl_util.h
Normal file
71
ubuntu/google/protobuf/stubs/stl_util.h
Normal file
@@ -0,0 +1,71 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// from google3/util/gtl/stl_util.h
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Inside Google, this function implements a horrible, disgusting hack in which
|
||||
// we reach into the string's private implementation and resize it without
|
||||
// initializing the new bytes. In some cases doing this can significantly
|
||||
// improve performance. However, since it's totally non-portable it has no
|
||||
// place in open source code. Feel free to fill this function in with your
|
||||
// own disgusting hack if you want the perf boost.
|
||||
inline void STLStringResizeUninitialized(std::string* s, size_t new_size) {
|
||||
s->resize(new_size);
|
||||
}
|
||||
|
||||
// Return a mutable char* pointing to a string's internal buffer,
|
||||
// which may not be null-terminated. Writing through this pointer will
|
||||
// modify the string.
|
||||
//
|
||||
// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
|
||||
// next call to a string method that invalidates iterators.
|
||||
//
|
||||
// As of 2006-04, there is no standard-blessed way of getting a
|
||||
// mutable reference to a string's internal buffer. However, issue 530
|
||||
// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
|
||||
// proposes this as the method. According to Matt Austern, this should
|
||||
// already work on all current implementations.
|
||||
inline char* string_as_array(std::string* str) {
|
||||
// DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
|
||||
return str->empty() ? nullptr : &*str->begin();
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
|
||||
270
ubuntu/google/protobuf/stubs/stringpiece.cc
Normal file
270
ubuntu/google/protobuf/stubs/stringpiece.cc
Normal file
@@ -0,0 +1,270 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <google/protobuf/stubs/stringpiece.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
|
||||
#include <google/protobuf/stubs/logging.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
std::ostream& operator<<(std::ostream& o, StringPiece piece) {
|
||||
o.write(piece.data(), piece.size());
|
||||
return o;
|
||||
}
|
||||
|
||||
// Out-of-line error path.
|
||||
void StringPiece::LogFatalSizeTooBig(size_t size, const char* details) {
|
||||
GOOGLE_LOG(FATAL) << "size too big: " << size << " details: " << details;
|
||||
}
|
||||
|
||||
StringPiece::StringPiece(StringPiece x, stringpiece_ssize_type pos)
|
||||
: ptr_(x.ptr_ + pos), length_(x.length_ - pos) {
|
||||
GOOGLE_DCHECK_LE(0, pos);
|
||||
GOOGLE_DCHECK_LE(pos, x.length_);
|
||||
}
|
||||
|
||||
StringPiece::StringPiece(StringPiece x,
|
||||
stringpiece_ssize_type pos,
|
||||
stringpiece_ssize_type len)
|
||||
: ptr_(x.ptr_ + pos), length_(std::min(len, x.length_ - pos)) {
|
||||
GOOGLE_DCHECK_LE(0, pos);
|
||||
GOOGLE_DCHECK_LE(pos, x.length_);
|
||||
GOOGLE_DCHECK_GE(len, 0);
|
||||
}
|
||||
|
||||
void StringPiece::CopyToString(std::string* target) const {
|
||||
target->assign(ptr_, length_);
|
||||
}
|
||||
|
||||
void StringPiece::AppendToString(std::string* target) const {
|
||||
target->append(ptr_, length_);
|
||||
}
|
||||
|
||||
bool StringPiece::Consume(StringPiece x) {
|
||||
if (starts_with(x)) {
|
||||
ptr_ += x.length_;
|
||||
length_ -= x.length_;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StringPiece::ConsumeFromEnd(StringPiece x) {
|
||||
if (ends_with(x)) {
|
||||
length_ -= x.length_;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
stringpiece_ssize_type StringPiece::copy(char* buf,
|
||||
size_type n,
|
||||
size_type pos) const {
|
||||
stringpiece_ssize_type ret = std::min(length_ - pos, n);
|
||||
memcpy(buf, ptr_ + pos, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool StringPiece::contains(StringPiece s) const {
|
||||
return find(s, 0) != npos;
|
||||
}
|
||||
|
||||
stringpiece_ssize_type StringPiece::find(StringPiece s, size_type pos) const {
|
||||
if (length_ <= 0 || pos > static_cast<size_type>(length_)) {
|
||||
if (length_ == 0 && pos == 0 && s.length_ == 0) return 0;
|
||||
return npos;
|
||||
}
|
||||
const char *result = std::search(ptr_ + pos, ptr_ + length_,
|
||||
s.ptr_, s.ptr_ + s.length_);
|
||||
return result == ptr_ + length_ ? npos : result - ptr_;
|
||||
}
|
||||
|
||||
stringpiece_ssize_type StringPiece::find(char c, size_type pos) const {
|
||||
if (length_ <= 0 || pos >= static_cast<size_type>(length_)) {
|
||||
return npos;
|
||||
}
|
||||
const char* result = static_cast<const char*>(
|
||||
memchr(ptr_ + pos, c, length_ - pos));
|
||||
return result != nullptr ? result - ptr_ : npos;
|
||||
}
|
||||
|
||||
stringpiece_ssize_type StringPiece::rfind(StringPiece s, size_type pos) const {
|
||||
if (length_ < s.length_) return npos;
|
||||
const size_t ulen = length_;
|
||||
if (s.length_ == 0) return std::min(ulen, pos);
|
||||
|
||||
const char* last = ptr_ + std::min(ulen - s.length_, pos) + s.length_;
|
||||
const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
|
||||
return result != last ? result - ptr_ : npos;
|
||||
}
|
||||
|
||||
// Search range is [0..pos] inclusive. If pos == npos, search everything.
|
||||
stringpiece_ssize_type StringPiece::rfind(char c, size_type pos) const {
|
||||
// Note: memrchr() is not available on Windows.
|
||||
if (length_ <= 0) return npos;
|
||||
for (stringpiece_ssize_type i =
|
||||
std::min(pos, static_cast<size_type>(length_ - 1));
|
||||
i >= 0; --i) {
|
||||
if (ptr_[i] == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
// For each character in characters_wanted, sets the index corresponding
|
||||
// to the ASCII code of that character to 1 in table. This is used by
|
||||
// the find_.*_of methods below to tell whether or not a character is in
|
||||
// the lookup table in constant time.
|
||||
// The argument `table' must be an array that is large enough to hold all
|
||||
// the possible values of an unsigned char. Thus it should be be declared
|
||||
// as follows:
|
||||
// bool table[UCHAR_MAX + 1]
|
||||
static inline void BuildLookupTable(StringPiece characters_wanted,
|
||||
bool* table) {
|
||||
const stringpiece_ssize_type length = characters_wanted.length();
|
||||
const char* const data = characters_wanted.data();
|
||||
for (stringpiece_ssize_type i = 0; i < length; ++i) {
|
||||
table[static_cast<unsigned char>(data[i])] = true;
|
||||
}
|
||||
}
|
||||
|
||||
stringpiece_ssize_type StringPiece::find_first_of(StringPiece s,
|
||||
size_type pos) const {
|
||||
if (length_ <= 0 || s.length_ <= 0) {
|
||||
return npos;
|
||||
}
|
||||
// Avoid the cost of BuildLookupTable() for a single-character search.
|
||||
if (s.length_ == 1) return find_first_of(s.ptr_[0], pos);
|
||||
|
||||
bool lookup[UCHAR_MAX + 1] = { false };
|
||||
BuildLookupTable(s, lookup);
|
||||
for (stringpiece_ssize_type i = pos; i < length_; ++i) {
|
||||
if (lookup[static_cast<unsigned char>(ptr_[i])]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
stringpiece_ssize_type StringPiece::find_first_not_of(StringPiece s,
|
||||
size_type pos) const {
|
||||
if (length_ <= 0) return npos;
|
||||
if (s.length_ <= 0) return 0;
|
||||
// Avoid the cost of BuildLookupTable() for a single-character search.
|
||||
if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos);
|
||||
|
||||
bool lookup[UCHAR_MAX + 1] = { false };
|
||||
BuildLookupTable(s, lookup);
|
||||
for (stringpiece_ssize_type i = pos; i < length_; ++i) {
|
||||
if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
stringpiece_ssize_type StringPiece::find_first_not_of(char c,
|
||||
size_type pos) const {
|
||||
if (length_ <= 0) return npos;
|
||||
|
||||
for (; pos < static_cast<size_type>(length_); ++pos) {
|
||||
if (ptr_[pos] != c) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
stringpiece_ssize_type StringPiece::find_last_of(StringPiece s,
|
||||
size_type pos) const {
|
||||
if (length_ <= 0 || s.length_ <= 0) return npos;
|
||||
// Avoid the cost of BuildLookupTable() for a single-character search.
|
||||
if (s.length_ == 1) return find_last_of(s.ptr_[0], pos);
|
||||
|
||||
bool lookup[UCHAR_MAX + 1] = { false };
|
||||
BuildLookupTable(s, lookup);
|
||||
for (stringpiece_ssize_type i =
|
||||
std::min(pos, static_cast<size_type>(length_ - 1)); i >= 0; --i) {
|
||||
if (lookup[static_cast<unsigned char>(ptr_[i])]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
stringpiece_ssize_type StringPiece::find_last_not_of(StringPiece s,
|
||||
size_type pos) const {
|
||||
if (length_ <= 0) return npos;
|
||||
|
||||
stringpiece_ssize_type i = std::min(pos, static_cast<size_type>(length_ - 1));
|
||||
if (s.length_ <= 0) return i;
|
||||
|
||||
// Avoid the cost of BuildLookupTable() for a single-character search.
|
||||
if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos);
|
||||
|
||||
bool lookup[UCHAR_MAX + 1] = { false };
|
||||
BuildLookupTable(s, lookup);
|
||||
for (; i >= 0; --i) {
|
||||
if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
stringpiece_ssize_type StringPiece::find_last_not_of(char c,
|
||||
size_type pos) const {
|
||||
if (length_ <= 0) return npos;
|
||||
|
||||
for (stringpiece_ssize_type i =
|
||||
std::min(pos, static_cast<size_type>(length_ - 1)); i >= 0; --i) {
|
||||
if (ptr_[i] != c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
StringPiece StringPiece::substr(size_type pos, size_type n) const {
|
||||
if (pos > length_) pos = length_;
|
||||
if (n > length_ - pos) n = length_ - pos;
|
||||
return StringPiece(ptr_ + pos, n);
|
||||
}
|
||||
|
||||
const StringPiece::size_type StringPiece::npos = size_type(-1);
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
489
ubuntu/google/protobuf/stubs/stringpiece.h
Normal file
489
ubuntu/google/protobuf/stubs/stringpiece.h
Normal file
@@ -0,0 +1,489 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// A StringPiece points to part or all of a string, Cord, double-quoted string
|
||||
// literal, or other string-like object. A StringPiece does *not* own the
|
||||
// string to which it points. A StringPiece is not null-terminated.
|
||||
//
|
||||
// You can use StringPiece as a function or method parameter. A StringPiece
|
||||
// parameter can receive a double-quoted string literal argument, a "const
|
||||
// char*" argument, a string argument, or a StringPiece argument with no data
|
||||
// copying. Systematic use of StringPiece for arguments reduces data
|
||||
// copies and strlen() calls.
|
||||
//
|
||||
// Prefer passing StringPieces by value:
|
||||
// void MyFunction(StringPiece arg);
|
||||
// If circumstances require, you may also pass by const reference:
|
||||
// void MyFunction(const StringPiece& arg); // not preferred
|
||||
// Both of these have the same lifetime semantics. Passing by value
|
||||
// generates slightly smaller code. For more discussion, see the thread
|
||||
// go/stringpiecebyvalue on c-users.
|
||||
//
|
||||
// StringPiece is also suitable for local variables if you know that
|
||||
// the lifetime of the underlying object is longer than the lifetime
|
||||
// of your StringPiece variable.
|
||||
//
|
||||
// Beware of binding a StringPiece to a temporary:
|
||||
// StringPiece sp = obj.MethodReturningString(); // BAD: lifetime problem
|
||||
//
|
||||
// This code is okay:
|
||||
// string str = obj.MethodReturningString(); // str owns its contents
|
||||
// StringPiece sp(str); // GOOD, because str outlives sp
|
||||
//
|
||||
// StringPiece is sometimes a poor choice for a return value and usually a poor
|
||||
// choice for a data member. If you do use a StringPiece this way, it is your
|
||||
// responsibility to ensure that the object pointed to by the StringPiece
|
||||
// outlives the StringPiece.
|
||||
//
|
||||
// A StringPiece may represent just part of a string; thus the name "Piece".
|
||||
// For example, when splitting a string, vector<StringPiece> is a natural data
|
||||
// type for the output. For another example, a Cord is a non-contiguous,
|
||||
// potentially very long string-like object. The Cord class has an interface
|
||||
// that iteratively provides StringPiece objects that point to the
|
||||
// successive pieces of a Cord object.
|
||||
//
|
||||
// A StringPiece is not null-terminated. If you write code that scans a
|
||||
// StringPiece, you must check its length before reading any characters.
|
||||
// Common idioms that work on null-terminated strings do not work on
|
||||
// StringPiece objects.
|
||||
//
|
||||
// There are several ways to create a null StringPiece:
|
||||
// StringPiece()
|
||||
// StringPiece(nullptr)
|
||||
// StringPiece(nullptr, 0)
|
||||
// For all of the above, sp.data() == nullptr, sp.length() == 0,
|
||||
// and sp.empty() == true. Also, if you create a StringPiece with
|
||||
// a non-null pointer then sp.data() != nullptr. Once created,
|
||||
// sp.data() will stay either nullptr or not-nullptr, except if you call
|
||||
// sp.clear() or sp.set().
|
||||
//
|
||||
// Thus, you can use StringPiece(nullptr) to signal an out-of-band value
|
||||
// that is different from other StringPiece values. This is similar
|
||||
// to the way that const char* p1 = nullptr; is different from
|
||||
// const char* p2 = "";.
|
||||
//
|
||||
// There are many ways to create an empty StringPiece:
|
||||
// StringPiece()
|
||||
// StringPiece(nullptr)
|
||||
// StringPiece(nullptr, 0)
|
||||
// StringPiece("")
|
||||
// StringPiece("", 0)
|
||||
// StringPiece("abcdef", 0)
|
||||
// StringPiece("abcdef"+6, 0)
|
||||
// For all of the above, sp.length() will be 0 and sp.empty() will be true.
|
||||
// For some empty StringPiece values, sp.data() will be nullptr.
|
||||
// For some empty StringPiece values, sp.data() will not be nullptr.
|
||||
//
|
||||
// Be careful not to confuse: null StringPiece and empty StringPiece.
|
||||
// The set of empty StringPieces properly includes the set of null StringPieces.
|
||||
// That is, every null StringPiece is an empty StringPiece,
|
||||
// but some non-null StringPieces are empty Stringpieces too.
|
||||
//
|
||||
// All empty StringPiece values compare equal to each other.
|
||||
// Even a null StringPieces compares equal to a non-null empty StringPiece:
|
||||
// StringPiece() == StringPiece("", 0)
|
||||
// StringPiece(nullptr) == StringPiece("abc", 0)
|
||||
// StringPiece(nullptr, 0) == StringPiece("abcdef"+6, 0)
|
||||
//
|
||||
// Look carefully at this example:
|
||||
// StringPiece("") == nullptr
|
||||
// True or false? TRUE, because StringPiece::operator== converts
|
||||
// the right-hand side from nullptr to StringPiece(nullptr),
|
||||
// and then compares two zero-length spans of characters.
|
||||
// However, we are working to make this example produce a compile error.
|
||||
//
|
||||
// Suppose you want to write:
|
||||
// bool TestWhat?(StringPiece sp) { return sp == nullptr; } // BAD
|
||||
// Do not do that. Write one of these instead:
|
||||
// bool TestNull(StringPiece sp) { return sp.data() == nullptr; }
|
||||
// bool TestEmpty(StringPiece sp) { return sp.empty(); }
|
||||
// The intent of TestWhat? is unclear. Did you mean TestNull or TestEmpty?
|
||||
// Right now, TestWhat? behaves likes TestEmpty.
|
||||
// We are working to make TestWhat? produce a compile error.
|
||||
// TestNull is good to test for an out-of-band signal.
|
||||
// TestEmpty is good to test for an empty StringPiece.
|
||||
//
|
||||
// Caveats (again):
|
||||
// (1) The lifetime of the pointed-to string (or piece of a string)
|
||||
// must be longer than the lifetime of the StringPiece.
|
||||
// (2) There may or may not be a '\0' character after the end of
|
||||
// StringPiece data.
|
||||
// (3) A null StringPiece is empty.
|
||||
// An empty StringPiece may or may not be a null StringPiece.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_STRINGPIECE_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_STRINGPIECE_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <iosfwd>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
// StringPiece has *two* size types.
|
||||
// StringPiece::size_type
|
||||
// is unsigned
|
||||
// is 32 bits in LP32, 64 bits in LP64, 64 bits in LLP64
|
||||
// no future changes intended
|
||||
// stringpiece_ssize_type
|
||||
// is signed
|
||||
// is 32 bits in LP32, 64 bits in LP64, 64 bits in LLP64
|
||||
// future changes intended: http://go/64BitStringPiece
|
||||
//
|
||||
typedef std::string::difference_type stringpiece_ssize_type;
|
||||
|
||||
// STRINGPIECE_CHECK_SIZE protects us from 32-bit overflows.
|
||||
// TODO(mec): delete this after stringpiece_ssize_type goes 64 bit.
|
||||
#if !defined(NDEBUG)
|
||||
#define STRINGPIECE_CHECK_SIZE 1
|
||||
#elif defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0
|
||||
#define STRINGPIECE_CHECK_SIZE 1
|
||||
#else
|
||||
#define STRINGPIECE_CHECK_SIZE 0
|
||||
#endif
|
||||
|
||||
class PROTOBUF_EXPORT StringPiece {
|
||||
private:
|
||||
const char* ptr_;
|
||||
stringpiece_ssize_type length_;
|
||||
|
||||
// Prevent overflow in debug mode or fortified mode.
|
||||
// sizeof(stringpiece_ssize_type) may be smaller than sizeof(size_t).
|
||||
static stringpiece_ssize_type CheckedSsizeTFromSizeT(size_t size) {
|
||||
#if STRINGPIECE_CHECK_SIZE > 0
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
if (size > static_cast<size_t>(
|
||||
std::numeric_limits<stringpiece_ssize_type>::max())) {
|
||||
// Some people grep for this message in logs
|
||||
// so take care if you ever change it.
|
||||
LogFatalSizeTooBig(size, "size_t to int conversion");
|
||||
}
|
||||
#endif
|
||||
return static_cast<stringpiece_ssize_type>(size);
|
||||
}
|
||||
|
||||
// Out-of-line error path.
|
||||
static void LogFatalSizeTooBig(size_t size, const char* details);
|
||||
|
||||
public:
|
||||
// We provide non-explicit singleton constructors so users can pass
|
||||
// in a "const char*" or a "string" wherever a "StringPiece" is
|
||||
// expected.
|
||||
//
|
||||
// Style guide exception granted:
|
||||
// http://goto/style-guide-exception-20978288
|
||||
StringPiece() : ptr_(nullptr), length_(0) {}
|
||||
|
||||
StringPiece(const char* str) // NOLINT(runtime/explicit)
|
||||
: ptr_(str), length_(0) {
|
||||
if (str != nullptr) {
|
||||
length_ = CheckedSsizeTFromSizeT(strlen(str));
|
||||
}
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
StringPiece( // NOLINT(runtime/explicit)
|
||||
const std::basic_string<char, std::char_traits<char>, Allocator>& str)
|
||||
: ptr_(str.data()), length_(0) {
|
||||
length_ = CheckedSsizeTFromSizeT(str.size());
|
||||
}
|
||||
|
||||
StringPiece(const char* offset, stringpiece_ssize_type len)
|
||||
: ptr_(offset), length_(len) {
|
||||
assert(len >= 0);
|
||||
}
|
||||
|
||||
// Substring of another StringPiece.
|
||||
// pos must be non-negative and <= x.length().
|
||||
StringPiece(StringPiece x, stringpiece_ssize_type pos);
|
||||
// Substring of another StringPiece.
|
||||
// pos must be non-negative and <= x.length().
|
||||
// len must be non-negative and will be pinned to at most x.length() - pos.
|
||||
StringPiece(StringPiece x,
|
||||
stringpiece_ssize_type pos,
|
||||
stringpiece_ssize_type len);
|
||||
|
||||
// data() may return a pointer to a buffer with embedded NULs, and the
|
||||
// returned buffer may or may not be null terminated. Therefore it is
|
||||
// typically a mistake to pass data() to a routine that expects a NUL
|
||||
// terminated string.
|
||||
const char* data() const { return ptr_; }
|
||||
stringpiece_ssize_type size() const { return length_; }
|
||||
stringpiece_ssize_type length() const { return length_; }
|
||||
bool empty() const { return length_ == 0; }
|
||||
|
||||
void clear() {
|
||||
ptr_ = nullptr;
|
||||
length_ = 0;
|
||||
}
|
||||
|
||||
void set(const char* data, stringpiece_ssize_type len) {
|
||||
assert(len >= 0);
|
||||
ptr_ = data;
|
||||
length_ = len;
|
||||
}
|
||||
|
||||
void set(const char* str) {
|
||||
ptr_ = str;
|
||||
if (str != nullptr)
|
||||
length_ = CheckedSsizeTFromSizeT(strlen(str));
|
||||
else
|
||||
length_ = 0;
|
||||
}
|
||||
|
||||
void set(const void* data, stringpiece_ssize_type len) {
|
||||
ptr_ = reinterpret_cast<const char*>(data);
|
||||
length_ = len;
|
||||
}
|
||||
|
||||
char operator[](stringpiece_ssize_type i) const {
|
||||
assert(0 <= i);
|
||||
assert(i < length_);
|
||||
return ptr_[i];
|
||||
}
|
||||
|
||||
void remove_prefix(stringpiece_ssize_type n) {
|
||||
assert(length_ >= n);
|
||||
ptr_ += n;
|
||||
length_ -= n;
|
||||
}
|
||||
|
||||
void remove_suffix(stringpiece_ssize_type n) {
|
||||
assert(length_ >= n);
|
||||
length_ -= n;
|
||||
}
|
||||
|
||||
// returns {-1, 0, 1}
|
||||
int compare(StringPiece x) const {
|
||||
const stringpiece_ssize_type min_size =
|
||||
length_ < x.length_ ? length_ : x.length_;
|
||||
int r = memcmp(ptr_, x.ptr_, static_cast<size_t>(min_size));
|
||||
if (r < 0) return -1;
|
||||
if (r > 0) return 1;
|
||||
if (length_ < x.length_) return -1;
|
||||
if (length_ > x.length_) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string as_string() const { return ToString(); }
|
||||
// We also define ToString() here, since many other string-like
|
||||
// interfaces name the routine that converts to a C++ string
|
||||
// "ToString", and it's confusing to have the method that does that
|
||||
// for a StringPiece be called "as_string()". We also leave the
|
||||
// "as_string()" method defined here for existing code.
|
||||
std::string ToString() const {
|
||||
if (ptr_ == nullptr) return "";
|
||||
return std::string(data(), static_cast<size_type>(size()));
|
||||
}
|
||||
|
||||
explicit operator std::string() const { return ToString(); }
|
||||
|
||||
void CopyToString(std::string* target) const;
|
||||
void AppendToString(std::string* target) const;
|
||||
|
||||
bool starts_with(StringPiece x) const {
|
||||
return (length_ >= x.length_) &&
|
||||
(memcmp(ptr_, x.ptr_, static_cast<size_t>(x.length_)) == 0);
|
||||
}
|
||||
|
||||
bool ends_with(StringPiece x) const {
|
||||
return ((length_ >= x.length_) &&
|
||||
(memcmp(ptr_ + (length_-x.length_), x.ptr_,
|
||||
static_cast<size_t>(x.length_)) == 0));
|
||||
}
|
||||
|
||||
// Checks whether StringPiece starts with x and if so advances the beginning
|
||||
// of it to past the match. It's basically a shortcut for starts_with
|
||||
// followed by remove_prefix.
|
||||
bool Consume(StringPiece x);
|
||||
// Like above but for the end of the string.
|
||||
bool ConsumeFromEnd(StringPiece x);
|
||||
|
||||
// standard STL container boilerplate
|
||||
typedef char value_type;
|
||||
typedef const char* pointer;
|
||||
typedef const char& reference;
|
||||
typedef const char& const_reference;
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
static const size_type npos;
|
||||
typedef const char* const_iterator;
|
||||
typedef const char* iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
iterator begin() const { return ptr_; }
|
||||
iterator end() const { return ptr_ + length_; }
|
||||
const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(ptr_ + length_);
|
||||
}
|
||||
const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(ptr_);
|
||||
}
|
||||
stringpiece_ssize_type max_size() const { return length_; }
|
||||
stringpiece_ssize_type capacity() const { return length_; }
|
||||
|
||||
// cpplint.py emits a false positive [build/include_what_you_use]
|
||||
stringpiece_ssize_type copy(char* buf, size_type n, size_type pos = 0) const; // NOLINT
|
||||
|
||||
bool contains(StringPiece s) const;
|
||||
|
||||
stringpiece_ssize_type find(StringPiece s, size_type pos = 0) const;
|
||||
stringpiece_ssize_type find(char c, size_type pos = 0) const;
|
||||
stringpiece_ssize_type rfind(StringPiece s, size_type pos = npos) const;
|
||||
stringpiece_ssize_type rfind(char c, size_type pos = npos) const;
|
||||
|
||||
stringpiece_ssize_type find_first_of(StringPiece s, size_type pos = 0) const;
|
||||
stringpiece_ssize_type find_first_of(char c, size_type pos = 0) const {
|
||||
return find(c, pos);
|
||||
}
|
||||
stringpiece_ssize_type find_first_not_of(StringPiece s,
|
||||
size_type pos = 0) const;
|
||||
stringpiece_ssize_type find_first_not_of(char c, size_type pos = 0) const;
|
||||
stringpiece_ssize_type find_last_of(StringPiece s,
|
||||
size_type pos = npos) const;
|
||||
stringpiece_ssize_type find_last_of(char c, size_type pos = npos) const {
|
||||
return rfind(c, pos);
|
||||
}
|
||||
stringpiece_ssize_type find_last_not_of(StringPiece s,
|
||||
size_type pos = npos) const;
|
||||
stringpiece_ssize_type find_last_not_of(char c, size_type pos = npos) const;
|
||||
|
||||
StringPiece substr(size_type pos, size_type n = npos) const;
|
||||
};
|
||||
|
||||
// This large function is defined inline so that in a fairly common case where
|
||||
// one of the arguments is a literal, the compiler can elide a lot of the
|
||||
// following comparisons.
|
||||
inline bool operator==(StringPiece x, StringPiece y) {
|
||||
stringpiece_ssize_type len = x.size();
|
||||
if (len != y.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return x.data() == y.data() || len <= 0 ||
|
||||
memcmp(x.data(), y.data(), static_cast<size_t>(len)) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(StringPiece x, StringPiece y) {
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
inline bool operator<(StringPiece x, StringPiece y) {
|
||||
const stringpiece_ssize_type min_size =
|
||||
x.size() < y.size() ? x.size() : y.size();
|
||||
const int r = memcmp(x.data(), y.data(), static_cast<size_t>(min_size));
|
||||
return (r < 0) || (r == 0 && x.size() < y.size());
|
||||
}
|
||||
|
||||
inline bool operator>(StringPiece x, StringPiece y) {
|
||||
return y < x;
|
||||
}
|
||||
|
||||
inline bool operator<=(StringPiece x, StringPiece y) {
|
||||
return !(x > y);
|
||||
}
|
||||
|
||||
inline bool operator>=(StringPiece x, StringPiece y) {
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
// allow StringPiece to be logged
|
||||
extern std::ostream& operator<<(std::ostream& o, StringPiece piece);
|
||||
|
||||
namespace internal {
|
||||
// StringPiece is not a POD and can not be used in an union (pre C++11). We
|
||||
// need a POD version of it.
|
||||
struct StringPiecePod {
|
||||
// Create from a StringPiece.
|
||||
static StringPiecePod CreateFromStringPiece(StringPiece str) {
|
||||
StringPiecePod pod;
|
||||
pod.data_ = str.data();
|
||||
pod.size_ = str.size();
|
||||
return pod;
|
||||
}
|
||||
|
||||
// Cast to StringPiece.
|
||||
operator StringPiece() const { return StringPiece(data_, size_); }
|
||||
|
||||
bool operator==(const char* value) const {
|
||||
return StringPiece(data_, size_) == StringPiece(value);
|
||||
}
|
||||
|
||||
char operator[](stringpiece_ssize_type i) const {
|
||||
assert(0 <= i);
|
||||
assert(i < size_);
|
||||
return data_[i];
|
||||
}
|
||||
|
||||
const char* data() const { return data_; }
|
||||
|
||||
stringpiece_ssize_type size() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
std::string ToString() const {
|
||||
return std::string(data_, static_cast<size_t>(size_));
|
||||
}
|
||||
|
||||
explicit operator std::string() const { return ToString(); }
|
||||
|
||||
private:
|
||||
const char* data_;
|
||||
stringpiece_ssize_type size_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START
|
||||
template<> struct hash<StringPiece> {
|
||||
size_t operator()(const StringPiece& s) const {
|
||||
size_t result = 0;
|
||||
for (const char *str = s.data(), *end = str + s.size(); str < end; str++) {
|
||||
result = 5 * result + static_cast<size_t>(*str);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // STRINGS_STRINGPIECE_H_
|
||||
796
ubuntu/google/protobuf/stubs/stringpiece_unittest.cc
Normal file
796
ubuntu/google/protobuf/stubs/stringpiece_unittest.cc
Normal file
@@ -0,0 +1,796 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <google/protobuf/stubs/stringpiece.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
TEST(StringPiece, Ctor) {
|
||||
{
|
||||
// Null.
|
||||
StringPiece s10;
|
||||
EXPECT_TRUE(s10.data() == nullptr);
|
||||
EXPECT_EQ(0, s10.length());
|
||||
}
|
||||
|
||||
{
|
||||
// const char* without length.
|
||||
const char* hello = "hello";
|
||||
StringPiece s20(hello);
|
||||
EXPECT_TRUE(s20.data() == hello);
|
||||
EXPECT_EQ(5, s20.length());
|
||||
|
||||
// const char* with length.
|
||||
StringPiece s21(hello, 4);
|
||||
EXPECT_TRUE(s21.data() == hello);
|
||||
EXPECT_EQ(4, s21.length());
|
||||
|
||||
// Not recommended, but valid C++
|
||||
StringPiece s22(hello, 6);
|
||||
EXPECT_TRUE(s22.data() == hello);
|
||||
EXPECT_EQ(6, s22.length());
|
||||
}
|
||||
|
||||
{
|
||||
// std::string.
|
||||
std::string hola = "hola";
|
||||
StringPiece s30(hola);
|
||||
EXPECT_TRUE(s30.data() == hola.data());
|
||||
EXPECT_EQ(4, s30.length());
|
||||
|
||||
// std::string with embedded '\0'.
|
||||
hola.push_back('\0');
|
||||
hola.append("h2");
|
||||
hola.push_back('\0');
|
||||
StringPiece s31(hola);
|
||||
EXPECT_TRUE(s31.data() == hola.data());
|
||||
EXPECT_EQ(8, s31.length());
|
||||
}
|
||||
|
||||
#if defined(HAS_GLOBAL_STRING)
|
||||
{
|
||||
// ::string
|
||||
std::string bonjour = "bonjour";
|
||||
StringPiece s40(bonjour);
|
||||
EXPECT_TRUE(s40.data() == bonjour.data());
|
||||
EXPECT_EQ(7, s40.length());
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO(mec): StringPiece(StringPiece x, int pos);
|
||||
// TODO(mec): StringPiece(StringPiece x, int pos, int len);
|
||||
// TODO(mec): StringPiece(const StringPiece&);
|
||||
}
|
||||
|
||||
TEST(StringPiece, STLComparator) {
|
||||
std::string s1("foo");
|
||||
std::string s2("bar");
|
||||
std::string s3("baz");
|
||||
|
||||
StringPiece p1(s1);
|
||||
StringPiece p2(s2);
|
||||
StringPiece p3(s3);
|
||||
|
||||
typedef std::map<StringPiece, int> TestMap;
|
||||
TestMap map;
|
||||
|
||||
map.insert(std::make_pair(p1, 0));
|
||||
map.insert(std::make_pair(p2, 1));
|
||||
map.insert(std::make_pair(p3, 2));
|
||||
EXPECT_EQ(map.size(), 3);
|
||||
|
||||
TestMap::const_iterator iter = map.begin();
|
||||
EXPECT_EQ(iter->second, 1);
|
||||
++iter;
|
||||
EXPECT_EQ(iter->second, 2);
|
||||
++iter;
|
||||
EXPECT_EQ(iter->second, 0);
|
||||
++iter;
|
||||
EXPECT_TRUE(iter == map.end());
|
||||
|
||||
TestMap::iterator new_iter = map.find("zot");
|
||||
EXPECT_TRUE(new_iter == map.end());
|
||||
|
||||
new_iter = map.find("bar");
|
||||
EXPECT_TRUE(new_iter != map.end());
|
||||
|
||||
map.erase(new_iter);
|
||||
EXPECT_EQ(map.size(), 2);
|
||||
|
||||
iter = map.begin();
|
||||
EXPECT_EQ(iter->second, 2);
|
||||
++iter;
|
||||
EXPECT_EQ(iter->second, 0);
|
||||
++iter;
|
||||
EXPECT_TRUE(iter == map.end());
|
||||
}
|
||||
|
||||
TEST(StringPiece, ComparisonOperators) {
|
||||
#define COMPARE(result, op, x, y) \
|
||||
EXPECT_EQ(result, StringPiece((x)) op StringPiece((y))); \
|
||||
EXPECT_EQ(result, StringPiece((x)).compare(StringPiece((y))) op 0)
|
||||
|
||||
COMPARE(true, ==, "", "");
|
||||
COMPARE(true, ==, "", nullptr);
|
||||
COMPARE(true, ==, nullptr, "");
|
||||
COMPARE(true, ==, "a", "a");
|
||||
COMPARE(true, ==, "aa", "aa");
|
||||
COMPARE(false, ==, "a", "");
|
||||
COMPARE(false, ==, "", "a");
|
||||
COMPARE(false, ==, "a", "b");
|
||||
COMPARE(false, ==, "a", "aa");
|
||||
COMPARE(false, ==, "aa", "a");
|
||||
|
||||
COMPARE(false, !=, "", "");
|
||||
COMPARE(false, !=, "a", "a");
|
||||
COMPARE(false, !=, "aa", "aa");
|
||||
COMPARE(true, !=, "a", "");
|
||||
COMPARE(true, !=, "", "a");
|
||||
COMPARE(true, !=, "a", "b");
|
||||
COMPARE(true, !=, "a", "aa");
|
||||
COMPARE(true, !=, "aa", "a");
|
||||
|
||||
COMPARE(true, <, "a", "b");
|
||||
COMPARE(true, <, "a", "aa");
|
||||
COMPARE(true, <, "aa", "b");
|
||||
COMPARE(true, <, "aa", "bb");
|
||||
COMPARE(false, <, "a", "a");
|
||||
COMPARE(false, <, "b", "a");
|
||||
COMPARE(false, <, "aa", "a");
|
||||
COMPARE(false, <, "b", "aa");
|
||||
COMPARE(false, <, "bb", "aa");
|
||||
|
||||
COMPARE(true, <=, "a", "a");
|
||||
COMPARE(true, <=, "a", "b");
|
||||
COMPARE(true, <=, "a", "aa");
|
||||
COMPARE(true, <=, "aa", "b");
|
||||
COMPARE(true, <=, "aa", "bb");
|
||||
COMPARE(false, <=, "b", "a");
|
||||
COMPARE(false, <=, "aa", "a");
|
||||
COMPARE(false, <=, "b", "aa");
|
||||
COMPARE(false, <=, "bb", "aa");
|
||||
|
||||
COMPARE(false, >=, "a", "b");
|
||||
COMPARE(false, >=, "a", "aa");
|
||||
COMPARE(false, >=, "aa", "b");
|
||||
COMPARE(false, >=, "aa", "bb");
|
||||
COMPARE(true, >=, "a", "a");
|
||||
COMPARE(true, >=, "b", "a");
|
||||
COMPARE(true, >=, "aa", "a");
|
||||
COMPARE(true, >=, "b", "aa");
|
||||
COMPARE(true, >=, "bb", "aa");
|
||||
|
||||
COMPARE(false, >, "a", "a");
|
||||
COMPARE(false, >, "a", "b");
|
||||
COMPARE(false, >, "a", "aa");
|
||||
COMPARE(false, >, "aa", "b");
|
||||
COMPARE(false, >, "aa", "bb");
|
||||
COMPARE(true, >, "b", "a");
|
||||
COMPARE(true, >, "aa", "a");
|
||||
COMPARE(true, >, "b", "aa");
|
||||
COMPARE(true, >, "bb", "aa");
|
||||
|
||||
std::string x;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
x += 'a';
|
||||
std::string y = x;
|
||||
COMPARE(true, ==, x, y);
|
||||
for (int j = 0; j < i; j++) {
|
||||
std::string z = x;
|
||||
z[j] = 'b'; // Differs in position 'j'
|
||||
COMPARE(false, ==, x, z);
|
||||
COMPARE(true, <, x, z);
|
||||
COMPARE(true, >, z, x);
|
||||
if (j + 1 < i) {
|
||||
z[j + 1] = 'A'; // Differs in position 'j+1' as well
|
||||
COMPARE(false, ==, x, z);
|
||||
COMPARE(true, <, x, z);
|
||||
COMPARE(true, >, z, x);
|
||||
z[j + 1] = 'z'; // Differs in position 'j+1' as well
|
||||
COMPARE(false, ==, x, z);
|
||||
COMPARE(true, <, x, z);
|
||||
COMPARE(true, >, z, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef COMPARE
|
||||
}
|
||||
|
||||
TEST(StringPiece, STL1) {
|
||||
const StringPiece a("abcdefghijklmnopqrstuvwxyz");
|
||||
const StringPiece b("abc");
|
||||
const StringPiece c("xyz");
|
||||
const StringPiece d("foobar");
|
||||
const StringPiece e;
|
||||
std::string temp("123");
|
||||
temp += '\0';
|
||||
temp += "456";
|
||||
const StringPiece f(temp);
|
||||
|
||||
EXPECT_EQ(a[6], 'g');
|
||||
EXPECT_EQ(b[0], 'a');
|
||||
EXPECT_EQ(c[2], 'z');
|
||||
EXPECT_EQ(f[3], '\0');
|
||||
EXPECT_EQ(f[5], '5');
|
||||
|
||||
EXPECT_EQ(*d.data(), 'f');
|
||||
EXPECT_EQ(d.data()[5], 'r');
|
||||
EXPECT_TRUE(e.data() == nullptr);
|
||||
|
||||
EXPECT_EQ(*a.begin(), 'a');
|
||||
EXPECT_EQ(*(b.begin() + 2), 'c');
|
||||
EXPECT_EQ(*(c.end() - 1), 'z');
|
||||
|
||||
EXPECT_EQ(*a.rbegin(), 'z');
|
||||
EXPECT_EQ(*(b.rbegin() + 2), 'a');
|
||||
EXPECT_EQ(*(c.rend() - 1), 'x');
|
||||
EXPECT_TRUE(a.rbegin() + 26 == a.rend());
|
||||
|
||||
EXPECT_EQ(a.size(), 26);
|
||||
EXPECT_EQ(b.size(), 3);
|
||||
EXPECT_EQ(c.size(), 3);
|
||||
EXPECT_EQ(d.size(), 6);
|
||||
EXPECT_EQ(e.size(), 0);
|
||||
EXPECT_EQ(f.size(), 7);
|
||||
|
||||
EXPECT_TRUE(!d.empty());
|
||||
EXPECT_TRUE(d.begin() != d.end());
|
||||
EXPECT_TRUE(d.begin() + 6 == d.end());
|
||||
|
||||
EXPECT_TRUE(e.empty());
|
||||
EXPECT_TRUE(e.begin() == e.end());
|
||||
|
||||
EXPECT_GE(a.max_size(), a.capacity());
|
||||
EXPECT_GE(a.capacity(), a.size());
|
||||
|
||||
char buf[4] = { '%', '%', '%', '%' };
|
||||
EXPECT_EQ(a.copy(buf, 4), 4);
|
||||
EXPECT_EQ(buf[0], a[0]);
|
||||
EXPECT_EQ(buf[1], a[1]);
|
||||
EXPECT_EQ(buf[2], a[2]);
|
||||
EXPECT_EQ(buf[3], a[3]);
|
||||
EXPECT_EQ(a.copy(buf, 3, 7), 3);
|
||||
EXPECT_EQ(buf[0], a[7]);
|
||||
EXPECT_EQ(buf[1], a[8]);
|
||||
EXPECT_EQ(buf[2], a[9]);
|
||||
EXPECT_EQ(buf[3], a[3]);
|
||||
EXPECT_EQ(c.copy(buf, 99), 3);
|
||||
EXPECT_EQ(buf[0], c[0]);
|
||||
EXPECT_EQ(buf[1], c[1]);
|
||||
EXPECT_EQ(buf[2], c[2]);
|
||||
EXPECT_EQ(buf[3], a[3]);
|
||||
}
|
||||
|
||||
// Separated from STL1() because some compilers produce an overly
|
||||
// large stack frame for the combined function.
|
||||
TEST(StringPiece, STL2) {
|
||||
const StringPiece a("abcdefghijklmnopqrstuvwxyz");
|
||||
const StringPiece b("abc");
|
||||
const StringPiece c("xyz");
|
||||
StringPiece d("foobar");
|
||||
const StringPiece e;
|
||||
const StringPiece f("123" "\0" "456", 7);
|
||||
|
||||
d.clear();
|
||||
EXPECT_EQ(d.size(), 0);
|
||||
EXPECT_TRUE(d.empty());
|
||||
EXPECT_TRUE(d.data() == nullptr);
|
||||
EXPECT_TRUE(d.begin() == d.end());
|
||||
|
||||
EXPECT_EQ(StringPiece::npos, std::string::npos);
|
||||
|
||||
EXPECT_EQ(a.find(b), 0);
|
||||
EXPECT_EQ(a.find(b, 1), StringPiece::npos);
|
||||
EXPECT_EQ(a.find(c), 23);
|
||||
EXPECT_EQ(a.find(c, 9), 23);
|
||||
EXPECT_EQ(a.find(c, StringPiece::npos), StringPiece::npos);
|
||||
EXPECT_EQ(b.find(c), StringPiece::npos);
|
||||
EXPECT_EQ(b.find(c, StringPiece::npos), StringPiece::npos);
|
||||
EXPECT_EQ(a.find(d), 0);
|
||||
EXPECT_EQ(a.find(e), 0);
|
||||
EXPECT_EQ(a.find(d, 12), 12);
|
||||
EXPECT_EQ(a.find(e, 17), 17);
|
||||
StringPiece g("xx not found bb");
|
||||
EXPECT_EQ(a.find(g), StringPiece::npos);
|
||||
// empty string nonsense
|
||||
EXPECT_EQ(d.find(b), StringPiece::npos);
|
||||
EXPECT_EQ(e.find(b), StringPiece::npos);
|
||||
EXPECT_EQ(d.find(b, 4), StringPiece::npos);
|
||||
EXPECT_EQ(e.find(b, 7), StringPiece::npos);
|
||||
|
||||
size_t empty_search_pos = std::string().find(std::string());
|
||||
EXPECT_EQ(d.find(d), empty_search_pos);
|
||||
EXPECT_EQ(d.find(e), empty_search_pos);
|
||||
EXPECT_EQ(e.find(d), empty_search_pos);
|
||||
EXPECT_EQ(e.find(e), empty_search_pos);
|
||||
EXPECT_EQ(d.find(d, 4), std::string().find(std::string(), 4));
|
||||
EXPECT_EQ(d.find(e, 4), std::string().find(std::string(), 4));
|
||||
EXPECT_EQ(e.find(d, 4), std::string().find(std::string(), 4));
|
||||
EXPECT_EQ(e.find(e, 4), std::string().find(std::string(), 4));
|
||||
|
||||
EXPECT_EQ(a.find('a'), 0);
|
||||
EXPECT_EQ(a.find('c'), 2);
|
||||
EXPECT_EQ(a.find('z'), 25);
|
||||
EXPECT_EQ(a.find('$'), StringPiece::npos);
|
||||
EXPECT_EQ(a.find('\0'), StringPiece::npos);
|
||||
EXPECT_EQ(f.find('\0'), 3);
|
||||
EXPECT_EQ(f.find('3'), 2);
|
||||
EXPECT_EQ(f.find('5'), 5);
|
||||
EXPECT_EQ(g.find('o'), 4);
|
||||
EXPECT_EQ(g.find('o', 4), 4);
|
||||
EXPECT_EQ(g.find('o', 5), 8);
|
||||
EXPECT_EQ(a.find('b', 5), StringPiece::npos);
|
||||
// empty string nonsense
|
||||
EXPECT_EQ(d.find('\0'), StringPiece::npos);
|
||||
EXPECT_EQ(e.find('\0'), StringPiece::npos);
|
||||
EXPECT_EQ(d.find('\0', 4), StringPiece::npos);
|
||||
EXPECT_EQ(e.find('\0', 7), StringPiece::npos);
|
||||
EXPECT_EQ(d.find('x'), StringPiece::npos);
|
||||
EXPECT_EQ(e.find('x'), StringPiece::npos);
|
||||
EXPECT_EQ(d.find('x', 4), StringPiece::npos);
|
||||
EXPECT_EQ(e.find('x', 7), StringPiece::npos);
|
||||
|
||||
EXPECT_EQ(a.rfind(b), 0);
|
||||
EXPECT_EQ(a.rfind(b, 1), 0);
|
||||
EXPECT_EQ(a.rfind(c), 23);
|
||||
EXPECT_EQ(a.rfind(c, 22), StringPiece::npos);
|
||||
EXPECT_EQ(a.rfind(c, 1), StringPiece::npos);
|
||||
EXPECT_EQ(a.rfind(c, 0), StringPiece::npos);
|
||||
EXPECT_EQ(b.rfind(c), StringPiece::npos);
|
||||
EXPECT_EQ(b.rfind(c, 0), StringPiece::npos);
|
||||
EXPECT_EQ(a.rfind(d), a.as_string().rfind(std::string()));
|
||||
EXPECT_EQ(a.rfind(e), a.as_string().rfind(std::string()));
|
||||
EXPECT_EQ(a.rfind(d, 12), 12);
|
||||
EXPECT_EQ(a.rfind(e, 17), 17);
|
||||
EXPECT_EQ(a.rfind(g), StringPiece::npos);
|
||||
EXPECT_EQ(d.rfind(b), StringPiece::npos);
|
||||
EXPECT_EQ(e.rfind(b), StringPiece::npos);
|
||||
EXPECT_EQ(d.rfind(b, 4), StringPiece::npos);
|
||||
EXPECT_EQ(e.rfind(b, 7), StringPiece::npos);
|
||||
// empty string nonsense
|
||||
EXPECT_EQ(d.rfind(d, 4), std::string().rfind(std::string()));
|
||||
EXPECT_EQ(e.rfind(d, 7), std::string().rfind(std::string()));
|
||||
EXPECT_EQ(d.rfind(e, 4), std::string().rfind(std::string()));
|
||||
EXPECT_EQ(e.rfind(e, 7), std::string().rfind(std::string()));
|
||||
EXPECT_EQ(d.rfind(d), std::string().rfind(std::string()));
|
||||
EXPECT_EQ(e.rfind(d), std::string().rfind(std::string()));
|
||||
EXPECT_EQ(d.rfind(e), std::string().rfind(std::string()));
|
||||
EXPECT_EQ(e.rfind(e), std::string().rfind(std::string()));
|
||||
|
||||
EXPECT_EQ(g.rfind('o'), 8);
|
||||
EXPECT_EQ(g.rfind('q'), StringPiece::npos);
|
||||
EXPECT_EQ(g.rfind('o', 8), 8);
|
||||
EXPECT_EQ(g.rfind('o', 7), 4);
|
||||
EXPECT_EQ(g.rfind('o', 3), StringPiece::npos);
|
||||
EXPECT_EQ(f.rfind('\0'), 3);
|
||||
EXPECT_EQ(f.rfind('\0', 12), 3);
|
||||
EXPECT_EQ(f.rfind('3'), 2);
|
||||
EXPECT_EQ(f.rfind('5'), 5);
|
||||
// empty string nonsense
|
||||
EXPECT_EQ(d.rfind('o'), StringPiece::npos);
|
||||
EXPECT_EQ(e.rfind('o'), StringPiece::npos);
|
||||
EXPECT_EQ(d.rfind('o', 4), StringPiece::npos);
|
||||
EXPECT_EQ(e.rfind('o', 7), StringPiece::npos);
|
||||
|
||||
EXPECT_EQ(a.find_first_of(b), 0);
|
||||
EXPECT_EQ(a.find_first_of(b, 0), 0);
|
||||
EXPECT_EQ(a.find_first_of(b, 1), 1);
|
||||
EXPECT_EQ(a.find_first_of(b, 2), 2);
|
||||
EXPECT_EQ(a.find_first_of(b, 3), StringPiece::npos);
|
||||
EXPECT_EQ(a.find_first_of(c), 23);
|
||||
EXPECT_EQ(a.find_first_of(c, 23), 23);
|
||||
EXPECT_EQ(a.find_first_of(c, 24), 24);
|
||||
EXPECT_EQ(a.find_first_of(c, 25), 25);
|
||||
EXPECT_EQ(a.find_first_of(c, 26), StringPiece::npos);
|
||||
EXPECT_EQ(g.find_first_of(b), 13);
|
||||
EXPECT_EQ(g.find_first_of(c), 0);
|
||||
EXPECT_EQ(a.find_first_of(f), StringPiece::npos);
|
||||
EXPECT_EQ(f.find_first_of(a), StringPiece::npos);
|
||||
// empty string nonsense
|
||||
EXPECT_EQ(a.find_first_of(d), StringPiece::npos);
|
||||
EXPECT_EQ(a.find_first_of(e), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_first_of(b), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_first_of(b), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_first_of(d), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_first_of(d), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_first_of(e), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_first_of(e), StringPiece::npos);
|
||||
|
||||
EXPECT_EQ(a.find_first_not_of(b), 3);
|
||||
EXPECT_EQ(a.find_first_not_of(c), 0);
|
||||
EXPECT_EQ(b.find_first_not_of(a), StringPiece::npos);
|
||||
EXPECT_EQ(c.find_first_not_of(a), StringPiece::npos);
|
||||
EXPECT_EQ(f.find_first_not_of(a), 0);
|
||||
EXPECT_EQ(a.find_first_not_of(f), 0);
|
||||
EXPECT_EQ(a.find_first_not_of(d), 0);
|
||||
EXPECT_EQ(a.find_first_not_of(e), 0);
|
||||
// empty string nonsense
|
||||
EXPECT_EQ(d.find_first_not_of(a), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_first_not_of(a), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_first_not_of(d), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_first_not_of(d), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_first_not_of(e), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_first_not_of(e), StringPiece::npos);
|
||||
|
||||
StringPiece h("====");
|
||||
EXPECT_EQ(h.find_first_not_of('='), StringPiece::npos);
|
||||
EXPECT_EQ(h.find_first_not_of('=', 3), StringPiece::npos);
|
||||
EXPECT_EQ(h.find_first_not_of('\0'), 0);
|
||||
EXPECT_EQ(g.find_first_not_of('x'), 2);
|
||||
EXPECT_EQ(f.find_first_not_of('\0'), 0);
|
||||
EXPECT_EQ(f.find_first_not_of('\0', 3), 4);
|
||||
EXPECT_EQ(f.find_first_not_of('\0', 2), 2);
|
||||
// empty string nonsense
|
||||
EXPECT_EQ(d.find_first_not_of('x'), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_first_not_of('x'), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_first_not_of('\0'), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_first_not_of('\0'), StringPiece::npos);
|
||||
|
||||
// StringPiece g("xx not found bb");
|
||||
StringPiece i("56");
|
||||
EXPECT_EQ(h.find_last_of(a), StringPiece::npos);
|
||||
EXPECT_EQ(g.find_last_of(a), g.size()-1);
|
||||
EXPECT_EQ(a.find_last_of(b), 2);
|
||||
EXPECT_EQ(a.find_last_of(c), a.size()-1);
|
||||
EXPECT_EQ(f.find_last_of(i), 6);
|
||||
EXPECT_EQ(a.find_last_of('a'), 0);
|
||||
EXPECT_EQ(a.find_last_of('b'), 1);
|
||||
EXPECT_EQ(a.find_last_of('z'), 25);
|
||||
EXPECT_EQ(a.find_last_of('a', 5), 0);
|
||||
EXPECT_EQ(a.find_last_of('b', 5), 1);
|
||||
EXPECT_EQ(a.find_last_of('b', 0), StringPiece::npos);
|
||||
EXPECT_EQ(a.find_last_of('z', 25), 25);
|
||||
EXPECT_EQ(a.find_last_of('z', 24), StringPiece::npos);
|
||||
EXPECT_EQ(f.find_last_of(i, 5), 5);
|
||||
EXPECT_EQ(f.find_last_of(i, 6), 6);
|
||||
EXPECT_EQ(f.find_last_of(a, 4), StringPiece::npos);
|
||||
// empty string nonsense
|
||||
EXPECT_EQ(f.find_last_of(d), StringPiece::npos);
|
||||
EXPECT_EQ(f.find_last_of(e), StringPiece::npos);
|
||||
EXPECT_EQ(f.find_last_of(d, 4), StringPiece::npos);
|
||||
EXPECT_EQ(f.find_last_of(e, 4), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_last_of(d), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_last_of(e), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_of(d), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_of(e), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_last_of(f), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_of(f), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_last_of(d, 4), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_last_of(e, 4), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_of(d, 4), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_of(e, 4), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_last_of(f, 4), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_of(f, 4), StringPiece::npos);
|
||||
|
||||
EXPECT_EQ(a.find_last_not_of(b), a.size()-1);
|
||||
EXPECT_EQ(a.find_last_not_of(c), 22);
|
||||
EXPECT_EQ(b.find_last_not_of(a), StringPiece::npos);
|
||||
EXPECT_EQ(b.find_last_not_of(b), StringPiece::npos);
|
||||
EXPECT_EQ(f.find_last_not_of(i), 4);
|
||||
EXPECT_EQ(a.find_last_not_of(c, 24), 22);
|
||||
EXPECT_EQ(a.find_last_not_of(b, 3), 3);
|
||||
EXPECT_EQ(a.find_last_not_of(b, 2), StringPiece::npos);
|
||||
// empty string nonsense
|
||||
EXPECT_EQ(f.find_last_not_of(d), f.size()-1);
|
||||
EXPECT_EQ(f.find_last_not_of(e), f.size()-1);
|
||||
EXPECT_EQ(f.find_last_not_of(d, 4), 4);
|
||||
EXPECT_EQ(f.find_last_not_of(e, 4), 4);
|
||||
EXPECT_EQ(d.find_last_not_of(d), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_last_not_of(e), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_not_of(d), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_not_of(e), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_last_not_of(f), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_not_of(f), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_last_not_of(d, 4), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_last_not_of(e, 4), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_not_of(d, 4), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_not_of(e, 4), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_last_not_of(f, 4), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_not_of(f, 4), StringPiece::npos);
|
||||
|
||||
EXPECT_EQ(h.find_last_not_of('x'), h.size() - 1);
|
||||
EXPECT_EQ(h.find_last_not_of('='), StringPiece::npos);
|
||||
EXPECT_EQ(b.find_last_not_of('c'), 1);
|
||||
EXPECT_EQ(h.find_last_not_of('x', 2), 2);
|
||||
EXPECT_EQ(h.find_last_not_of('=', 2), StringPiece::npos);
|
||||
EXPECT_EQ(b.find_last_not_of('b', 1), 0);
|
||||
// empty string nonsense
|
||||
EXPECT_EQ(d.find_last_not_of('x'), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_not_of('x'), StringPiece::npos);
|
||||
EXPECT_EQ(d.find_last_not_of('\0'), StringPiece::npos);
|
||||
EXPECT_EQ(e.find_last_not_of('\0'), StringPiece::npos);
|
||||
|
||||
EXPECT_EQ(a.substr(0, 3), b);
|
||||
EXPECT_EQ(a.substr(23), c);
|
||||
EXPECT_EQ(a.substr(23, 3), c);
|
||||
EXPECT_EQ(a.substr(23, 99), c);
|
||||
EXPECT_EQ(a.substr(0), a);
|
||||
EXPECT_EQ(a.substr(3, 2), "de");
|
||||
// empty string nonsense
|
||||
EXPECT_EQ(a.substr(99, 2), e);
|
||||
EXPECT_EQ(d.substr(99), e);
|
||||
EXPECT_EQ(d.substr(0, 99), e);
|
||||
EXPECT_EQ(d.substr(99, 99), e);
|
||||
// use of npos
|
||||
EXPECT_EQ(a.substr(0, StringPiece::npos), a);
|
||||
EXPECT_EQ(a.substr(23, StringPiece::npos), c);
|
||||
EXPECT_EQ(a.substr(StringPiece::npos, 0), e);
|
||||
EXPECT_EQ(a.substr(StringPiece::npos, 1), e);
|
||||
EXPECT_EQ(a.substr(StringPiece::npos, StringPiece::npos), e);
|
||||
|
||||
// Substring constructors.
|
||||
EXPECT_EQ(StringPiece(a, 0, 3), b);
|
||||
EXPECT_EQ(StringPiece(a, 23), c);
|
||||
EXPECT_EQ(StringPiece(a, 23, 3), c);
|
||||
EXPECT_EQ(StringPiece(a, 23, 99), c);
|
||||
EXPECT_EQ(StringPiece(a, 0), a);
|
||||
EXPECT_EQ(StringPiece(a, 3, 2), "de");
|
||||
// empty string nonsense
|
||||
EXPECT_EQ(StringPiece(d, 0, 99), e);
|
||||
// Verify that they work taking an actual string, not just a StringPiece.
|
||||
std::string a2 = a.as_string();
|
||||
EXPECT_EQ(StringPiece(a2, 0, 3), b);
|
||||
EXPECT_EQ(StringPiece(a2, 23), c);
|
||||
EXPECT_EQ(StringPiece(a2, 23, 3), c);
|
||||
EXPECT_EQ(StringPiece(a2, 23, 99), c);
|
||||
EXPECT_EQ(StringPiece(a2, 0), a);
|
||||
EXPECT_EQ(StringPiece(a2, 3, 2), "de");
|
||||
}
|
||||
|
||||
TEST(StringPiece, Custom) {
|
||||
StringPiece a("foobar");
|
||||
std::string s1("123");
|
||||
s1 += '\0';
|
||||
s1 += "456";
|
||||
StringPiece b(s1);
|
||||
StringPiece e;
|
||||
std::string s2;
|
||||
|
||||
// CopyToString
|
||||
a.CopyToString(&s2);
|
||||
EXPECT_EQ(s2.size(), 6);
|
||||
EXPECT_EQ(s2, "foobar");
|
||||
b.CopyToString(&s2);
|
||||
EXPECT_EQ(s2.size(), 7);
|
||||
EXPECT_EQ(s1, s2);
|
||||
e.CopyToString(&s2);
|
||||
EXPECT_TRUE(s2.empty());
|
||||
|
||||
// AppendToString
|
||||
s2.erase();
|
||||
a.AppendToString(&s2);
|
||||
EXPECT_EQ(s2.size(), 6);
|
||||
EXPECT_EQ(s2, "foobar");
|
||||
a.AppendToString(&s2);
|
||||
EXPECT_EQ(s2.size(), 12);
|
||||
EXPECT_EQ(s2, "foobarfoobar");
|
||||
|
||||
// starts_with
|
||||
EXPECT_TRUE(a.starts_with(a));
|
||||
EXPECT_TRUE(a.starts_with("foo"));
|
||||
EXPECT_TRUE(a.starts_with(e));
|
||||
EXPECT_TRUE(b.starts_with(s1));
|
||||
EXPECT_TRUE(b.starts_with(b));
|
||||
EXPECT_TRUE(b.starts_with(e));
|
||||
EXPECT_TRUE(e.starts_with(""));
|
||||
EXPECT_TRUE(!a.starts_with(b));
|
||||
EXPECT_TRUE(!b.starts_with(a));
|
||||
EXPECT_TRUE(!e.starts_with(a));
|
||||
|
||||
// ends with
|
||||
EXPECT_TRUE(a.ends_with(a));
|
||||
EXPECT_TRUE(a.ends_with("bar"));
|
||||
EXPECT_TRUE(a.ends_with(e));
|
||||
EXPECT_TRUE(b.ends_with(s1));
|
||||
EXPECT_TRUE(b.ends_with(b));
|
||||
EXPECT_TRUE(b.ends_with(e));
|
||||
EXPECT_TRUE(e.ends_with(""));
|
||||
EXPECT_TRUE(!a.ends_with(b));
|
||||
EXPECT_TRUE(!b.ends_with(a));
|
||||
EXPECT_TRUE(!e.ends_with(a));
|
||||
|
||||
// remove_prefix
|
||||
StringPiece c(a);
|
||||
c.remove_prefix(3);
|
||||
EXPECT_EQ(c, "bar");
|
||||
c = a;
|
||||
c.remove_prefix(0);
|
||||
EXPECT_EQ(c, a);
|
||||
c.remove_prefix(c.size());
|
||||
EXPECT_EQ(c, e);
|
||||
|
||||
// remove_suffix
|
||||
c = a;
|
||||
c.remove_suffix(3);
|
||||
EXPECT_EQ(c, "foo");
|
||||
c = a;
|
||||
c.remove_suffix(0);
|
||||
EXPECT_EQ(c, a);
|
||||
c.remove_suffix(c.size());
|
||||
EXPECT_EQ(c, e);
|
||||
|
||||
// set
|
||||
c.set("foobar", 6);
|
||||
EXPECT_EQ(c, a);
|
||||
c.set("foobar", 0);
|
||||
EXPECT_EQ(c, e);
|
||||
c.set("foobar", 7);
|
||||
EXPECT_NE(c, a);
|
||||
|
||||
c.set("foobar");
|
||||
EXPECT_EQ(c, a);
|
||||
|
||||
c.set(static_cast<const void*>("foobar"), 6);
|
||||
EXPECT_EQ(c, a);
|
||||
c.set(static_cast<const void*>("foobar"), 0);
|
||||
EXPECT_EQ(c, e);
|
||||
c.set(static_cast<const void*>("foobar"), 7);
|
||||
EXPECT_NE(c, a);
|
||||
|
||||
// as_string
|
||||
std::string s3(a.as_string().c_str(), 7);
|
||||
EXPECT_EQ(c, s3);
|
||||
std::string s4(e.as_string());
|
||||
EXPECT_TRUE(s4.empty());
|
||||
|
||||
// ToString
|
||||
{
|
||||
std::string s5(a.ToString().c_str(), 7);
|
||||
EXPECT_EQ(c, s5);
|
||||
std::string s6(e.ToString());
|
||||
EXPECT_TRUE(s6.empty());
|
||||
}
|
||||
|
||||
// Consume
|
||||
a.set("foobar");
|
||||
EXPECT_TRUE(a.Consume("foo"));
|
||||
EXPECT_EQ(a, "bar");
|
||||
EXPECT_FALSE(a.Consume("foo"));
|
||||
EXPECT_FALSE(a.Consume("barbar"));
|
||||
EXPECT_FALSE(a.Consume("ar"));
|
||||
EXPECT_EQ(a, "bar");
|
||||
|
||||
a.set("foobar");
|
||||
EXPECT_TRUE(a.ConsumeFromEnd("bar"));
|
||||
EXPECT_EQ(a, "foo");
|
||||
EXPECT_FALSE(a.ConsumeFromEnd("bar"));
|
||||
EXPECT_FALSE(a.ConsumeFromEnd("foofoo"));
|
||||
EXPECT_FALSE(a.ConsumeFromEnd("fo"));
|
||||
EXPECT_EQ(a, "foo");
|
||||
}
|
||||
|
||||
TEST(StringPiece, Contains) {
|
||||
StringPiece a("abcdefg");
|
||||
StringPiece b("abcd");
|
||||
StringPiece c("efg");
|
||||
StringPiece d("gh");
|
||||
EXPECT_TRUE(a.contains(b));
|
||||
EXPECT_TRUE(a.contains(c));
|
||||
EXPECT_TRUE(!a.contains(d));
|
||||
}
|
||||
|
||||
TEST(StringPiece, NullInput) {
|
||||
// we used to crash here, but now we don't.
|
||||
StringPiece s(nullptr);
|
||||
EXPECT_EQ(s.data(), (const char*)nullptr);
|
||||
EXPECT_EQ(s.size(), 0);
|
||||
|
||||
s.set(nullptr);
|
||||
EXPECT_EQ(s.data(), (const char*)nullptr);
|
||||
EXPECT_EQ(s.size(), 0);
|
||||
|
||||
// .ToString() on a StringPiece with nullptr should produce the empty string.
|
||||
EXPECT_EQ("", s.ToString());
|
||||
EXPECT_EQ("", s.as_string());
|
||||
}
|
||||
|
||||
TEST(StringPiece, Comparisons2) {
|
||||
StringPiece abc("abcdefghijklmnopqrstuvwxyz");
|
||||
|
||||
// check comparison operations on strings longer than 4 bytes.
|
||||
EXPECT_EQ(abc, StringPiece("abcdefghijklmnopqrstuvwxyz"));
|
||||
EXPECT_EQ(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxyz")), 0);
|
||||
|
||||
EXPECT_LT(abc, StringPiece("abcdefghijklmnopqrstuvwxzz"));
|
||||
EXPECT_LT(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxzz")), 0);
|
||||
|
||||
EXPECT_GT(abc, StringPiece("abcdefghijklmnopqrstuvwxyy"));
|
||||
EXPECT_GT(abc.compare(StringPiece("abcdefghijklmnopqrstuvwxyy")), 0);
|
||||
|
||||
// starts_with
|
||||
EXPECT_TRUE(abc.starts_with(abc));
|
||||
EXPECT_TRUE(abc.starts_with("abcdefghijklm"));
|
||||
EXPECT_TRUE(!abc.starts_with("abcdefguvwxyz"));
|
||||
|
||||
// ends_with
|
||||
EXPECT_TRUE(abc.ends_with(abc));
|
||||
EXPECT_TRUE(!abc.ends_with("abcdefguvwxyz"));
|
||||
EXPECT_TRUE(abc.ends_with("nopqrstuvwxyz"));
|
||||
}
|
||||
|
||||
TEST(ComparisonOpsTest, StringCompareNotAmbiguous) {
|
||||
EXPECT_EQ("hello", std::string("hello"));
|
||||
EXPECT_LT("hello", std::string("world"));
|
||||
}
|
||||
|
||||
TEST(ComparisonOpsTest, HeterogenousStringPieceEquals) {
|
||||
EXPECT_EQ(StringPiece("hello"), std::string("hello"));
|
||||
EXPECT_EQ("hello", StringPiece("hello"));
|
||||
}
|
||||
|
||||
TEST(FindOneCharTest, EdgeCases) {
|
||||
StringPiece a("xxyyyxx");
|
||||
|
||||
// Set a = "xyyyx".
|
||||
a.remove_prefix(1);
|
||||
a.remove_suffix(1);
|
||||
|
||||
EXPECT_EQ(0, a.find('x'));
|
||||
EXPECT_EQ(0, a.find('x', 0));
|
||||
EXPECT_EQ(4, a.find('x', 1));
|
||||
EXPECT_EQ(4, a.find('x', 4));
|
||||
EXPECT_EQ(StringPiece::npos, a.find('x', 5));
|
||||
|
||||
EXPECT_EQ(4, a.rfind('x'));
|
||||
EXPECT_EQ(4, a.rfind('x', 5));
|
||||
EXPECT_EQ(4, a.rfind('x', 4));
|
||||
EXPECT_EQ(0, a.rfind('x', 3));
|
||||
EXPECT_EQ(0, a.rfind('x', 0));
|
||||
|
||||
// Set a = "yyy".
|
||||
a.remove_prefix(1);
|
||||
a.remove_suffix(1);
|
||||
|
||||
EXPECT_EQ(StringPiece::npos, a.find('x'));
|
||||
EXPECT_EQ(StringPiece::npos, a.rfind('x'));
|
||||
}
|
||||
|
||||
#ifdef PROTOBUF_HAS_DEATH_TEST
|
||||
#ifndef NDEBUG
|
||||
TEST(NonNegativeLenTest, NonNegativeLen) {
|
||||
EXPECT_DEATH(StringPiece("xyz", -1), "len >= 0");
|
||||
}
|
||||
#endif // ndef DEBUG
|
||||
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||
|
||||
} // namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
176
ubuntu/google/protobuf/stubs/stringprintf.cc
Normal file
176
ubuntu/google/protobuf/stubs/stringprintf.cc
Normal file
@@ -0,0 +1,176 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2012 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// from google3/base/stringprintf.cc
|
||||
|
||||
#include <google/protobuf/stubs/stringprintf.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h> // For va_list and related operations
|
||||
#include <stdio.h> // MSVC requires this for _vsnprintf
|
||||
#include <vector>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/logging.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
enum { IS_COMPILER_MSVC = 1 };
|
||||
#ifndef va_copy
|
||||
// Define va_copy for MSVC. This is a hack, assuming va_list is simply a
|
||||
// pointer into the stack and is safe to copy.
|
||||
#define va_copy(dest, src) ((dest) = (src))
|
||||
#endif
|
||||
#else
|
||||
enum { IS_COMPILER_MSVC = 0 };
|
||||
#endif
|
||||
|
||||
void StringAppendV(std::string* dst, const char* format, va_list ap) {
|
||||
// First try with a small fixed size buffer
|
||||
static const int kSpaceLength = 1024;
|
||||
char space[kSpaceLength];
|
||||
|
||||
// It's possible for methods that use a va_list to invalidate
|
||||
// the data in it upon use. The fix is to make a copy
|
||||
// of the structure before using it and use that copy instead.
|
||||
va_list backup_ap;
|
||||
va_copy(backup_ap, ap);
|
||||
int result = vsnprintf(space, kSpaceLength, format, backup_ap);
|
||||
va_end(backup_ap);
|
||||
|
||||
if (result < kSpaceLength) {
|
||||
if (result >= 0) {
|
||||
// Normal case -- everything fit.
|
||||
dst->append(space, result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_COMPILER_MSVC) {
|
||||
// Error or MSVC running out of space. MSVC 8.0 and higher
|
||||
// can be asked about space needed with the special idiom below:
|
||||
va_copy(backup_ap, ap);
|
||||
result = vsnprintf(nullptr, 0, format, backup_ap);
|
||||
va_end(backup_ap);
|
||||
}
|
||||
|
||||
if (result < 0) {
|
||||
// Just an error.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Increase the buffer size to the size requested by vsnprintf,
|
||||
// plus one for the closing \0.
|
||||
int length = result+1;
|
||||
char* buf = new char[length];
|
||||
|
||||
// Restore the va_list before we use it again
|
||||
va_copy(backup_ap, ap);
|
||||
result = vsnprintf(buf, length, format, backup_ap);
|
||||
va_end(backup_ap);
|
||||
|
||||
if (result >= 0 && result < length) {
|
||||
// It fit
|
||||
dst->append(buf, result);
|
||||
}
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
std::string StringPrintf(const char* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
std::string result;
|
||||
StringAppendV(&result, format, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
dst->clear();
|
||||
StringAppendV(dst, format, ap);
|
||||
va_end(ap);
|
||||
return *dst;
|
||||
}
|
||||
|
||||
void StringAppendF(std::string* dst, const char* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
StringAppendV(dst, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
// Max arguments supported by StringPrintVector
|
||||
const int kStringPrintfVectorMaxArgs = 32;
|
||||
|
||||
// An empty block of zero for filler arguments. This is const so that if
|
||||
// printf tries to write to it (via %n) then the program gets a SIGSEGV
|
||||
// and we can fix the problem or protect against an attack.
|
||||
static const char string_printf_empty_block[256] = { '\0' };
|
||||
|
||||
std::string StringPrintfVector(const char* format,
|
||||
const std::vector<std::string>& v) {
|
||||
GOOGLE_CHECK_LE(v.size(), kStringPrintfVectorMaxArgs)
|
||||
<< "StringPrintfVector currently only supports up to "
|
||||
<< kStringPrintfVectorMaxArgs << " arguments. "
|
||||
<< "Feel free to add support for more if you need it.";
|
||||
|
||||
// Add filler arguments so that bogus format+args have a harder time
|
||||
// crashing the program, corrupting the program (%n),
|
||||
// or displaying random chunks of memory to users.
|
||||
|
||||
const char* cstr[kStringPrintfVectorMaxArgs];
|
||||
for (int i = 0; i < v.size(); ++i) {
|
||||
cstr[i] = v[i].c_str();
|
||||
}
|
||||
for (int i = v.size(); i < GOOGLE_ARRAYSIZE(cstr); ++i) {
|
||||
cstr[i] = &string_printf_empty_block[0];
|
||||
}
|
||||
|
||||
// I do not know any way to pass kStringPrintfVectorMaxArgs arguments,
|
||||
// or any way to build a va_list by hand, or any API for printf
|
||||
// that accepts an array of arguments. The best I can do is stick
|
||||
// this COMPILE_ASSERT right next to the actual statement.
|
||||
|
||||
GOOGLE_COMPILE_ASSERT(kStringPrintfVectorMaxArgs == 32, arg_count_mismatch);
|
||||
return StringPrintf(format,
|
||||
cstr[0], cstr[1], cstr[2], cstr[3], cstr[4],
|
||||
cstr[5], cstr[6], cstr[7], cstr[8], cstr[9],
|
||||
cstr[10], cstr[11], cstr[12], cstr[13], cstr[14],
|
||||
cstr[15], cstr[16], cstr[17], cstr[18], cstr[19],
|
||||
cstr[20], cstr[21], cstr[22], cstr[23], cstr[24],
|
||||
cstr[25], cstr[26], cstr[27], cstr[28], cstr[29],
|
||||
cstr[30], cstr[31]);
|
||||
}
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
85
ubuntu/google/protobuf/stubs/stringprintf.h
Normal file
85
ubuntu/google/protobuf/stubs/stringprintf.h
Normal file
@@ -0,0 +1,85 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2012 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// from google3/base/stringprintf.h
|
||||
//
|
||||
// Printf variants that place their output in a C++ string.
|
||||
//
|
||||
// Usage:
|
||||
// string result = StringPrintf("%d %s\n", 10, "hello");
|
||||
// SStringPrintf(&result, "%d %s\n", 10, "hello");
|
||||
// StringAppendF(&result, "%d %s\n", 20, "there");
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
|
||||
#define GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Return a C++ string
|
||||
PROTOBUF_EXPORT extern std::string StringPrintf(const char* format, ...);
|
||||
|
||||
// Store result into a supplied string and return it
|
||||
PROTOBUF_EXPORT extern const std::string& SStringPrintf(std::string* dst,
|
||||
const char* format,
|
||||
...);
|
||||
|
||||
// Append result to a supplied string
|
||||
PROTOBUF_EXPORT extern void StringAppendF(std::string* dst, const char* format,
|
||||
...);
|
||||
|
||||
// Lower-level routine that takes a va_list and appends to a specified
|
||||
// string. All other routines are just convenience wrappers around it.
|
||||
PROTOBUF_EXPORT extern void StringAppendV(std::string* dst, const char* format,
|
||||
va_list ap);
|
||||
|
||||
// The max arguments supported by StringPrintfVector
|
||||
PROTOBUF_EXPORT extern const int kStringPrintfVectorMaxArgs;
|
||||
|
||||
// You can use this version when all your arguments are strings, but
|
||||
// you don't know how many arguments you'll have at compile time.
|
||||
// StringPrintfVector will LOG(FATAL) if v.size() > kStringPrintfVectorMaxArgs
|
||||
PROTOBUF_EXPORT extern std::string StringPrintfVector(
|
||||
const char* format, const std::vector<std::string>& v);
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_STRINGPRINTF_H
|
||||
152
ubuntu/google/protobuf/stubs/stringprintf_unittest.cc
Normal file
152
ubuntu/google/protobuf/stubs/stringprintf_unittest.cc
Normal file
@@ -0,0 +1,152 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2012 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// from google3/base/stringprintf_unittest.cc
|
||||
|
||||
#include <google/protobuf/stubs/stringprintf.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
|
||||
TEST(StringPrintfTest, Empty) {
|
||||
#if 0
|
||||
// gcc 2.95.3, gcc 4.1.0, and gcc 4.2.2 all warn about this:
|
||||
// warning: zero-length printf format string.
|
||||
// so we do not allow them in google3.
|
||||
EXPECT_EQ("", StringPrintf(""));
|
||||
#endif
|
||||
EXPECT_EQ("", StringPrintf("%s", std::string().c_str()));
|
||||
EXPECT_EQ("", StringPrintf("%s", ""));
|
||||
}
|
||||
|
||||
TEST(StringPrintfTest, Misc) {
|
||||
// MSVC and mingw does not support $ format specifier.
|
||||
#if !defined(_MSC_VER) && !defined(__MINGW32__)
|
||||
EXPECT_EQ("123hello w", StringPrintf("%3$d%2$s %1$c", 'w', "hello", 123));
|
||||
#endif // !_MSC_VER
|
||||
}
|
||||
|
||||
TEST(StringAppendFTest, Empty) {
|
||||
std::string value("Hello");
|
||||
const char* empty = "";
|
||||
StringAppendF(&value, "%s", empty);
|
||||
EXPECT_EQ("Hello", value);
|
||||
}
|
||||
|
||||
TEST(StringAppendFTest, EmptyString) {
|
||||
std::string value("Hello");
|
||||
StringAppendF(&value, "%s", "");
|
||||
EXPECT_EQ("Hello", value);
|
||||
}
|
||||
|
||||
TEST(StringAppendFTest, String) {
|
||||
std::string value("Hello");
|
||||
StringAppendF(&value, " %s", "World");
|
||||
EXPECT_EQ("Hello World", value);
|
||||
}
|
||||
|
||||
TEST(StringAppendFTest, Int) {
|
||||
std::string value("Hello");
|
||||
StringAppendF(&value, " %d", 123);
|
||||
EXPECT_EQ("Hello 123", value);
|
||||
}
|
||||
|
||||
TEST(StringPrintfTest, Multibyte) {
|
||||
// If we are in multibyte mode and feed invalid multibyte sequence,
|
||||
// StringPrintf should return an empty string instead of running
|
||||
// out of memory while trying to determine destination buffer size.
|
||||
// see b/4194543.
|
||||
|
||||
char* old_locale = setlocale(LC_CTYPE, nullptr);
|
||||
// Push locale with multibyte mode
|
||||
setlocale(LC_CTYPE, "en_US.utf8");
|
||||
|
||||
const char kInvalidCodePoint[] = "\375\067s";
|
||||
std::string value = StringPrintf("%.*s", 3, kInvalidCodePoint);
|
||||
|
||||
// In some versions of glibc (e.g. eglibc-2.11.1, aka GRTEv2), snprintf
|
||||
// returns error given an invalid codepoint. Other versions
|
||||
// (e.g. eglibc-2.15, aka pre-GRTEv3) emit the codepoint verbatim.
|
||||
// We test that the output is one of the above.
|
||||
EXPECT_TRUE(value.empty() || value == kInvalidCodePoint);
|
||||
|
||||
// Repeat with longer string, to make sure that the dynamically
|
||||
// allocated path in StringAppendV is handled correctly.
|
||||
int n = 2048;
|
||||
char* buf = new char[n+1];
|
||||
memset(buf, ' ', n-3);
|
||||
memcpy(buf + n - 3, kInvalidCodePoint, 4);
|
||||
value = StringPrintf("%.*s", n, buf);
|
||||
// See GRTEv2 vs. GRTEv3 comment above.
|
||||
EXPECT_TRUE(value.empty() || value == buf);
|
||||
delete[] buf;
|
||||
|
||||
setlocale(LC_CTYPE, old_locale);
|
||||
}
|
||||
|
||||
TEST(StringPrintfTest, NoMultibyte) {
|
||||
// No multibyte handling, but the string contains funny chars.
|
||||
char* old_locale = setlocale(LC_CTYPE, nullptr);
|
||||
setlocale(LC_CTYPE, "POSIX");
|
||||
std::string value = StringPrintf("%.*s", 3, "\375\067s");
|
||||
setlocale(LC_CTYPE, old_locale);
|
||||
EXPECT_EQ("\375\067s", value);
|
||||
}
|
||||
|
||||
TEST(StringPrintfTest, DontOverwriteErrno) {
|
||||
// Check that errno isn't overwritten unless we're printing
|
||||
// something significantly larger than what people are normally
|
||||
// printing in their badly written PLOG() statements.
|
||||
errno = ECHILD;
|
||||
std::string value = StringPrintf("Hello, %s!", "World");
|
||||
EXPECT_EQ(ECHILD, errno);
|
||||
}
|
||||
|
||||
TEST(StringPrintfTest, LargeBuf) {
|
||||
// Check that the large buffer is handled correctly.
|
||||
int n = 2048;
|
||||
char* buf = new char[n+1];
|
||||
memset(buf, ' ', n);
|
||||
buf[n] = 0;
|
||||
std::string value = StringPrintf("%s", buf);
|
||||
EXPECT_EQ(buf, value);
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
615
ubuntu/google/protobuf/stubs/structurally_valid.cc
Normal file
615
ubuntu/google/protobuf/stubs/structurally_valid.cc
Normal file
@@ -0,0 +1,615 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: jrm@google.com (Jim Meehan)
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <google/protobuf/stubs/stringpiece.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// These four-byte entries compactly encode how many bytes 0..255 to delete
|
||||
// in making a string replacement, how many bytes to add 0..255, and the offset
|
||||
// 0..64k-1 of the replacement string in remap_string.
|
||||
struct RemapEntry {
|
||||
uint8 delete_bytes;
|
||||
uint8 add_bytes;
|
||||
uint16 bytes_offset;
|
||||
};
|
||||
|
||||
// Exit type codes for state tables. All but the first get stuffed into
|
||||
// signed one-byte entries. The first is only generated by executable code.
|
||||
// To distinguish from next-state entries, these must be contiguous and
|
||||
// all <= kExitNone
|
||||
typedef enum {
|
||||
kExitDstSpaceFull = 239,
|
||||
kExitIllegalStructure, // 240
|
||||
kExitOK, // 241
|
||||
kExitReject, // ...
|
||||
kExitReplace1,
|
||||
kExitReplace2,
|
||||
kExitReplace3,
|
||||
kExitReplace21,
|
||||
kExitReplace31,
|
||||
kExitReplace32,
|
||||
kExitReplaceOffset1,
|
||||
kExitReplaceOffset2,
|
||||
kExitReplace1S0,
|
||||
kExitSpecial,
|
||||
kExitDoAgain,
|
||||
kExitRejectAlt,
|
||||
kExitNone // 255
|
||||
} ExitReason;
|
||||
|
||||
|
||||
// This struct represents one entire state table. The three initialized byte
|
||||
// areas are state_table, remap_base, and remap_string. state0 and state0_size
|
||||
// give the byte offset and length within state_table of the initial state --
|
||||
// table lookups are expected to start and end in this state, but for
|
||||
// truncated UTF-8 strings, may end in a different state. These allow a quick
|
||||
// test for that condition. entry_shift is 8 for tables subscripted by a full
|
||||
// byte value and 6 for space-optimized tables subscripted by only six
|
||||
// significant bits in UTF-8 continuation bytes.
|
||||
typedef struct {
|
||||
const uint32 state0;
|
||||
const uint32 state0_size;
|
||||
const uint32 total_size;
|
||||
const int max_expand;
|
||||
const int entry_shift;
|
||||
const int bytes_per_entry;
|
||||
const uint32 losub;
|
||||
const uint32 hiadd;
|
||||
const uint8* state_table;
|
||||
const RemapEntry* remap_base;
|
||||
const uint8* remap_string;
|
||||
const uint8* fast_state;
|
||||
} UTF8StateMachineObj;
|
||||
|
||||
typedef UTF8StateMachineObj UTF8ScanObj;
|
||||
|
||||
#define X__ (kExitIllegalStructure)
|
||||
#define RJ_ (kExitReject)
|
||||
#define S1_ (kExitReplace1)
|
||||
#define S2_ (kExitReplace2)
|
||||
#define S3_ (kExitReplace3)
|
||||
#define S21 (kExitReplace21)
|
||||
#define S31 (kExitReplace31)
|
||||
#define S32 (kExitReplace32)
|
||||
#define T1_ (kExitReplaceOffset1)
|
||||
#define T2_ (kExitReplaceOffset2)
|
||||
#define S11 (kExitReplace1S0)
|
||||
#define SP_ (kExitSpecial)
|
||||
#define D__ (kExitDoAgain)
|
||||
#define RJA (kExitRejectAlt)
|
||||
|
||||
// Entire table has 9 state blocks of 256 entries each
|
||||
static const unsigned int utf8acceptnonsurrogates_STATE0 = 0; // state[0]
|
||||
static const unsigned int utf8acceptnonsurrogates_STATE0_SIZE = 256; // =[1]
|
||||
static const unsigned int utf8acceptnonsurrogates_TOTAL_SIZE = 2304;
|
||||
static const unsigned int utf8acceptnonsurrogates_MAX_EXPAND_X4 = 0;
|
||||
static const unsigned int utf8acceptnonsurrogates_SHIFT = 8;
|
||||
static const unsigned int utf8acceptnonsurrogates_BYTES = 1;
|
||||
static const unsigned int utf8acceptnonsurrogates_LOSUB = 0x20202020;
|
||||
static const unsigned int utf8acceptnonsurrogates_HIADD = 0x00000000;
|
||||
|
||||
static const uint8 utf8acceptnonsurrogates[] = {
|
||||
// state[0] 0x000000 Byte 1
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 3,
|
||||
4, 5, 5, 5, 6, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[1] 0x000080 Byte 2 of 2
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[2] 0x000000 Byte 2 of 3
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[3] 0x001000 Byte 2 of 3
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[4] 0x000000 Byte 2 of 4
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[5] 0x040000 Byte 2 of 4
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[6] 0x100000 Byte 2 of 4
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[7] 0x00d000 Byte 2 of 3
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[8] 0x00d800 Byte 3 of 3
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
|
||||
RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
|
||||
RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
|
||||
RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
};
|
||||
|
||||
// Remap base[0] = (del, add, string_offset)
|
||||
static const RemapEntry utf8acceptnonsurrogates_remap_base[] = {
|
||||
{0, 0, 0} };
|
||||
|
||||
// Remap string[0]
|
||||
static const unsigned char utf8acceptnonsurrogates_remap_string[] = {
|
||||
0 };
|
||||
|
||||
static const unsigned char utf8acceptnonsurrogates_fast[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
|
||||
static const UTF8ScanObj utf8acceptnonsurrogates_obj = {
|
||||
utf8acceptnonsurrogates_STATE0,
|
||||
utf8acceptnonsurrogates_STATE0_SIZE,
|
||||
utf8acceptnonsurrogates_TOTAL_SIZE,
|
||||
utf8acceptnonsurrogates_MAX_EXPAND_X4,
|
||||
utf8acceptnonsurrogates_SHIFT,
|
||||
utf8acceptnonsurrogates_BYTES,
|
||||
utf8acceptnonsurrogates_LOSUB,
|
||||
utf8acceptnonsurrogates_HIADD,
|
||||
utf8acceptnonsurrogates,
|
||||
utf8acceptnonsurrogates_remap_base,
|
||||
utf8acceptnonsurrogates_remap_string,
|
||||
utf8acceptnonsurrogates_fast
|
||||
};
|
||||
|
||||
|
||||
#undef X__
|
||||
#undef RJ_
|
||||
#undef S1_
|
||||
#undef S2_
|
||||
#undef S3_
|
||||
#undef S21
|
||||
#undef S31
|
||||
#undef S32
|
||||
#undef T1_
|
||||
#undef T2_
|
||||
#undef S11
|
||||
#undef SP_
|
||||
#undef D__
|
||||
#undef RJA
|
||||
|
||||
// Return true if current Tbl pointer is within state0 range
|
||||
// Note that unsigned compare checks both ends of range simultaneously
|
||||
static inline bool InStateZero(const UTF8ScanObj* st, const uint8* Tbl) {
|
||||
const uint8* Tbl0 = &st->state_table[st->state0];
|
||||
return (static_cast<uint32>(Tbl - Tbl0) < st->state0_size);
|
||||
}
|
||||
|
||||
// Scan a UTF-8 string based on state table.
|
||||
// Always scan complete UTF-8 characters
|
||||
// Set number of bytes scanned. Return reason for exiting
|
||||
int UTF8GenericScan(const UTF8ScanObj* st,
|
||||
const char * str,
|
||||
int str_length,
|
||||
int* bytes_consumed) {
|
||||
*bytes_consumed = 0;
|
||||
if (str_length == 0) return kExitOK;
|
||||
|
||||
int eshift = st->entry_shift;
|
||||
const uint8* isrc = reinterpret_cast<const uint8*>(str);
|
||||
const uint8* src = isrc;
|
||||
const uint8* srclimit = isrc + str_length;
|
||||
const uint8* srclimit8 = str_length < 7 ? isrc : srclimit - 7;
|
||||
const uint8* Tbl_0 = &st->state_table[st->state0];
|
||||
|
||||
DoAgain:
|
||||
// Do state-table scan
|
||||
int e = 0;
|
||||
uint8 c;
|
||||
const uint8* Tbl2 = &st->fast_state[0];
|
||||
const uint32 losub = st->losub;
|
||||
const uint32 hiadd = st->hiadd;
|
||||
// Check initial few bytes one at a time until 8-byte aligned
|
||||
//----------------------------
|
||||
while ((((uintptr_t)src & 0x07) != 0) &&
|
||||
(src < srclimit) &&
|
||||
Tbl2[src[0]] == 0) {
|
||||
src++;
|
||||
}
|
||||
if (((uintptr_t)src & 0x07) == 0) {
|
||||
// Do fast for groups of 8 identity bytes.
|
||||
// This covers a lot of 7-bit ASCII ~8x faster then the 1-byte loop,
|
||||
// including slowing slightly on cr/lf/ht
|
||||
//----------------------------
|
||||
while (src < srclimit8) {
|
||||
uint32 s0123 = (reinterpret_cast<const uint32 *>(src))[0];
|
||||
uint32 s4567 = (reinterpret_cast<const uint32 *>(src))[1];
|
||||
src += 8;
|
||||
// This is a fast range check for all bytes in [lowsub..0x80-hiadd)
|
||||
uint32 temp = (s0123 - losub) | (s0123 + hiadd) |
|
||||
(s4567 - losub) | (s4567 + hiadd);
|
||||
if ((temp & 0x80808080) != 0) {
|
||||
// We typically end up here on cr/lf/ht; src was incremented
|
||||
int e0123 = (Tbl2[src[-8]] | Tbl2[src[-7]]) |
|
||||
(Tbl2[src[-6]] | Tbl2[src[-5]]);
|
||||
if (e0123 != 0) {
|
||||
src -= 8;
|
||||
break;
|
||||
} // Exit on Non-interchange
|
||||
e0123 = (Tbl2[src[-4]] | Tbl2[src[-3]]) |
|
||||
(Tbl2[src[-2]] | Tbl2[src[-1]]);
|
||||
if (e0123 != 0) {
|
||||
src -= 4;
|
||||
break;
|
||||
} // Exit on Non-interchange
|
||||
// Else OK, go around again
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------
|
||||
|
||||
// Byte-at-a-time scan
|
||||
//----------------------------
|
||||
const uint8* Tbl = Tbl_0;
|
||||
while (src < srclimit) {
|
||||
c = *src;
|
||||
e = Tbl[c];
|
||||
src++;
|
||||
if (e >= kExitIllegalStructure) {break;}
|
||||
Tbl = &Tbl_0[e << eshift];
|
||||
}
|
||||
//----------------------------
|
||||
|
||||
// Exit possibilities:
|
||||
// Some exit code, !state0, back up over last char
|
||||
// Some exit code, state0, back up one byte exactly
|
||||
// source consumed, !state0, back up over partial char
|
||||
// source consumed, state0, exit OK
|
||||
// For illegal byte in state0, avoid backup up over PREVIOUS char
|
||||
// For truncated last char, back up to beginning of it
|
||||
|
||||
if (e >= kExitIllegalStructure) {
|
||||
// Back up over exactly one byte of rejected/illegal UTF-8 character
|
||||
src--;
|
||||
// Back up more if needed
|
||||
if (!InStateZero(st, Tbl)) {
|
||||
do {
|
||||
src--;
|
||||
} while ((src > isrc) && ((src[0] & 0xc0) == 0x80));
|
||||
}
|
||||
} else if (!InStateZero(st, Tbl)) {
|
||||
// Back up over truncated UTF-8 character
|
||||
e = kExitIllegalStructure;
|
||||
do {
|
||||
src--;
|
||||
} while ((src > isrc) && ((src[0] & 0xc0) == 0x80));
|
||||
} else {
|
||||
// Normal termination, source fully consumed
|
||||
e = kExitOK;
|
||||
}
|
||||
|
||||
if (e == kExitDoAgain) {
|
||||
// Loop back up to the fast scan
|
||||
goto DoAgain;
|
||||
}
|
||||
|
||||
*bytes_consumed = src - isrc;
|
||||
return e;
|
||||
}
|
||||
|
||||
int UTF8GenericScanFastAscii(const UTF8ScanObj* st,
|
||||
const char * str,
|
||||
int str_length,
|
||||
int* bytes_consumed) {
|
||||
*bytes_consumed = 0;
|
||||
if (str_length == 0) return kExitOK;
|
||||
|
||||
const uint8* isrc = reinterpret_cast<const uint8*>(str);
|
||||
const uint8* src = isrc;
|
||||
const uint8* srclimit = isrc + str_length;
|
||||
const uint8* srclimit8 = str_length < 7 ? isrc : srclimit - 7;
|
||||
int n;
|
||||
int rest_consumed;
|
||||
int exit_reason;
|
||||
do {
|
||||
// Check initial few bytes one at a time until 8-byte aligned
|
||||
while ((((uintptr_t)src & 0x07) != 0) &&
|
||||
(src < srclimit) && (src[0] < 0x80)) {
|
||||
src++;
|
||||
}
|
||||
if (((uintptr_t)src & 0x07) == 0) {
|
||||
while ((src < srclimit8) &&
|
||||
(((reinterpret_cast<const uint32*>(src)[0] |
|
||||
reinterpret_cast<const uint32*>(src)[1]) & 0x80808080) == 0)) {
|
||||
src += 8;
|
||||
}
|
||||
}
|
||||
while ((src < srclimit) && (src[0] < 0x80)) {
|
||||
src++;
|
||||
}
|
||||
// Run state table on the rest
|
||||
n = src - isrc;
|
||||
exit_reason = UTF8GenericScan(st, str + n, str_length - n, &rest_consumed);
|
||||
src += rest_consumed;
|
||||
} while ( exit_reason == kExitDoAgain );
|
||||
|
||||
*bytes_consumed = src - isrc;
|
||||
return exit_reason;
|
||||
}
|
||||
|
||||
// Hack: On some compilers the static tables are initialized at startup.
|
||||
// We can't use them until they are initialized. However, some Protocol
|
||||
// Buffer parsing happens at static init time and may try to validate
|
||||
// UTF-8 strings. Since UTF-8 validation is only used for debugging
|
||||
// anyway, we simply always return success if initialization hasn't
|
||||
// occurred yet.
|
||||
namespace {
|
||||
|
||||
bool module_initialized_ = false;
|
||||
|
||||
struct InitDetector {
|
||||
InitDetector() {
|
||||
module_initialized_ = true;
|
||||
}
|
||||
};
|
||||
InitDetector init_detector;
|
||||
|
||||
} // namespace
|
||||
|
||||
bool IsStructurallyValidUTF8(const char* buf, int len) {
|
||||
if (!module_initialized_) return true;
|
||||
|
||||
int bytes_consumed = 0;
|
||||
UTF8GenericScanFastAscii(&utf8acceptnonsurrogates_obj,
|
||||
buf, len, &bytes_consumed);
|
||||
return (bytes_consumed == len);
|
||||
}
|
||||
|
||||
int UTF8SpnStructurallyValid(StringPiece str) {
|
||||
if (!module_initialized_) return str.size();
|
||||
|
||||
int bytes_consumed = 0;
|
||||
UTF8GenericScanFastAscii(&utf8acceptnonsurrogates_obj,
|
||||
str.data(), str.size(), &bytes_consumed);
|
||||
return bytes_consumed;
|
||||
}
|
||||
|
||||
// Coerce UTF-8 byte string in src_str to be
|
||||
// a structurally-valid equal-length string by selectively
|
||||
// overwriting illegal bytes with replace_char (typically blank).
|
||||
// replace_char must be legal printable 7-bit Ascii 0x20..0x7e.
|
||||
// src_str is read-only. If any overwriting is needed, a modified byte string
|
||||
// is created in idst, length isrclen.
|
||||
//
|
||||
// Returns pointer to output buffer, isrc if no changes were made,
|
||||
// or idst if some bytes were changed.
|
||||
//
|
||||
// Fast case: all is structurally valid and no byte copying is done.
|
||||
//
|
||||
char* UTF8CoerceToStructurallyValid(StringPiece src_str, char* idst,
|
||||
const char replace_char) {
|
||||
const char* isrc = src_str.data();
|
||||
const int len = src_str.length();
|
||||
int n = UTF8SpnStructurallyValid(src_str);
|
||||
if (n == len) { // Normal case -- all is cool, return
|
||||
return const_cast<char*>(isrc);
|
||||
} else { // Unusual case -- copy w/o bad bytes
|
||||
const char* src = isrc;
|
||||
const char* srclimit = isrc + len;
|
||||
char* dst = idst;
|
||||
memmove(dst, src, n); // Copy initial good chunk
|
||||
src += n;
|
||||
dst += n;
|
||||
while (src < srclimit) { // src points to bogus byte or is off the end
|
||||
dst[0] = replace_char; // replace one bad byte
|
||||
src++;
|
||||
dst++;
|
||||
StringPiece str2(src, srclimit - src);
|
||||
n = UTF8SpnStructurallyValid(str2); // scan the remainder
|
||||
memmove(dst, src, n); // copy next good chunk
|
||||
src += n;
|
||||
dst += n;
|
||||
}
|
||||
}
|
||||
return idst;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
71
ubuntu/google/protobuf/stubs/structurally_valid_unittest.cc
Normal file
71
ubuntu/google/protobuf/stubs/structurally_valid_unittest.cc
Normal file
@@ -0,0 +1,71 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Copyright 2008 Google Inc. All Rights Reserved.
|
||||
// Author: xpeng@google.com (Peter Peng)
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
TEST(StructurallyValidTest, ValidUTF8String) {
|
||||
// On GCC, this string can be written as:
|
||||
// "abcd 1234 - \u2014\u2013\u2212"
|
||||
// MSVC seems to interpret \u differently.
|
||||
std::string valid_str(
|
||||
"abcd 1234 - \342\200\224\342\200\223\342\210\222 - xyz789");
|
||||
EXPECT_TRUE(IsStructurallyValidUTF8(valid_str.data(),
|
||||
valid_str.size()));
|
||||
// Additional check for pointer alignment
|
||||
for (int i = 1; i < 8; ++i) {
|
||||
EXPECT_TRUE(IsStructurallyValidUTF8(valid_str.data() + i,
|
||||
valid_str.size() - i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StructurallyValidTest, InvalidUTF8String) {
|
||||
const std::string invalid_str("abcd\xA0\xB0\xA0\xB0\xA0\xB0 - xyz789");
|
||||
EXPECT_FALSE(IsStructurallyValidUTF8(invalid_str.data(),
|
||||
invalid_str.size()));
|
||||
// Additional check for pointer alignment
|
||||
for (int i = 1; i < 8; ++i) {
|
||||
EXPECT_FALSE(IsStructurallyValidUTF8(invalid_str.data() + i,
|
||||
invalid_str.size() - i));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
2477
ubuntu/google/protobuf/stubs/strutil.cc
Normal file
2477
ubuntu/google/protobuf/stubs/strutil.cc
Normal file
File diff suppressed because it is too large
Load Diff
953
ubuntu/google/protobuf/stubs/strutil.h
Normal file
953
ubuntu/google/protobuf/stubs/strutil.h
Normal file
@@ -0,0 +1,953 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// from google3/strings/strutil.h
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stringpiece.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <google/protobuf/port_def.inc>
|
||||
#include <vector>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||
#define strtoll _strtoi64
|
||||
#define strtoull _strtoui64
|
||||
#elif defined(__DECCXX) && defined(__osf__)
|
||||
// HP C++ on Tru64 does not have strtoll, but strtol is already 64-bit.
|
||||
#define strtoll strtol
|
||||
#define strtoull strtoul
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// ascii_isalnum()
|
||||
// Check if an ASCII character is alphanumeric. We can't use ctype's
|
||||
// isalnum() because it is affected by locale. This function is applied
|
||||
// to identifiers in the protocol buffer language, not to natural-language
|
||||
// strings, so locale should not be taken into account.
|
||||
// ascii_isdigit()
|
||||
// Like above, but only accepts digits.
|
||||
// ascii_isspace()
|
||||
// Check if the character is a space character.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline bool ascii_isalnum(char c) {
|
||||
return ('a' <= c && c <= 'z') ||
|
||||
('A' <= c && c <= 'Z') ||
|
||||
('0' <= c && c <= '9');
|
||||
}
|
||||
|
||||
inline bool ascii_isdigit(char c) {
|
||||
return ('0' <= c && c <= '9');
|
||||
}
|
||||
|
||||
inline bool ascii_isspace(char c) {
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' ||
|
||||
c == '\r';
|
||||
}
|
||||
|
||||
inline bool ascii_isupper(char c) {
|
||||
return c >= 'A' && c <= 'Z';
|
||||
}
|
||||
|
||||
inline bool ascii_islower(char c) {
|
||||
return c >= 'a' && c <= 'z';
|
||||
}
|
||||
|
||||
inline char ascii_toupper(char c) {
|
||||
return ascii_islower(c) ? c - ('a' - 'A') : c;
|
||||
}
|
||||
|
||||
inline char ascii_tolower(char c) {
|
||||
return ascii_isupper(c) ? c + ('a' - 'A') : c;
|
||||
}
|
||||
|
||||
inline int hex_digit_to_int(char c) {
|
||||
/* Assume ASCII. */
|
||||
int x = static_cast<unsigned char>(c);
|
||||
if (x > '9') {
|
||||
x += 9;
|
||||
}
|
||||
return x & 0xf;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// HasPrefixString()
|
||||
// Check if a string begins with a given prefix.
|
||||
// StripPrefixString()
|
||||
// Given a string and a putative prefix, returns the string minus the
|
||||
// prefix string if the prefix matches, otherwise the original
|
||||
// string.
|
||||
// ----------------------------------------------------------------------
|
||||
inline bool HasPrefixString(StringPiece str, StringPiece prefix) {
|
||||
return str.size() >= prefix.size() &&
|
||||
memcmp(str.data(), prefix.data(), prefix.size()) == 0;
|
||||
}
|
||||
|
||||
inline std::string StripPrefixString(const std::string& str,
|
||||
const std::string& prefix) {
|
||||
if (HasPrefixString(str, prefix)) {
|
||||
return str.substr(prefix.size());
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// HasSuffixString()
|
||||
// Return true if str ends in suffix.
|
||||
// StripSuffixString()
|
||||
// Given a string and a putative suffix, returns the string minus the
|
||||
// suffix string if the suffix matches, otherwise the original
|
||||
// string.
|
||||
// ----------------------------------------------------------------------
|
||||
inline bool HasSuffixString(StringPiece str, StringPiece suffix) {
|
||||
return str.size() >= suffix.size() &&
|
||||
memcmp(str.data() + str.size() - suffix.size(), suffix.data(),
|
||||
suffix.size()) == 0;
|
||||
}
|
||||
|
||||
inline std::string StripSuffixString(const std::string& str,
|
||||
const std::string& suffix) {
|
||||
if (HasSuffixString(str, suffix)) {
|
||||
return str.substr(0, str.size() - suffix.size());
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// ReplaceCharacters
|
||||
// Replaces any occurrence of the character 'remove' (or the characters
|
||||
// in 'remove') with the character 'replacewith'.
|
||||
// Good for keeping html characters or protocol characters (\t) out
|
||||
// of places where they might cause a problem.
|
||||
// StripWhitespace
|
||||
// Removes whitespaces from both ends of the given string.
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT void ReplaceCharacters(std::string* s, const char* remove,
|
||||
char replacewith);
|
||||
|
||||
PROTOBUF_EXPORT void StripWhitespace(std::string* s);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// LowerString()
|
||||
// UpperString()
|
||||
// ToUpper()
|
||||
// Convert the characters in "s" to lowercase or uppercase. ASCII-only:
|
||||
// these functions intentionally ignore locale because they are applied to
|
||||
// identifiers used in the Protocol Buffer language, not to natural-language
|
||||
// strings.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline void LowerString(std::string* s) {
|
||||
std::string::iterator end = s->end();
|
||||
for (std::string::iterator i = s->begin(); i != end; ++i) {
|
||||
// tolower() changes based on locale. We don't want this!
|
||||
if ('A' <= *i && *i <= 'Z') *i += 'a' - 'A';
|
||||
}
|
||||
}
|
||||
|
||||
inline void UpperString(std::string* s) {
|
||||
std::string::iterator end = s->end();
|
||||
for (std::string::iterator i = s->begin(); i != end; ++i) {
|
||||
// toupper() changes based on locale. We don't want this!
|
||||
if ('a' <= *i && *i <= 'z') *i += 'A' - 'a';
|
||||
}
|
||||
}
|
||||
|
||||
inline void ToUpper(std::string* s) { UpperString(s); }
|
||||
|
||||
inline std::string ToUpper(const std::string& s) {
|
||||
std::string out = s;
|
||||
UpperString(&out);
|
||||
return out;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// StringReplace()
|
||||
// Give me a string and two patterns "old" and "new", and I replace
|
||||
// the first instance of "old" in the string with "new", if it
|
||||
// exists. RETURN a new string, regardless of whether the replacement
|
||||
// happened or not.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
PROTOBUF_EXPORT std::string StringReplace(const std::string& s,
|
||||
const std::string& oldsub,
|
||||
const std::string& newsub,
|
||||
bool replace_all);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// SplitStringUsing()
|
||||
// Split a string using a character delimiter. Append the components
|
||||
// to 'result'. If there are consecutive delimiters, this function skips
|
||||
// over all of them.
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT void SplitStringUsing(StringPiece full, const char* delim,
|
||||
std::vector<std::string>* res);
|
||||
|
||||
// Split a string using one or more byte delimiters, presented
|
||||
// as a nul-terminated c string. Append the components to 'result'.
|
||||
// If there are consecutive delimiters, this function will return
|
||||
// corresponding empty strings. If you want to drop the empty
|
||||
// strings, try SplitStringUsing().
|
||||
//
|
||||
// If "full" is the empty string, yields an empty string as the only value.
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT void SplitStringAllowEmpty(StringPiece full, const char* delim,
|
||||
std::vector<std::string>* result);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Split()
|
||||
// Split a string using a character delimiter.
|
||||
// ----------------------------------------------------------------------
|
||||
inline std::vector<std::string> Split(StringPiece full, const char* delim,
|
||||
bool skip_empty = true) {
|
||||
std::vector<std::string> result;
|
||||
if (skip_empty) {
|
||||
SplitStringUsing(full, delim, &result);
|
||||
} else {
|
||||
SplitStringAllowEmpty(full, delim, &result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// JoinStrings()
|
||||
// These methods concatenate a vector of strings into a C++ string, using
|
||||
// the C-string "delim" as a separator between components. There are two
|
||||
// flavors of the function, one flavor returns the concatenated string,
|
||||
// another takes a pointer to the target string. In the latter case the
|
||||
// target string is cleared and overwritten.
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT void JoinStrings(const std::vector<std::string>& components,
|
||||
const char* delim, std::string* result);
|
||||
|
||||
inline std::string JoinStrings(const std::vector<std::string>& components,
|
||||
const char* delim) {
|
||||
std::string result;
|
||||
JoinStrings(components, delim, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// UnescapeCEscapeSequences()
|
||||
// Copies "source" to "dest", rewriting C-style escape sequences
|
||||
// -- '\n', '\r', '\\', '\ooo', etc -- to their ASCII
|
||||
// equivalents. "dest" must be sufficiently large to hold all
|
||||
// the characters in the rewritten string (i.e. at least as large
|
||||
// as strlen(source) + 1 should be safe, since the replacements
|
||||
// are always shorter than the original escaped sequences). It's
|
||||
// safe for source and dest to be the same. RETURNS the length
|
||||
// of dest.
|
||||
//
|
||||
// It allows hex sequences \xhh, or generally \xhhhhh with an
|
||||
// arbitrary number of hex digits, but all of them together must
|
||||
// specify a value of a single byte (e.g. \x0045 is equivalent
|
||||
// to \x45, and \x1234 is erroneous).
|
||||
//
|
||||
// It also allows escape sequences of the form \uhhhh (exactly four
|
||||
// hex digits, upper or lower case) or \Uhhhhhhhh (exactly eight
|
||||
// hex digits, upper or lower case) to specify a Unicode code
|
||||
// point. The dest array will contain the UTF8-encoded version of
|
||||
// that code-point (e.g., if source contains \u2019, then dest will
|
||||
// contain the three bytes 0xE2, 0x80, and 0x99).
|
||||
//
|
||||
// Errors: In the first form of the call, errors are reported with
|
||||
// LOG(ERROR). The same is true for the second form of the call if
|
||||
// the pointer to the string std::vector is nullptr; otherwise, error
|
||||
// messages are stored in the std::vector. In either case, the effect on
|
||||
// the dest array is not defined, but rest of the source will be
|
||||
// processed.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
PROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest);
|
||||
PROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest,
|
||||
std::vector<std::string>* errors);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// UnescapeCEscapeString()
|
||||
// This does the same thing as UnescapeCEscapeSequences, but creates
|
||||
// a new string. The caller does not need to worry about allocating
|
||||
// a dest buffer. This should be used for non performance critical
|
||||
// tasks such as printing debug messages. It is safe for src and dest
|
||||
// to be the same.
|
||||
//
|
||||
// The second call stores its errors in a supplied string vector.
|
||||
// If the string vector pointer is nullptr, it reports the errors with LOG().
|
||||
//
|
||||
// In the first and second calls, the length of dest is returned. In the
|
||||
// the third call, the new string is returned.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
PROTOBUF_EXPORT int UnescapeCEscapeString(const std::string& src,
|
||||
std::string* dest);
|
||||
PROTOBUF_EXPORT int UnescapeCEscapeString(const std::string& src,
|
||||
std::string* dest,
|
||||
std::vector<std::string>* errors);
|
||||
PROTOBUF_EXPORT std::string UnescapeCEscapeString(const std::string& src);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// CEscape()
|
||||
// Escapes 'src' using C-style escape sequences and returns the resulting
|
||||
// string.
|
||||
//
|
||||
// Escaped chars: \n, \r, \t, ", ', \, and !isprint().
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT std::string CEscape(const std::string& src);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// CEscapeAndAppend()
|
||||
// Escapes 'src' using C-style escape sequences, and appends the escaped
|
||||
// string to 'dest'.
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT void CEscapeAndAppend(StringPiece src, std::string* dest);
|
||||
|
||||
namespace strings {
|
||||
// Like CEscape() but does not escape bytes with the upper bit set.
|
||||
PROTOBUF_EXPORT std::string Utf8SafeCEscape(const std::string& src);
|
||||
|
||||
// Like CEscape() but uses hex (\x) escapes instead of octals.
|
||||
PROTOBUF_EXPORT std::string CHexEscape(const std::string& src);
|
||||
} // namespace strings
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// strto32()
|
||||
// strtou32()
|
||||
// strto64()
|
||||
// strtou64()
|
||||
// Architecture-neutral plug compatible replacements for strtol() and
|
||||
// strtoul(). Long's have different lengths on ILP-32 and LP-64
|
||||
// platforms, so using these is safer, from the point of view of
|
||||
// overflow behavior, than using the standard libc functions.
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT int32 strto32_adaptor(const char* nptr, char** endptr,
|
||||
int base);
|
||||
PROTOBUF_EXPORT uint32 strtou32_adaptor(const char* nptr, char** endptr,
|
||||
int base);
|
||||
|
||||
inline int32 strto32(const char *nptr, char **endptr, int base) {
|
||||
if (sizeof(int32) == sizeof(long))
|
||||
return strtol(nptr, endptr, base);
|
||||
else
|
||||
return strto32_adaptor(nptr, endptr, base);
|
||||
}
|
||||
|
||||
inline uint32 strtou32(const char *nptr, char **endptr, int base) {
|
||||
if (sizeof(uint32) == sizeof(unsigned long))
|
||||
return strtoul(nptr, endptr, base);
|
||||
else
|
||||
return strtou32_adaptor(nptr, endptr, base);
|
||||
}
|
||||
|
||||
// For now, long long is 64-bit on all the platforms we care about, so these
|
||||
// functions can simply pass the call to strto[u]ll.
|
||||
inline int64 strto64(const char *nptr, char **endptr, int base) {
|
||||
GOOGLE_COMPILE_ASSERT(sizeof(int64) == sizeof(long long),
|
||||
sizeof_int64_is_not_sizeof_long_long);
|
||||
return strtoll(nptr, endptr, base);
|
||||
}
|
||||
|
||||
inline uint64 strtou64(const char *nptr, char **endptr, int base) {
|
||||
GOOGLE_COMPILE_ASSERT(sizeof(uint64) == sizeof(unsigned long long),
|
||||
sizeof_uint64_is_not_sizeof_long_long);
|
||||
return strtoull(nptr, endptr, base);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// safe_strtob()
|
||||
// safe_strto32()
|
||||
// safe_strtou32()
|
||||
// safe_strto64()
|
||||
// safe_strtou64()
|
||||
// safe_strtof()
|
||||
// safe_strtod()
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT bool safe_strtob(StringPiece str, bool* value);
|
||||
|
||||
PROTOBUF_EXPORT bool safe_strto32(const std::string& str, int32* value);
|
||||
PROTOBUF_EXPORT bool safe_strtou32(const std::string& str, uint32* value);
|
||||
inline bool safe_strto32(const char* str, int32* value) {
|
||||
return safe_strto32(std::string(str), value);
|
||||
}
|
||||
inline bool safe_strto32(StringPiece str, int32* value) {
|
||||
return safe_strto32(str.ToString(), value);
|
||||
}
|
||||
inline bool safe_strtou32(const char* str, uint32* value) {
|
||||
return safe_strtou32(std::string(str), value);
|
||||
}
|
||||
inline bool safe_strtou32(StringPiece str, uint32* value) {
|
||||
return safe_strtou32(str.ToString(), value);
|
||||
}
|
||||
|
||||
PROTOBUF_EXPORT bool safe_strto64(const std::string& str, int64* value);
|
||||
PROTOBUF_EXPORT bool safe_strtou64(const std::string& str, uint64* value);
|
||||
inline bool safe_strto64(const char* str, int64* value) {
|
||||
return safe_strto64(std::string(str), value);
|
||||
}
|
||||
inline bool safe_strto64(StringPiece str, int64* value) {
|
||||
return safe_strto64(str.ToString(), value);
|
||||
}
|
||||
inline bool safe_strtou64(const char* str, uint64* value) {
|
||||
return safe_strtou64(std::string(str), value);
|
||||
}
|
||||
inline bool safe_strtou64(StringPiece str, uint64* value) {
|
||||
return safe_strtou64(str.ToString(), value);
|
||||
}
|
||||
|
||||
PROTOBUF_EXPORT bool safe_strtof(const char* str, float* value);
|
||||
PROTOBUF_EXPORT bool safe_strtod(const char* str, double* value);
|
||||
inline bool safe_strtof(const std::string& str, float* value) {
|
||||
return safe_strtof(str.c_str(), value);
|
||||
}
|
||||
inline bool safe_strtod(const std::string& str, double* value) {
|
||||
return safe_strtod(str.c_str(), value);
|
||||
}
|
||||
inline bool safe_strtof(StringPiece str, float* value) {
|
||||
return safe_strtof(str.ToString(), value);
|
||||
}
|
||||
inline bool safe_strtod(StringPiece str, double* value) {
|
||||
return safe_strtod(str.ToString(), value);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// FastIntToBuffer()
|
||||
// FastHexToBuffer()
|
||||
// FastHex64ToBuffer()
|
||||
// FastHex32ToBuffer()
|
||||
// FastTimeToBuffer()
|
||||
// These are intended for speed. FastIntToBuffer() assumes the
|
||||
// integer is non-negative. FastHexToBuffer() puts output in
|
||||
// hex rather than decimal. FastTimeToBuffer() puts the output
|
||||
// into RFC822 format.
|
||||
//
|
||||
// FastHex64ToBuffer() puts a 64-bit unsigned value in hex-format,
|
||||
// padded to exactly 16 bytes (plus one byte for '\0')
|
||||
//
|
||||
// FastHex32ToBuffer() puts a 32-bit unsigned value in hex-format,
|
||||
// padded to exactly 8 bytes (plus one byte for '\0')
|
||||
//
|
||||
// All functions take the output buffer as an arg.
|
||||
// They all return a pointer to the beginning of the output,
|
||||
// which may not be the beginning of the input buffer.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// Suggested buffer size for FastToBuffer functions. Also works with
|
||||
// DoubleToBuffer() and FloatToBuffer().
|
||||
static const int kFastToBufferSize = 32;
|
||||
|
||||
PROTOBUF_EXPORT char* FastInt32ToBuffer(int32 i, char* buffer);
|
||||
PROTOBUF_EXPORT char* FastInt64ToBuffer(int64 i, char* buffer);
|
||||
char* FastUInt32ToBuffer(uint32 i, char* buffer); // inline below
|
||||
char* FastUInt64ToBuffer(uint64 i, char* buffer); // inline below
|
||||
PROTOBUF_EXPORT char* FastHexToBuffer(int i, char* buffer);
|
||||
PROTOBUF_EXPORT char* FastHex64ToBuffer(uint64 i, char* buffer);
|
||||
PROTOBUF_EXPORT char* FastHex32ToBuffer(uint32 i, char* buffer);
|
||||
|
||||
// at least 22 bytes long
|
||||
inline char* FastIntToBuffer(int i, char* buffer) {
|
||||
return (sizeof(i) == 4 ?
|
||||
FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer));
|
||||
}
|
||||
inline char* FastUIntToBuffer(unsigned int i, char* buffer) {
|
||||
return (sizeof(i) == 4 ?
|
||||
FastUInt32ToBuffer(i, buffer) : FastUInt64ToBuffer(i, buffer));
|
||||
}
|
||||
inline char* FastLongToBuffer(long i, char* buffer) {
|
||||
return (sizeof(i) == 4 ?
|
||||
FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer));
|
||||
}
|
||||
inline char* FastULongToBuffer(unsigned long i, char* buffer) {
|
||||
return (sizeof(i) == 4 ?
|
||||
FastUInt32ToBuffer(i, buffer) : FastUInt64ToBuffer(i, buffer));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// FastInt32ToBufferLeft()
|
||||
// FastUInt32ToBufferLeft()
|
||||
// FastInt64ToBufferLeft()
|
||||
// FastUInt64ToBufferLeft()
|
||||
//
|
||||
// Like the Fast*ToBuffer() functions above, these are intended for speed.
|
||||
// Unlike the Fast*ToBuffer() functions, however, these functions write
|
||||
// their output to the beginning of the buffer (hence the name, as the
|
||||
// output is left-aligned). The caller is responsible for ensuring that
|
||||
// the buffer has enough space to hold the output.
|
||||
//
|
||||
// Returns a pointer to the end of the string (i.e. the null character
|
||||
// terminating the string).
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
PROTOBUF_EXPORT char* FastInt32ToBufferLeft(int32 i, char* buffer);
|
||||
PROTOBUF_EXPORT char* FastUInt32ToBufferLeft(uint32 i, char* buffer);
|
||||
PROTOBUF_EXPORT char* FastInt64ToBufferLeft(int64 i, char* buffer);
|
||||
PROTOBUF_EXPORT char* FastUInt64ToBufferLeft(uint64 i, char* buffer);
|
||||
|
||||
// Just define these in terms of the above.
|
||||
inline char* FastUInt32ToBuffer(uint32 i, char* buffer) {
|
||||
FastUInt32ToBufferLeft(i, buffer);
|
||||
return buffer;
|
||||
}
|
||||
inline char* FastUInt64ToBuffer(uint64 i, char* buffer) {
|
||||
FastUInt64ToBufferLeft(i, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline std::string SimpleBtoa(bool value) { return value ? "true" : "false"; }
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// SimpleItoa()
|
||||
// Description: converts an integer to a string.
|
||||
//
|
||||
// Return value: string
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT std::string SimpleItoa(int i);
|
||||
PROTOBUF_EXPORT std::string SimpleItoa(unsigned int i);
|
||||
PROTOBUF_EXPORT std::string SimpleItoa(long i);
|
||||
PROTOBUF_EXPORT std::string SimpleItoa(unsigned long i);
|
||||
PROTOBUF_EXPORT std::string SimpleItoa(long long i);
|
||||
PROTOBUF_EXPORT std::string SimpleItoa(unsigned long long i);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// SimpleDtoa()
|
||||
// SimpleFtoa()
|
||||
// DoubleToBuffer()
|
||||
// FloatToBuffer()
|
||||
// Description: converts a double or float to a string which, if
|
||||
// passed to NoLocaleStrtod(), will produce the exact same original double
|
||||
// (except in case of NaN; all NaNs are considered the same value).
|
||||
// We try to keep the string short but it's not guaranteed to be as
|
||||
// short as possible.
|
||||
//
|
||||
// DoubleToBuffer() and FloatToBuffer() write the text to the given
|
||||
// buffer and return it. The buffer must be at least
|
||||
// kDoubleToBufferSize bytes for doubles and kFloatToBufferSize
|
||||
// bytes for floats. kFastToBufferSize is also guaranteed to be large
|
||||
// enough to hold either.
|
||||
//
|
||||
// Return value: string
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT std::string SimpleDtoa(double value);
|
||||
PROTOBUF_EXPORT std::string SimpleFtoa(float value);
|
||||
|
||||
PROTOBUF_EXPORT char* DoubleToBuffer(double i, char* buffer);
|
||||
PROTOBUF_EXPORT char* FloatToBuffer(float i, char* buffer);
|
||||
|
||||
// In practice, doubles should never need more than 24 bytes and floats
|
||||
// should never need more than 14 (including null terminators), but we
|
||||
// overestimate to be safe.
|
||||
static const int kDoubleToBufferSize = 32;
|
||||
static const int kFloatToBufferSize = 24;
|
||||
|
||||
namespace strings {
|
||||
|
||||
enum PadSpec {
|
||||
NO_PAD = 1,
|
||||
ZERO_PAD_2,
|
||||
ZERO_PAD_3,
|
||||
ZERO_PAD_4,
|
||||
ZERO_PAD_5,
|
||||
ZERO_PAD_6,
|
||||
ZERO_PAD_7,
|
||||
ZERO_PAD_8,
|
||||
ZERO_PAD_9,
|
||||
ZERO_PAD_10,
|
||||
ZERO_PAD_11,
|
||||
ZERO_PAD_12,
|
||||
ZERO_PAD_13,
|
||||
ZERO_PAD_14,
|
||||
ZERO_PAD_15,
|
||||
ZERO_PAD_16,
|
||||
};
|
||||
|
||||
struct Hex {
|
||||
uint64 value;
|
||||
enum PadSpec spec;
|
||||
template <class Int>
|
||||
explicit Hex(Int v, PadSpec s = NO_PAD)
|
||||
: spec(s) {
|
||||
// Prevent sign-extension by casting integers to
|
||||
// their unsigned counterparts.
|
||||
#ifdef LANG_CXX11
|
||||
static_assert(
|
||||
sizeof(v) == 1 || sizeof(v) == 2 || sizeof(v) == 4 || sizeof(v) == 8,
|
||||
"Unknown integer type");
|
||||
#endif
|
||||
value = sizeof(v) == 1 ? static_cast<uint8>(v)
|
||||
: sizeof(v) == 2 ? static_cast<uint16>(v)
|
||||
: sizeof(v) == 4 ? static_cast<uint32>(v)
|
||||
: static_cast<uint64>(v);
|
||||
}
|
||||
};
|
||||
|
||||
struct PROTOBUF_EXPORT AlphaNum {
|
||||
const char *piece_data_; // move these to string_ref eventually
|
||||
size_t piece_size_; // move these to string_ref eventually
|
||||
|
||||
char digits[kFastToBufferSize];
|
||||
|
||||
// No bool ctor -- bools convert to an integral type.
|
||||
// A bool ctor would also convert incoming pointers (bletch).
|
||||
|
||||
AlphaNum(int i32)
|
||||
: piece_data_(digits),
|
||||
piece_size_(FastInt32ToBufferLeft(i32, digits) - &digits[0]) {}
|
||||
AlphaNum(unsigned int u32)
|
||||
: piece_data_(digits),
|
||||
piece_size_(FastUInt32ToBufferLeft(u32, digits) - &digits[0]) {}
|
||||
AlphaNum(long long i64)
|
||||
: piece_data_(digits),
|
||||
piece_size_(FastInt64ToBufferLeft(i64, digits) - &digits[0]) {}
|
||||
AlphaNum(unsigned long long u64)
|
||||
: piece_data_(digits),
|
||||
piece_size_(FastUInt64ToBufferLeft(u64, digits) - &digits[0]) {}
|
||||
|
||||
// Note: on some architectures, "long" is only 32 bits, not 64, but the
|
||||
// performance hit of using FastInt64ToBufferLeft to handle 32-bit values
|
||||
// is quite minor.
|
||||
AlphaNum(long i64)
|
||||
: piece_data_(digits),
|
||||
piece_size_(FastInt64ToBufferLeft(i64, digits) - &digits[0]) {}
|
||||
AlphaNum(unsigned long u64)
|
||||
: piece_data_(digits),
|
||||
piece_size_(FastUInt64ToBufferLeft(u64, digits) - &digits[0]) {}
|
||||
|
||||
AlphaNum(float f)
|
||||
: piece_data_(digits), piece_size_(strlen(FloatToBuffer(f, digits))) {}
|
||||
AlphaNum(double f)
|
||||
: piece_data_(digits), piece_size_(strlen(DoubleToBuffer(f, digits))) {}
|
||||
|
||||
AlphaNum(Hex hex);
|
||||
|
||||
AlphaNum(const char* c_str)
|
||||
: piece_data_(c_str), piece_size_(strlen(c_str)) {}
|
||||
// TODO: Add a string_ref constructor, eventually
|
||||
// AlphaNum(const StringPiece &pc) : piece(pc) {}
|
||||
|
||||
AlphaNum(const std::string& str)
|
||||
: piece_data_(str.data()), piece_size_(str.size()) {}
|
||||
|
||||
AlphaNum(StringPiece str)
|
||||
: piece_data_(str.data()), piece_size_(str.size()) {}
|
||||
|
||||
AlphaNum(internal::StringPiecePod str)
|
||||
: piece_data_(str.data()), piece_size_(str.size()) {}
|
||||
|
||||
size_t size() const { return piece_size_; }
|
||||
const char *data() const { return piece_data_; }
|
||||
|
||||
private:
|
||||
// Use ":" not ':'
|
||||
AlphaNum(char c); // NOLINT(runtime/explicit)
|
||||
|
||||
// Disallow copy and assign.
|
||||
AlphaNum(const AlphaNum&);
|
||||
void operator=(const AlphaNum&);
|
||||
};
|
||||
|
||||
} // namespace strings
|
||||
|
||||
using strings::AlphaNum;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// StrCat()
|
||||
// This merges the given strings or numbers, with no delimiter. This
|
||||
// is designed to be the fastest possible way to construct a string out
|
||||
// of a mix of raw C strings, strings, bool values,
|
||||
// and numeric values.
|
||||
//
|
||||
// Don't use this for user-visible strings. The localization process
|
||||
// works poorly on strings built up out of fragments.
|
||||
//
|
||||
// For clarity and performance, don't use StrCat when appending to a
|
||||
// string. In particular, avoid using any of these (anti-)patterns:
|
||||
// str.append(StrCat(...)
|
||||
// str += StrCat(...)
|
||||
// str = StrCat(str, ...)
|
||||
// where the last is the worse, with the potential to change a loop
|
||||
// from a linear time operation with O(1) dynamic allocations into a
|
||||
// quadratic time operation with O(n) dynamic allocations. StrAppend
|
||||
// is a better choice than any of the above, subject to the restriction
|
||||
// of StrAppend(&str, a, b, c, ...) that none of the a, b, c, ... may
|
||||
// be a reference into str.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b);
|
||||
PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
|
||||
const AlphaNum& c);
|
||||
PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
|
||||
const AlphaNum& c, const AlphaNum& d);
|
||||
PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
|
||||
const AlphaNum& c, const AlphaNum& d,
|
||||
const AlphaNum& e);
|
||||
PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
|
||||
const AlphaNum& c, const AlphaNum& d,
|
||||
const AlphaNum& e, const AlphaNum& f);
|
||||
PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
|
||||
const AlphaNum& c, const AlphaNum& d,
|
||||
const AlphaNum& e, const AlphaNum& f,
|
||||
const AlphaNum& g);
|
||||
PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
|
||||
const AlphaNum& c, const AlphaNum& d,
|
||||
const AlphaNum& e, const AlphaNum& f,
|
||||
const AlphaNum& g, const AlphaNum& h);
|
||||
PROTOBUF_EXPORT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
|
||||
const AlphaNum& c, const AlphaNum& d,
|
||||
const AlphaNum& e, const AlphaNum& f,
|
||||
const AlphaNum& g, const AlphaNum& h,
|
||||
const AlphaNum& i);
|
||||
|
||||
inline std::string StrCat(const AlphaNum& a) {
|
||||
return std::string(a.data(), a.size());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// StrAppend()
|
||||
// Same as above, but adds the output to the given string.
|
||||
// WARNING: For speed, StrAppend does not try to check each of its input
|
||||
// arguments to be sure that they are not a subset of the string being
|
||||
// appended to. That is, while this will work:
|
||||
//
|
||||
// string s = "foo";
|
||||
// s += s;
|
||||
//
|
||||
// This will not (necessarily) work:
|
||||
//
|
||||
// string s = "foo";
|
||||
// StrAppend(&s, s);
|
||||
//
|
||||
// Note: while StrCat supports appending up to 9 arguments, StrAppend
|
||||
// is currently limited to 4. That's rarely an issue except when
|
||||
// automatically transforming StrCat to StrAppend, and can easily be
|
||||
// worked around as consecutive calls to StrAppend are quite efficient.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
PROTOBUF_EXPORT void StrAppend(std::string* dest, const AlphaNum& a);
|
||||
PROTOBUF_EXPORT void StrAppend(std::string* dest, const AlphaNum& a,
|
||||
const AlphaNum& b);
|
||||
PROTOBUF_EXPORT void StrAppend(std::string* dest, const AlphaNum& a,
|
||||
const AlphaNum& b, const AlphaNum& c);
|
||||
PROTOBUF_EXPORT void StrAppend(std::string* dest, const AlphaNum& a,
|
||||
const AlphaNum& b, const AlphaNum& c,
|
||||
const AlphaNum& d);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Join()
|
||||
// These methods concatenate a range of components into a C++ string, using
|
||||
// the C-string "delim" as a separator between components.
|
||||
// ----------------------------------------------------------------------
|
||||
template <typename Iterator>
|
||||
void Join(Iterator start, Iterator end, const char* delim,
|
||||
std::string* result) {
|
||||
for (Iterator it = start; it != end; ++it) {
|
||||
if (it != start) {
|
||||
result->append(delim);
|
||||
}
|
||||
StrAppend(result, *it);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Range>
|
||||
std::string Join(const Range& components, const char* delim) {
|
||||
std::string result;
|
||||
Join(components.begin(), components.end(), delim, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// ToHex()
|
||||
// Return a lower-case hex string representation of the given integer.
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT std::string ToHex(uint64 num);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// GlobalReplaceSubstring()
|
||||
// Replaces all instances of a substring in a string. Does nothing
|
||||
// if 'substring' is empty. Returns the number of replacements.
|
||||
//
|
||||
// NOTE: The string pieces must not overlap s.
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT int GlobalReplaceSubstring(const std::string& substring,
|
||||
const std::string& replacement,
|
||||
std::string* s);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Base64Unescape()
|
||||
// Converts "src" which is encoded in Base64 to its binary equivalent and
|
||||
// writes it to "dest". If src contains invalid characters, dest is cleared
|
||||
// and the function returns false. Returns true on success.
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT bool Base64Unescape(StringPiece src, std::string* dest);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// WebSafeBase64Unescape()
|
||||
// This is a variation of Base64Unescape which uses '-' instead of '+', and
|
||||
// '_' instead of '/'. src is not null terminated, instead specify len. I
|
||||
// recommend that slen<szdest, but we honor szdest anyway.
|
||||
// RETURNS the length of dest, or -1 if src contains invalid chars.
|
||||
|
||||
// The variation that stores into a string clears the string first, and
|
||||
// returns false (with dest empty) if src contains invalid chars; for
|
||||
// this version src and dest must be different strings.
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT int WebSafeBase64Unescape(const char* src, int slen, char* dest,
|
||||
int szdest);
|
||||
PROTOBUF_EXPORT bool WebSafeBase64Unescape(StringPiece src, std::string* dest);
|
||||
|
||||
// Return the length to use for the output buffer given to the base64 escape
|
||||
// routines. Make sure to use the same value for do_padding in both.
|
||||
// This function may return incorrect results if given input_len values that
|
||||
// are extremely high, which should happen rarely.
|
||||
PROTOBUF_EXPORT int CalculateBase64EscapedLen(int input_len, bool do_padding);
|
||||
// Use this version when calling Base64Escape without a do_padding arg.
|
||||
PROTOBUF_EXPORT int CalculateBase64EscapedLen(int input_len);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Base64Escape()
|
||||
// WebSafeBase64Escape()
|
||||
// Encode "src" to "dest" using base64 encoding.
|
||||
// src is not null terminated, instead specify len.
|
||||
// 'dest' should have at least CalculateBase64EscapedLen() length.
|
||||
// RETURNS the length of dest.
|
||||
// The WebSafe variation use '-' instead of '+' and '_' instead of '/'
|
||||
// so that we can place the out in the URL or cookies without having
|
||||
// to escape them. It also has an extra parameter "do_padding",
|
||||
// which when set to false will prevent padding with "=".
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT int Base64Escape(const unsigned char* src, int slen, char* dest,
|
||||
int szdest);
|
||||
PROTOBUF_EXPORT int WebSafeBase64Escape(const unsigned char* src, int slen,
|
||||
char* dest, int szdest,
|
||||
bool do_padding);
|
||||
// Encode src into dest with padding.
|
||||
PROTOBUF_EXPORT void Base64Escape(StringPiece src, std::string* dest);
|
||||
// Encode src into dest web-safely without padding.
|
||||
PROTOBUF_EXPORT void WebSafeBase64Escape(StringPiece src, std::string* dest);
|
||||
// Encode src into dest web-safely with padding.
|
||||
PROTOBUF_EXPORT void WebSafeBase64EscapeWithPadding(StringPiece src,
|
||||
std::string* dest);
|
||||
|
||||
PROTOBUF_EXPORT void Base64Escape(const unsigned char* src, int szsrc,
|
||||
std::string* dest, bool do_padding);
|
||||
PROTOBUF_EXPORT void WebSafeBase64Escape(const unsigned char* src, int szsrc,
|
||||
std::string* dest, bool do_padding);
|
||||
|
||||
inline bool IsValidCodePoint(uint32 code_point) {
|
||||
return code_point < 0xD800 ||
|
||||
(code_point >= 0xE000 && code_point <= 0x10FFFF);
|
||||
}
|
||||
|
||||
static const int UTFmax = 4;
|
||||
// ----------------------------------------------------------------------
|
||||
// EncodeAsUTF8Char()
|
||||
// Helper to append a Unicode code point to a string as UTF8, without bringing
|
||||
// in any external dependencies. The output buffer must be as least 4 bytes
|
||||
// large.
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT int EncodeAsUTF8Char(uint32 code_point, char* output);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// UTF8FirstLetterNumBytes()
|
||||
// Length of the first UTF-8 character.
|
||||
// ----------------------------------------------------------------------
|
||||
PROTOBUF_EXPORT int UTF8FirstLetterNumBytes(const char* src, int len);
|
||||
|
||||
// From google3/third_party/absl/strings/escaping.h
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// CleanStringLineEndings()
|
||||
// Clean up a multi-line string to conform to Unix line endings.
|
||||
// Reads from src and appends to dst, so usually dst should be empty.
|
||||
//
|
||||
// If there is no line ending at the end of a non-empty string, it can
|
||||
// be added automatically.
|
||||
//
|
||||
// Four different types of input are correctly handled:
|
||||
//
|
||||
// - Unix/Linux files: line ending is LF: pass through unchanged
|
||||
//
|
||||
// - DOS/Windows files: line ending is CRLF: convert to LF
|
||||
//
|
||||
// - Legacy Mac files: line ending is CR: convert to LF
|
||||
//
|
||||
// - Garbled files: random line endings: convert gracefully
|
||||
// lonely CR, lonely LF, CRLF: convert to LF
|
||||
//
|
||||
// @param src The multi-line string to convert
|
||||
// @param dst The converted string is appended to this string
|
||||
// @param auto_end_last_line Automatically terminate the last line
|
||||
//
|
||||
// Limitations:
|
||||
//
|
||||
// This does not do the right thing for CRCRLF files created by
|
||||
// broken programs that do another Unix->DOS conversion on files
|
||||
// that are already in CRLF format. For this, a two-pass approach
|
||||
// brute-force would be needed that
|
||||
//
|
||||
// (1) determines the presence of LF (first one is ok)
|
||||
// (2) if yes, removes any CR, else convert every CR to LF
|
||||
PROTOBUF_EXPORT void CleanStringLineEndings(const std::string& src,
|
||||
std::string* dst,
|
||||
bool auto_end_last_line);
|
||||
|
||||
// Same as above, but transforms the argument in place.
|
||||
PROTOBUF_EXPORT void CleanStringLineEndings(std::string* str,
|
||||
bool auto_end_last_line);
|
||||
|
||||
namespace strings {
|
||||
inline bool EndsWith(StringPiece text, StringPiece suffix) {
|
||||
return suffix.empty() ||
|
||||
(text.size() >= suffix.size() &&
|
||||
memcmp(text.data() + (text.size() - suffix.size()), suffix.data(),
|
||||
suffix.size()) == 0);
|
||||
}
|
||||
} // namespace strings
|
||||
|
||||
namespace internal {
|
||||
|
||||
// A locale-independent version of the standard strtod(), which always
|
||||
// uses a dot as the decimal separator.
|
||||
double NoLocaleStrtod(const char* str, char** endptr);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
|
||||
897
ubuntu/google/protobuf/stubs/strutil_unittest.cc
Normal file
897
ubuntu/google/protobuf/stubs/strutil_unittest.cc
Normal file
@@ -0,0 +1,897 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
|
||||
// TODO(kenton): Copy strutil tests from google3?
|
||||
|
||||
TEST(StringUtilityTest, ImmuneToLocales) {
|
||||
// Remember the old locale.
|
||||
char* old_locale_cstr = setlocale(LC_NUMERIC, nullptr);
|
||||
ASSERT_TRUE(old_locale_cstr != nullptr);
|
||||
std::string old_locale = old_locale_cstr;
|
||||
|
||||
// Set the locale to "C".
|
||||
ASSERT_TRUE(setlocale(LC_NUMERIC, "C") != nullptr);
|
||||
|
||||
EXPECT_EQ("1.5", SimpleDtoa(1.5));
|
||||
EXPECT_EQ("1.5", SimpleFtoa(1.5));
|
||||
|
||||
if (setlocale(LC_NUMERIC, "es_ES") == nullptr &&
|
||||
setlocale(LC_NUMERIC, "es_ES.utf8") == nullptr) {
|
||||
// Some systems may not have the desired locale available.
|
||||
GOOGLE_LOG(WARNING)
|
||||
<< "Couldn't set locale to es_ES. Skipping this test.";
|
||||
} else {
|
||||
EXPECT_EQ("1.5", SimpleDtoa(1.5));
|
||||
EXPECT_EQ("1.5", SimpleFtoa(1.5));
|
||||
}
|
||||
|
||||
// Return to original locale.
|
||||
setlocale(LC_NUMERIC, old_locale.c_str());
|
||||
}
|
||||
|
||||
#define EXPECT_EQ_ARRAY(len, x, y, msg) \
|
||||
for (int j = 0; j < len; ++j) { \
|
||||
EXPECT_EQ(x[j], y[j]) << "" # x << " != " # y \
|
||||
<< " byte " << j << ": " << msg; \
|
||||
}
|
||||
|
||||
static struct {
|
||||
int plain_length;
|
||||
const char* plaintext;
|
||||
const char* cyphertext;
|
||||
} base64_tests[] = {
|
||||
// Empty string.
|
||||
{ 0, "", ""},
|
||||
|
||||
// Basic bit patterns;
|
||||
// values obtained with "echo -n '...' | uuencode -m test"
|
||||
|
||||
{ 1, "\000", "AA==" },
|
||||
{ 1, "\001", "AQ==" },
|
||||
{ 1, "\002", "Ag==" },
|
||||
{ 1, "\004", "BA==" },
|
||||
{ 1, "\010", "CA==" },
|
||||
{ 1, "\020", "EA==" },
|
||||
{ 1, "\040", "IA==" },
|
||||
{ 1, "\100", "QA==" },
|
||||
{ 1, "\200", "gA==" },
|
||||
|
||||
{ 1, "\377", "/w==" },
|
||||
{ 1, "\376", "/g==" },
|
||||
{ 1, "\375", "/Q==" },
|
||||
{ 1, "\373", "+w==" },
|
||||
{ 1, "\367", "9w==" },
|
||||
{ 1, "\357", "7w==" },
|
||||
{ 1, "\337", "3w==" },
|
||||
{ 1, "\277", "vw==" },
|
||||
{ 1, "\177", "fw==" },
|
||||
{ 2, "\000\000", "AAA=" },
|
||||
{ 2, "\000\001", "AAE=" },
|
||||
{ 2, "\000\002", "AAI=" },
|
||||
{ 2, "\000\004", "AAQ=" },
|
||||
{ 2, "\000\010", "AAg=" },
|
||||
{ 2, "\000\020", "ABA=" },
|
||||
{ 2, "\000\040", "ACA=" },
|
||||
{ 2, "\000\100", "AEA=" },
|
||||
{ 2, "\000\200", "AIA=" },
|
||||
{ 2, "\001\000", "AQA=" },
|
||||
{ 2, "\002\000", "AgA=" },
|
||||
{ 2, "\004\000", "BAA=" },
|
||||
{ 2, "\010\000", "CAA=" },
|
||||
{ 2, "\020\000", "EAA=" },
|
||||
{ 2, "\040\000", "IAA=" },
|
||||
{ 2, "\100\000", "QAA=" },
|
||||
{ 2, "\200\000", "gAA=" },
|
||||
|
||||
{ 2, "\377\377", "//8=" },
|
||||
{ 2, "\377\376", "//4=" },
|
||||
{ 2, "\377\375", "//0=" },
|
||||
{ 2, "\377\373", "//s=" },
|
||||
{ 2, "\377\367", "//c=" },
|
||||
{ 2, "\377\357", "/+8=" },
|
||||
{ 2, "\377\337", "/98=" },
|
||||
{ 2, "\377\277", "/78=" },
|
||||
{ 2, "\377\177", "/38=" },
|
||||
{ 2, "\376\377", "/v8=" },
|
||||
{ 2, "\375\377", "/f8=" },
|
||||
{ 2, "\373\377", "+/8=" },
|
||||
{ 2, "\367\377", "9/8=" },
|
||||
{ 2, "\357\377", "7/8=" },
|
||||
{ 2, "\337\377", "3/8=" },
|
||||
{ 2, "\277\377", "v/8=" },
|
||||
{ 2, "\177\377", "f/8=" },
|
||||
|
||||
{ 3, "\000\000\000", "AAAA" },
|
||||
{ 3, "\000\000\001", "AAAB" },
|
||||
{ 3, "\000\000\002", "AAAC" },
|
||||
{ 3, "\000\000\004", "AAAE" },
|
||||
{ 3, "\000\000\010", "AAAI" },
|
||||
{ 3, "\000\000\020", "AAAQ" },
|
||||
{ 3, "\000\000\040", "AAAg" },
|
||||
{ 3, "\000\000\100", "AABA" },
|
||||
{ 3, "\000\000\200", "AACA" },
|
||||
{ 3, "\000\001\000", "AAEA" },
|
||||
{ 3, "\000\002\000", "AAIA" },
|
||||
{ 3, "\000\004\000", "AAQA" },
|
||||
{ 3, "\000\010\000", "AAgA" },
|
||||
{ 3, "\000\020\000", "ABAA" },
|
||||
{ 3, "\000\040\000", "ACAA" },
|
||||
{ 3, "\000\100\000", "AEAA" },
|
||||
{ 3, "\000\200\000", "AIAA" },
|
||||
{ 3, "\001\000\000", "AQAA" },
|
||||
{ 3, "\002\000\000", "AgAA" },
|
||||
{ 3, "\004\000\000", "BAAA" },
|
||||
{ 3, "\010\000\000", "CAAA" },
|
||||
{ 3, "\020\000\000", "EAAA" },
|
||||
{ 3, "\040\000\000", "IAAA" },
|
||||
{ 3, "\100\000\000", "QAAA" },
|
||||
{ 3, "\200\000\000", "gAAA" },
|
||||
|
||||
{ 3, "\377\377\377", "////" },
|
||||
{ 3, "\377\377\376", "///+" },
|
||||
{ 3, "\377\377\375", "///9" },
|
||||
{ 3, "\377\377\373", "///7" },
|
||||
{ 3, "\377\377\367", "///3" },
|
||||
{ 3, "\377\377\357", "///v" },
|
||||
{ 3, "\377\377\337", "///f" },
|
||||
{ 3, "\377\377\277", "//+/" },
|
||||
{ 3, "\377\377\177", "//9/" },
|
||||
{ 3, "\377\376\377", "//7/" },
|
||||
{ 3, "\377\375\377", "//3/" },
|
||||
{ 3, "\377\373\377", "//v/" },
|
||||
{ 3, "\377\367\377", "//f/" },
|
||||
{ 3, "\377\357\377", "/+//" },
|
||||
{ 3, "\377\337\377", "/9//" },
|
||||
{ 3, "\377\277\377", "/7//" },
|
||||
{ 3, "\377\177\377", "/3//" },
|
||||
{ 3, "\376\377\377", "/v//" },
|
||||
{ 3, "\375\377\377", "/f//" },
|
||||
{ 3, "\373\377\377", "+///" },
|
||||
{ 3, "\367\377\377", "9///" },
|
||||
{ 3, "\357\377\377", "7///" },
|
||||
{ 3, "\337\377\377", "3///" },
|
||||
{ 3, "\277\377\377", "v///" },
|
||||
{ 3, "\177\377\377", "f///" },
|
||||
|
||||
// Random numbers: values obtained with
|
||||
//
|
||||
// #! /bin/bash
|
||||
// dd bs=$1 count=1 if=/dev/random of=/tmp/bar.random
|
||||
// od -N $1 -t o1 /tmp/bar.random
|
||||
// uuencode -m test < /tmp/bar.random
|
||||
//
|
||||
// where $1 is the number of bytes (2, 3)
|
||||
|
||||
{ 2, "\243\361", "o/E=" },
|
||||
{ 2, "\024\167", "FHc=" },
|
||||
{ 2, "\313\252", "y6o=" },
|
||||
{ 2, "\046\041", "JiE=" },
|
||||
{ 2, "\145\236", "ZZ4=" },
|
||||
{ 2, "\254\325", "rNU=" },
|
||||
{ 2, "\061\330", "Mdg=" },
|
||||
{ 2, "\245\032", "pRo=" },
|
||||
{ 2, "\006\000", "BgA=" },
|
||||
{ 2, "\375\131", "/Vk=" },
|
||||
{ 2, "\303\210", "w4g=" },
|
||||
{ 2, "\040\037", "IB8=" },
|
||||
{ 2, "\261\372", "sfo=" },
|
||||
{ 2, "\335\014", "3Qw=" },
|
||||
{ 2, "\233\217", "m48=" },
|
||||
{ 2, "\373\056", "+y4=" },
|
||||
{ 2, "\247\232", "p5o=" },
|
||||
{ 2, "\107\053", "Rys=" },
|
||||
{ 2, "\204\077", "hD8=" },
|
||||
{ 2, "\276\211", "vok=" },
|
||||
{ 2, "\313\110", "y0g=" },
|
||||
{ 2, "\363\376", "8/4=" },
|
||||
{ 2, "\251\234", "qZw=" },
|
||||
{ 2, "\103\262", "Q7I=" },
|
||||
{ 2, "\142\312", "Yso=" },
|
||||
{ 2, "\067\211", "N4k=" },
|
||||
{ 2, "\220\001", "kAE=" },
|
||||
{ 2, "\152\240", "aqA=" },
|
||||
{ 2, "\367\061", "9zE=" },
|
||||
{ 2, "\133\255", "W60=" },
|
||||
{ 2, "\176\035", "fh0=" },
|
||||
{ 2, "\032\231", "Gpk=" },
|
||||
|
||||
{ 3, "\013\007\144", "Cwdk" },
|
||||
{ 3, "\030\112\106", "GEpG" },
|
||||
{ 3, "\047\325\046", "J9Um" },
|
||||
{ 3, "\310\160\022", "yHAS" },
|
||||
{ 3, "\131\100\237", "WUCf" },
|
||||
{ 3, "\064\342\134", "NOJc" },
|
||||
{ 3, "\010\177\004", "CH8E" },
|
||||
{ 3, "\345\147\205", "5WeF" },
|
||||
{ 3, "\300\343\360", "wOPw" },
|
||||
{ 3, "\061\240\201", "MaCB" },
|
||||
{ 3, "\225\333\044", "ldsk" },
|
||||
{ 3, "\215\137\352", "jV/q" },
|
||||
{ 3, "\371\147\160", "+Wdw" },
|
||||
{ 3, "\030\320\051", "GNAp" },
|
||||
{ 3, "\044\174\241", "JHyh" },
|
||||
{ 3, "\260\127\037", "sFcf" },
|
||||
{ 3, "\111\045\033", "SSUb" },
|
||||
{ 3, "\202\114\107", "gkxH" },
|
||||
{ 3, "\057\371\042", "L/ki" },
|
||||
{ 3, "\223\247\244", "k6ek" },
|
||||
{ 3, "\047\216\144", "J45k" },
|
||||
{ 3, "\203\070\327", "gzjX" },
|
||||
{ 3, "\247\140\072", "p2A6" },
|
||||
{ 3, "\124\115\116", "VE1O" },
|
||||
{ 3, "\157\162\050", "b3Io" },
|
||||
{ 3, "\357\223\004", "75ME" },
|
||||
{ 3, "\052\117\156", "Kk9u" },
|
||||
{ 3, "\347\154\000", "52wA" },
|
||||
{ 3, "\303\012\142", "wwpi" },
|
||||
{ 3, "\060\035\362", "MB3y" },
|
||||
{ 3, "\130\226\361", "WJbx" },
|
||||
{ 3, "\173\013\071", "ews5" },
|
||||
{ 3, "\336\004\027", "3gQX" },
|
||||
{ 3, "\357\366\234", "7/ac" },
|
||||
{ 3, "\353\304\111", "68RJ" },
|
||||
{ 3, "\024\264\131", "FLRZ" },
|
||||
{ 3, "\075\114\251", "PUyp" },
|
||||
{ 3, "\315\031\225", "zRmV" },
|
||||
{ 3, "\154\201\276", "bIG+" },
|
||||
{ 3, "\200\066\072", "gDY6" },
|
||||
{ 3, "\142\350\267", "Yui3" },
|
||||
{ 3, "\033\000\166", "GwB2" },
|
||||
{ 3, "\210\055\077", "iC0/" },
|
||||
{ 3, "\341\037\124", "4R9U" },
|
||||
{ 3, "\161\103\152", "cUNq" },
|
||||
{ 3, "\270\142\131", "uGJZ" },
|
||||
{ 3, "\337\076\074", "3z48" },
|
||||
{ 3, "\375\106\362", "/Uby" },
|
||||
{ 3, "\227\301\127", "l8FX" },
|
||||
{ 3, "\340\002\234", "4AKc" },
|
||||
{ 3, "\121\064\033", "UTQb" },
|
||||
{ 3, "\157\134\143", "b1xj" },
|
||||
{ 3, "\247\055\327", "py3X" },
|
||||
{ 3, "\340\142\005", "4GIF" },
|
||||
{ 3, "\060\260\143", "MLBj" },
|
||||
{ 3, "\075\203\170", "PYN4" },
|
||||
{ 3, "\143\160\016", "Y3AO" },
|
||||
{ 3, "\313\013\063", "ywsz" },
|
||||
{ 3, "\174\236\135", "fJ5d" },
|
||||
{ 3, "\103\047\026", "QycW" },
|
||||
{ 3, "\365\005\343", "9QXj" },
|
||||
{ 3, "\271\160\223", "uXCT" },
|
||||
{ 3, "\362\255\172", "8q16" },
|
||||
{ 3, "\113\012\015", "SwoN" },
|
||||
|
||||
// various lengths, generated by this python script:
|
||||
//
|
||||
// from string import lowercase as lc
|
||||
// for i in range(27):
|
||||
// print '{ %2d, "%s",%s "%s" },' % (i, lc[:i], ' ' * (26-i),
|
||||
// lc[:i].encode('base64').strip())
|
||||
|
||||
{ 0, "", "" },
|
||||
{ 1, "a", "YQ==" },
|
||||
{ 2, "ab", "YWI=" },
|
||||
{ 3, "abc", "YWJj" },
|
||||
{ 4, "abcd", "YWJjZA==" },
|
||||
{ 5, "abcde", "YWJjZGU=" },
|
||||
{ 6, "abcdef", "YWJjZGVm" },
|
||||
{ 7, "abcdefg", "YWJjZGVmZw==" },
|
||||
{ 8, "abcdefgh", "YWJjZGVmZ2g=" },
|
||||
{ 9, "abcdefghi", "YWJjZGVmZ2hp" },
|
||||
{ 10, "abcdefghij", "YWJjZGVmZ2hpag==" },
|
||||
{ 11, "abcdefghijk", "YWJjZGVmZ2hpams=" },
|
||||
{ 12, "abcdefghijkl", "YWJjZGVmZ2hpamts" },
|
||||
{ 13, "abcdefghijklm", "YWJjZGVmZ2hpamtsbQ==" },
|
||||
{ 14, "abcdefghijklmn", "YWJjZGVmZ2hpamtsbW4=" },
|
||||
{ 15, "abcdefghijklmno", "YWJjZGVmZ2hpamtsbW5v" },
|
||||
{ 16, "abcdefghijklmnop", "YWJjZGVmZ2hpamtsbW5vcA==" },
|
||||
{ 17, "abcdefghijklmnopq", "YWJjZGVmZ2hpamtsbW5vcHE=" },
|
||||
{ 18, "abcdefghijklmnopqr", "YWJjZGVmZ2hpamtsbW5vcHFy" },
|
||||
{ 19, "abcdefghijklmnopqrs", "YWJjZGVmZ2hpamtsbW5vcHFycw==" },
|
||||
{ 20, "abcdefghijklmnopqrst", "YWJjZGVmZ2hpamtsbW5vcHFyc3Q=" },
|
||||
{ 21, "abcdefghijklmnopqrstu", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1" },
|
||||
{ 22, "abcdefghijklmnopqrstuv", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dg==" },
|
||||
{ 23, "abcdefghijklmnopqrstuvw", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnc=" },
|
||||
{ 24, "abcdefghijklmnopqrstuvwx", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4" },
|
||||
{ 25, "abcdefghijklmnopqrstuvwxy", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ==" },
|
||||
{ 26, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=" },
|
||||
};
|
||||
|
||||
static struct {
|
||||
const char* plaintext;
|
||||
const char* cyphertext;
|
||||
} base64_strings[] = {
|
||||
// Some google quotes
|
||||
// Cyphertext created with "uuencode (GNU sharutils) 4.6.3"
|
||||
// (Note that we're testing the websafe encoding, though, so if
|
||||
// you add messages, be sure to run "tr -- '+/' '-_'" on the output)
|
||||
{ "I was always good at math and science, and I never realized "
|
||||
"that was unusual or somehow undesirable. So one of the things "
|
||||
"I care a lot about is helping to remove that stigma, "
|
||||
"to show girls that you can be feminine, you can like the things "
|
||||
"that girls like, but you can also be really good at technology. "
|
||||
"You can be really good at building things."
|
||||
" - Marissa Meyer, Newsweek, 2010-12-22" "\n",
|
||||
|
||||
"SSB3YXMgYWx3YXlzIGdvb2QgYXQgbWF0aCBhbmQgc2NpZW5jZSwgYW5kIEkg"
|
||||
"bmV2ZXIgcmVhbGl6ZWQgdGhhdCB3YXMgdW51c3VhbCBvciBzb21laG93IHVu"
|
||||
"ZGVzaXJhYmxlLiBTbyBvbmUgb2YgdGhlIHRoaW5ncyBJIGNhcmUgYSBsb3Qg"
|
||||
"YWJvdXQgaXMgaGVscGluZyB0byByZW1vdmUgdGhhdCBzdGlnbWEsIHRvIHNo"
|
||||
"b3cgZ2lybHMgdGhhdCB5b3UgY2FuIGJlIGZlbWluaW5lLCB5b3UgY2FuIGxp"
|
||||
"a2UgdGhlIHRoaW5ncyB0aGF0IGdpcmxzIGxpa2UsIGJ1dCB5b3UgY2FuIGFs"
|
||||
"c28gYmUgcmVhbGx5IGdvb2QgYXQgdGVjaG5vbG9neS4gWW91IGNhbiBiZSBy"
|
||||
"ZWFsbHkgZ29vZCBhdCBidWlsZGluZyB0aGluZ3MuIC0gTWFyaXNzYSBNZXll"
|
||||
"ciwgTmV3c3dlZWssIDIwMTAtMTItMjIK" },
|
||||
|
||||
{ "Typical first year for a new cluster: "
|
||||
"~0.5 overheating "
|
||||
"~1 PDU failure "
|
||||
"~1 rack-move "
|
||||
"~1 network rewiring "
|
||||
"~20 rack failures "
|
||||
"~5 racks go wonky "
|
||||
"~8 network maintenances "
|
||||
"~12 router reloads "
|
||||
"~3 router failures "
|
||||
"~dozens of minor 30-second blips for dns "
|
||||
"~1000 individual machine failures "
|
||||
"~thousands of hard drive failures "
|
||||
"slow disks, bad memory, misconfigured machines, flaky machines, etc."
|
||||
" - Jeff Dean, The Joys of Real Hardware" "\n",
|
||||
|
||||
"VHlwaWNhbCBmaXJzdCB5ZWFyIGZvciBhIG5ldyBjbHVzdGVyOiB-MC41IG92"
|
||||
"ZXJoZWF0aW5nIH4xIFBEVSBmYWlsdXJlIH4xIHJhY2stbW92ZSB-MSBuZXR3"
|
||||
"b3JrIHJld2lyaW5nIH4yMCByYWNrIGZhaWx1cmVzIH41IHJhY2tzIGdvIHdv"
|
||||
"bmt5IH44IG5ldHdvcmsgbWFpbnRlbmFuY2VzIH4xMiByb3V0ZXIgcmVsb2Fk"
|
||||
"cyB-MyByb3V0ZXIgZmFpbHVyZXMgfmRvemVucyBvZiBtaW5vciAzMC1zZWNv"
|
||||
"bmQgYmxpcHMgZm9yIGRucyB-MTAwMCBpbmRpdmlkdWFsIG1hY2hpbmUgZmFp"
|
||||
"bHVyZXMgfnRob3VzYW5kcyBvZiBoYXJkIGRyaXZlIGZhaWx1cmVzIHNsb3cg"
|
||||
"ZGlza3MsIGJhZCBtZW1vcnksIG1pc2NvbmZpZ3VyZWQgbWFjaGluZXMsIGZs"
|
||||
"YWt5IG1hY2hpbmVzLCBldGMuIC0gSmVmZiBEZWFuLCBUaGUgSm95cyBvZiBS"
|
||||
"ZWFsIEhhcmR3YXJlCg" },
|
||||
|
||||
{ "I'm the head of the webspam team at Google. "
|
||||
"That means that if you type your name into Google and get porn back, "
|
||||
"it's my fault. Unless you're a porn star, in which case porn is a "
|
||||
"completely reasonable response."
|
||||
" - Matt Cutts, Google Plus" "\n",
|
||||
|
||||
"SSdtIHRoZSBoZWFkIG9mIHRoZSB3ZWJzcGFtIHRlYW0gYXQgR29vZ2xlLiAg"
|
||||
"VGhhdCBtZWFucyB0aGF0IGlmIHlvdSB0eXBlIHlvdXIgbmFtZSBpbnRvIEdv"
|
||||
"b2dsZSBhbmQgZ2V0IHBvcm4gYmFjaywgaXQncyBteSBmYXVsdC4gVW5sZXNz"
|
||||
"IHlvdSdyZSBhIHBvcm4gc3RhciwgaW4gd2hpY2ggY2FzZSBwb3JuIGlzIGEg"
|
||||
"Y29tcGxldGVseSByZWFzb25hYmxlIHJlc3BvbnNlLiAtIE1hdHQgQ3V0dHMs"
|
||||
"IEdvb2dsZSBQbHVzCg" },
|
||||
|
||||
{ "It will still be a long time before machines approach human intelligence. "
|
||||
"But luckily, machines don't actually have to be intelligent; "
|
||||
"they just have to fake it. Access to a wealth of information, "
|
||||
"combined with a rudimentary decision-making capacity, "
|
||||
"can often be almost as useful. Of course, the results are better yet "
|
||||
"when coupled with intelligence. A reference librarian with access to "
|
||||
"a good search engine is a formidable tool."
|
||||
" - Craig Silverstein, Siemens Pictures of the Future, Spring 2004" "\n",
|
||||
|
||||
"SXQgd2lsbCBzdGlsbCBiZSBhIGxvbmcgdGltZSBiZWZvcmUgbWFjaGluZXMg"
|
||||
"YXBwcm9hY2ggaHVtYW4gaW50ZWxsaWdlbmNlLiBCdXQgbHVja2lseSwgbWFj"
|
||||
"aGluZXMgZG9uJ3QgYWN0dWFsbHkgaGF2ZSB0byBiZSBpbnRlbGxpZ2VudDsg"
|
||||
"dGhleSBqdXN0IGhhdmUgdG8gZmFrZSBpdC4gQWNjZXNzIHRvIGEgd2VhbHRo"
|
||||
"IG9mIGluZm9ybWF0aW9uLCBjb21iaW5lZCB3aXRoIGEgcnVkaW1lbnRhcnkg"
|
||||
"ZGVjaXNpb24tbWFraW5nIGNhcGFjaXR5LCBjYW4gb2Z0ZW4gYmUgYWxtb3N0"
|
||||
"IGFzIHVzZWZ1bC4gT2YgY291cnNlLCB0aGUgcmVzdWx0cyBhcmUgYmV0dGVy"
|
||||
"IHlldCB3aGVuIGNvdXBsZWQgd2l0aCBpbnRlbGxpZ2VuY2UuIEEgcmVmZXJl"
|
||||
"bmNlIGxpYnJhcmlhbiB3aXRoIGFjY2VzcyB0byBhIGdvb2Qgc2VhcmNoIGVu"
|
||||
"Z2luZSBpcyBhIGZvcm1pZGFibGUgdG9vbC4gLSBDcmFpZyBTaWx2ZXJzdGVp"
|
||||
"biwgU2llbWVucyBQaWN0dXJlcyBvZiB0aGUgRnV0dXJlLCBTcHJpbmcgMjAw"
|
||||
"NAo" },
|
||||
|
||||
// Degenerate edge case
|
||||
{ "",
|
||||
"" },
|
||||
};
|
||||
|
||||
TEST(Base64, EscapeAndUnescape) {
|
||||
// Check the short strings; this tests the math (and boundaries)
|
||||
for (int i = 0; i < sizeof(base64_tests) / sizeof(base64_tests[0]); ++i) {
|
||||
char encode_buffer[100];
|
||||
int encode_length;
|
||||
char decode_buffer[100];
|
||||
int decode_length;
|
||||
int cypher_length;
|
||||
std::string decode_str;
|
||||
|
||||
const unsigned char* unsigned_plaintext =
|
||||
reinterpret_cast<const unsigned char*>(base64_tests[i].plaintext);
|
||||
|
||||
StringPiece plaintext(base64_tests[i].plaintext,
|
||||
base64_tests[i].plain_length);
|
||||
|
||||
cypher_length = strlen(base64_tests[i].cyphertext);
|
||||
|
||||
// The basic escape function:
|
||||
memset(encode_buffer, 0, sizeof(encode_buffer));
|
||||
encode_length = Base64Escape(unsigned_plaintext,
|
||||
base64_tests[i].plain_length,
|
||||
encode_buffer,
|
||||
sizeof(encode_buffer));
|
||||
// Is it of the expected length?
|
||||
EXPECT_EQ(encode_length, cypher_length);
|
||||
// Would it have been okay to allocate only CalculateBase64EscapeLen()?
|
||||
EXPECT_EQ(CalculateBase64EscapedLen(base64_tests[i].plain_length),
|
||||
encode_length);
|
||||
|
||||
// Is it the expected encoded value?
|
||||
ASSERT_STREQ(encode_buffer, base64_tests[i].cyphertext);
|
||||
|
||||
// If we encode it into a buffer of exactly the right length...
|
||||
memset(encode_buffer, 0, sizeof(encode_buffer));
|
||||
encode_length = Base64Escape(unsigned_plaintext,
|
||||
base64_tests[i].plain_length,
|
||||
encode_buffer,
|
||||
cypher_length);
|
||||
// Is it still of the expected length?
|
||||
EXPECT_EQ(encode_length, cypher_length);
|
||||
|
||||
// And is the value still correct? (i.e., not losing the last byte)
|
||||
EXPECT_STREQ(encode_buffer, base64_tests[i].cyphertext);
|
||||
|
||||
// If we decode it back:
|
||||
decode_str.clear();
|
||||
EXPECT_TRUE(Base64Unescape(
|
||||
StringPiece(encode_buffer, cypher_length), &decode_str));
|
||||
|
||||
// Is it of the expected length?
|
||||
EXPECT_EQ(base64_tests[i].plain_length, decode_str.length());
|
||||
|
||||
// Is it the expected decoded value?
|
||||
EXPECT_EQ(plaintext, decode_str);
|
||||
|
||||
// Let's try with a pre-populated string.
|
||||
std::string encoded("this junk should be ignored");
|
||||
Base64Escape(
|
||||
std::string(base64_tests[i].plaintext, base64_tests[i].plain_length),
|
||||
&encoded);
|
||||
EXPECT_EQ(encoded, std::string(encode_buffer, cypher_length));
|
||||
|
||||
std::string decoded("this junk should be ignored");
|
||||
EXPECT_TRUE(Base64Unescape(
|
||||
StringPiece(encode_buffer, cypher_length), &decoded));
|
||||
EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
|
||||
EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);
|
||||
|
||||
// Our decoder treats the padding '=' characters at the end as
|
||||
// optional (but if there are any, there must be the correct
|
||||
// number of them.) If encode_buffer has any, run some additional
|
||||
// tests that fiddle with them.
|
||||
char* first_equals = strchr(encode_buffer, '=');
|
||||
if (first_equals) {
|
||||
// How many equals signs does the string start with?
|
||||
int equals = (*(first_equals+1) == '=') ? 2 : 1;
|
||||
|
||||
// Try chopping off the equals sign(s) entirely. The decoder
|
||||
// should still be okay with this.
|
||||
std::string decoded2("this junk should also be ignored");
|
||||
*first_equals = '\0';
|
||||
EXPECT_TRUE(Base64Unescape(
|
||||
StringPiece(encode_buffer, first_equals - encode_buffer), &decoded2));
|
||||
EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
|
||||
EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);
|
||||
|
||||
// Now test chopping off the equals sign(s) and adding
|
||||
// whitespace. Our decoder should still accept this.
|
||||
decoded2.assign("this junk should be ignored");
|
||||
*first_equals = ' ';
|
||||
*(first_equals+1) = '\0';
|
||||
EXPECT_TRUE(Base64Unescape(
|
||||
StringPiece(encode_buffer, first_equals - encode_buffer + 1),
|
||||
&decoded2));
|
||||
EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
|
||||
EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);
|
||||
|
||||
// Now stick a bad character at the end of the string. The decoder
|
||||
// should refuse this string.
|
||||
decoded2.assign("this junk should be ignored");
|
||||
*first_equals = '?';
|
||||
*(first_equals+1) = '\0';
|
||||
EXPECT_TRUE(
|
||||
!Base64Unescape(
|
||||
StringPiece(encode_buffer, first_equals - encode_buffer + 1),
|
||||
&decoded2));
|
||||
|
||||
int len;
|
||||
|
||||
// Test whitespace mixed with the padding. (eg "AA = = ") The
|
||||
// decoder should accept this.
|
||||
if (equals == 2) {
|
||||
snprintf(first_equals, 6, " = = ");
|
||||
len = first_equals - encode_buffer + 5;
|
||||
} else {
|
||||
snprintf(first_equals, 6, " = ");
|
||||
len = first_equals - encode_buffer + 3;
|
||||
}
|
||||
decoded2.assign("this junk should be ignored");
|
||||
EXPECT_TRUE(
|
||||
Base64Unescape(StringPiece(encode_buffer, len), &decoded2));
|
||||
EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
|
||||
EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);
|
||||
|
||||
// Test whitespace mixed with the padding, but with the wrong
|
||||
// number of equals signs (eg "AA = "). The decoder should
|
||||
// refuse these strings.
|
||||
if (equals == 1) {
|
||||
snprintf(first_equals, 6, " = = ");
|
||||
len = first_equals - encode_buffer + 5;
|
||||
} else {
|
||||
snprintf(first_equals, 6, " = ");
|
||||
len = first_equals - encode_buffer + 3;
|
||||
}
|
||||
EXPECT_TRUE(
|
||||
!Base64Unescape(StringPiece(encode_buffer, len), &decoded2));
|
||||
}
|
||||
|
||||
// Cool! the basic Base64 encoder/decoder works.
|
||||
// Let's try the alternate alphabet: tr -- '+/' '-_'
|
||||
|
||||
char websafe[100];
|
||||
memset(websafe, 0, sizeof(websafe));
|
||||
strncpy(websafe, base64_tests[i].cyphertext, cypher_length);
|
||||
for (int c = 0; c < sizeof(websafe); ++c) {
|
||||
if ('+' == websafe[c]) { websafe[c] = '-'; }
|
||||
if ('/' == websafe[c]) { websafe[c] = '_'; }
|
||||
}
|
||||
|
||||
// The websafe escape function:
|
||||
memset(encode_buffer, 0, sizeof(encode_buffer));
|
||||
encode_length = WebSafeBase64Escape(unsigned_plaintext,
|
||||
base64_tests[i].plain_length,
|
||||
encode_buffer,
|
||||
sizeof(encode_buffer),
|
||||
true);
|
||||
// Is it of the expected length?
|
||||
EXPECT_EQ(encode_length, cypher_length);
|
||||
EXPECT_EQ(
|
||||
CalculateBase64EscapedLen(base64_tests[i].plain_length, true),
|
||||
encode_length);
|
||||
|
||||
// Is it the expected encoded value?
|
||||
EXPECT_STREQ(encode_buffer, websafe);
|
||||
|
||||
// If we encode it into a buffer of exactly the right length...
|
||||
memset(encode_buffer, 0, sizeof(encode_buffer));
|
||||
encode_length = WebSafeBase64Escape(unsigned_plaintext,
|
||||
base64_tests[i].plain_length,
|
||||
encode_buffer,
|
||||
cypher_length,
|
||||
true);
|
||||
// Is it still of the expected length?
|
||||
EXPECT_EQ(encode_length, cypher_length);
|
||||
|
||||
// And is the value still correct? (i.e., not losing the last byte)
|
||||
EXPECT_STREQ(encode_buffer, websafe);
|
||||
|
||||
// Let's try the string version of the encoder
|
||||
encoded = "this junk should be ignored";
|
||||
WebSafeBase64Escape(
|
||||
unsigned_plaintext, base64_tests[i].plain_length,
|
||||
&encoded, true);
|
||||
EXPECT_EQ(encoded.size(), cypher_length);
|
||||
EXPECT_STREQ(encoded.c_str(), websafe);
|
||||
|
||||
// If we decode it back:
|
||||
memset(decode_buffer, 0, sizeof(decode_buffer));
|
||||
decode_length = WebSafeBase64Unescape(encode_buffer,
|
||||
cypher_length,
|
||||
decode_buffer,
|
||||
sizeof(decode_buffer));
|
||||
|
||||
// Is it of the expected length?
|
||||
EXPECT_EQ(decode_length, base64_tests[i].plain_length);
|
||||
|
||||
// Is it the expected decoded value?
|
||||
EXPECT_EQ(0,
|
||||
memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
|
||||
|
||||
// If we decode it into a buffer of exactly the right length...
|
||||
memset(decode_buffer, 0, sizeof(decode_buffer));
|
||||
decode_length = WebSafeBase64Unescape(encode_buffer,
|
||||
cypher_length,
|
||||
decode_buffer,
|
||||
decode_length);
|
||||
|
||||
// Is it still of the expected length?
|
||||
EXPECT_EQ(decode_length, base64_tests[i].plain_length);
|
||||
|
||||
// And is it the expected decoded value?
|
||||
EXPECT_EQ(0,
|
||||
memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
|
||||
|
||||
// Try using '.' for the pad character.
|
||||
for (int c = cypher_length - 1; c >= 0 && '=' == encode_buffer[c]; --c) {
|
||||
encode_buffer[c] = '.';
|
||||
}
|
||||
|
||||
// If we decode it back:
|
||||
memset(decode_buffer, 0, sizeof(decode_buffer));
|
||||
decode_length = WebSafeBase64Unescape(encode_buffer,
|
||||
cypher_length,
|
||||
decode_buffer,
|
||||
sizeof(decode_buffer));
|
||||
|
||||
// Is it of the expected length?
|
||||
EXPECT_EQ(decode_length, base64_tests[i].plain_length);
|
||||
|
||||
// Is it the expected decoded value?
|
||||
EXPECT_EQ(0,
|
||||
memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
|
||||
|
||||
// If we decode it into a buffer of exactly the right length...
|
||||
memset(decode_buffer, 0, sizeof(decode_buffer));
|
||||
decode_length = WebSafeBase64Unescape(encode_buffer,
|
||||
cypher_length,
|
||||
decode_buffer,
|
||||
decode_length);
|
||||
|
||||
// Is it still of the expected length?
|
||||
EXPECT_EQ(decode_length, base64_tests[i].plain_length);
|
||||
|
||||
// And is it the expected decoded value?
|
||||
EXPECT_EQ(0,
|
||||
memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
|
||||
|
||||
// Let's try the string version of the decoder
|
||||
decoded = "this junk should be ignored";
|
||||
EXPECT_TRUE(WebSafeBase64Unescape(
|
||||
StringPiece(encode_buffer, cypher_length), &decoded));
|
||||
EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
|
||||
EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);
|
||||
|
||||
// Okay! the websafe Base64 encoder/decoder works.
|
||||
// Let's try the unpadded version
|
||||
|
||||
for (int c = 0; c < sizeof(websafe); ++c) {
|
||||
if ('=' == websafe[c]) {
|
||||
websafe[c] = '\0';
|
||||
cypher_length = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The websafe escape function:
|
||||
memset(encode_buffer, 0, sizeof(encode_buffer));
|
||||
encode_length = WebSafeBase64Escape(unsigned_plaintext,
|
||||
base64_tests[i].plain_length,
|
||||
encode_buffer,
|
||||
sizeof(encode_buffer),
|
||||
false);
|
||||
// Is it of the expected length?
|
||||
EXPECT_EQ(encode_length, cypher_length);
|
||||
EXPECT_EQ(
|
||||
CalculateBase64EscapedLen(base64_tests[i].plain_length, false),
|
||||
encode_length);
|
||||
|
||||
// Is it the expected encoded value?
|
||||
EXPECT_STREQ(encode_buffer, websafe);
|
||||
|
||||
// If we encode it into a buffer of exactly the right length...
|
||||
memset(encode_buffer, 0, sizeof(encode_buffer));
|
||||
encode_length = WebSafeBase64Escape(unsigned_plaintext,
|
||||
base64_tests[i].plain_length,
|
||||
encode_buffer,
|
||||
cypher_length,
|
||||
false);
|
||||
// Is it still of the expected length?
|
||||
EXPECT_EQ(encode_length, cypher_length);
|
||||
|
||||
// And is the value still correct? (i.e., not losing the last byte)
|
||||
EXPECT_STREQ(encode_buffer, websafe);
|
||||
|
||||
// Let's try the (other) string version of the encoder
|
||||
std::string plain(base64_tests[i].plaintext, base64_tests[i].plain_length);
|
||||
encoded = "this junk should be ignored";
|
||||
WebSafeBase64Escape(plain, &encoded);
|
||||
EXPECT_EQ(encoded.size(), cypher_length);
|
||||
EXPECT_STREQ(encoded.c_str(), websafe);
|
||||
|
||||
// If we decode it back:
|
||||
memset(decode_buffer, 0, sizeof(decode_buffer));
|
||||
decode_length = WebSafeBase64Unescape(encode_buffer,
|
||||
cypher_length,
|
||||
decode_buffer,
|
||||
sizeof(decode_buffer));
|
||||
|
||||
// Is it of the expected length?
|
||||
EXPECT_EQ(decode_length, base64_tests[i].plain_length);
|
||||
|
||||
// Is it the expected decoded value?
|
||||
EXPECT_EQ(0,
|
||||
memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
|
||||
|
||||
// If we decode it into a buffer of exactly the right length...
|
||||
memset(decode_buffer, 0, sizeof(decode_buffer));
|
||||
decode_length = WebSafeBase64Unescape(encode_buffer,
|
||||
cypher_length,
|
||||
decode_buffer,
|
||||
decode_length);
|
||||
|
||||
// Is it still of the expected length?
|
||||
EXPECT_EQ(decode_length, base64_tests[i].plain_length);
|
||||
|
||||
// And is it the expected decoded value?
|
||||
EXPECT_EQ(0,
|
||||
memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
|
||||
|
||||
|
||||
// Let's try the string version of the decoder
|
||||
decoded = "this junk should be ignored";
|
||||
EXPECT_TRUE(WebSafeBase64Unescape(
|
||||
StringPiece(encode_buffer, cypher_length), &decoded));
|
||||
EXPECT_EQ(decoded.size(), base64_tests[i].plain_length);
|
||||
EXPECT_EQ_ARRAY(decoded.size(), decoded, base64_tests[i].plaintext, i);
|
||||
|
||||
// This value works. Try the next.
|
||||
}
|
||||
|
||||
// Now try the long strings, this tests the streaming
|
||||
for (int i = 0; i < sizeof(base64_strings) / sizeof(base64_strings[0]);
|
||||
++i) {
|
||||
const unsigned char* unsigned_plaintext =
|
||||
reinterpret_cast<const unsigned char*>(base64_strings[i].plaintext);
|
||||
int plain_length = strlen(base64_strings[i].plaintext);
|
||||
int cypher_length = strlen(base64_strings[i].cyphertext);
|
||||
std::vector<char> buffer(cypher_length+1);
|
||||
int encode_length = WebSafeBase64Escape(unsigned_plaintext,
|
||||
plain_length,
|
||||
&buffer[0],
|
||||
buffer.size(),
|
||||
false);
|
||||
EXPECT_EQ(cypher_length, encode_length);
|
||||
EXPECT_EQ(
|
||||
CalculateBase64EscapedLen(plain_length, false), encode_length);
|
||||
buffer[ encode_length ] = '\0';
|
||||
EXPECT_STREQ(base64_strings[i].cyphertext, &buffer[0]);
|
||||
}
|
||||
|
||||
// Verify the behavior when decoding bad data
|
||||
{
|
||||
const char* bad_data = "ab-/";
|
||||
std::string buf;
|
||||
EXPECT_FALSE(Base64Unescape(StringPiece(bad_data), &buf));
|
||||
EXPECT_TRUE(!WebSafeBase64Unescape(bad_data, &buf));
|
||||
EXPECT_TRUE(buf.empty());
|
||||
}
|
||||
}
|
||||
|
||||
// Test StrCat of ints and longs of various sizes and signdedness.
|
||||
TEST(StrCat, Ints) {
|
||||
const short s = -1; // NOLINT(runtime/int)
|
||||
const uint16_t us = 2;
|
||||
const int i = -3;
|
||||
const unsigned int ui = 4;
|
||||
const long l = -5; // NOLINT(runtime/int)
|
||||
const unsigned long ul = 6; // NOLINT(runtime/int)
|
||||
const long long ll = -7; // NOLINT(runtime/int)
|
||||
const unsigned long long ull = 8; // NOLINT(runtime/int)
|
||||
const ptrdiff_t ptrdiff = -9;
|
||||
const size_t size = 10;
|
||||
const intptr_t intptr = -12;
|
||||
const uintptr_t uintptr = 13;
|
||||
std::string answer;
|
||||
answer = StrCat(s, us);
|
||||
EXPECT_EQ(answer, "-12");
|
||||
answer = StrCat(i, ui);
|
||||
EXPECT_EQ(answer, "-34");
|
||||
answer = StrCat(l, ul);
|
||||
EXPECT_EQ(answer, "-56");
|
||||
answer = StrCat(ll, ull);
|
||||
EXPECT_EQ(answer, "-78");
|
||||
answer = StrCat(ptrdiff, size);
|
||||
EXPECT_EQ(answer, "-910");
|
||||
answer = StrCat(ptrdiff, intptr);
|
||||
EXPECT_EQ(answer, "-9-12");
|
||||
answer = StrCat(uintptr, 0);
|
||||
EXPECT_EQ(answer, "130");
|
||||
}
|
||||
|
||||
class ReplaceChars
|
||||
: public ::testing::TestWithParam<
|
||||
std::tuple<std::string, std::string, const char*, char>> {};
|
||||
|
||||
TEST_P(ReplaceChars, ReplacesAllOccurencesOfAnyCharInReplaceWithAReplaceChar) {
|
||||
std::string expected = std::get<0>(GetParam());
|
||||
std::string string_to_replace_in = std::get<1>(GetParam());
|
||||
const char* what_to_replace = std::get<2>(GetParam());
|
||||
char replacement = std::get<3>(GetParam());
|
||||
ReplaceCharacters(&string_to_replace_in, what_to_replace, replacement);
|
||||
ASSERT_EQ(expected, string_to_replace_in);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
Replace, ReplaceChars,
|
||||
::testing::Values(
|
||||
std::make_tuple("", "", "", '_'), // empty string should remain empty
|
||||
std::make_tuple(" ", " ", "", '_'), // no replacement string
|
||||
std::make_tuple(" ", " ", "_-abcedf",
|
||||
'*'), // replacement character not in string
|
||||
std::make_tuple("replace", "Replace", "R",
|
||||
'r'), // replace one character
|
||||
std::make_tuple("not_spaces__", "not\nspaces\t ", " \t\r\n",
|
||||
'_'), // replace some special characters
|
||||
std::make_tuple("c++", "cxx", "x",
|
||||
'+'), // same character multiple times
|
||||
std::make_tuple("qvvvvvng v T", "queueing a T", "aeiou",
|
||||
'v'))); // replace all voewls
|
||||
|
||||
class StripWs
|
||||
: public ::testing::TestWithParam<std::tuple<std::string, std::string>> {};
|
||||
|
||||
TEST_P(StripWs, AlwaysStripsLeadingAndTrailingWhitespace) {
|
||||
std::string expected = std::get<0>(GetParam());
|
||||
std::string string_to_strip = std::get<1>(GetParam());
|
||||
StripWhitespace(&string_to_strip);
|
||||
ASSERT_EQ(expected, string_to_strip);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
Strip, StripWs,
|
||||
::testing::Values(
|
||||
std::make_tuple("", ""), // empty string should remain empty
|
||||
std::make_tuple("", " "), // only ws should become empty
|
||||
std::make_tuple("no whitespace",
|
||||
" no whitespace"), // leading ws removed
|
||||
std::make_tuple("no whitespace",
|
||||
"no whitespace "), // trailing ws removed
|
||||
std::make_tuple("no whitespace",
|
||||
" no whitespace "), // same nb. of leading and trailing
|
||||
std::make_tuple(
|
||||
"no whitespace",
|
||||
" no whitespace "), // different nb. of leading/trailing
|
||||
std::make_tuple("no whitespace",
|
||||
" no whitespace "))); // more trailing than leading
|
||||
|
||||
} // anonymous namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
136
ubuntu/google/protobuf/stubs/substitute.cc
Normal file
136
ubuntu/google/protobuf/stubs/substitute.cc
Normal file
@@ -0,0 +1,136 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
|
||||
#include <google/protobuf/stubs/logging.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace strings {
|
||||
|
||||
using internal::SubstituteArg;
|
||||
|
||||
// Returns the number of args in arg_array which were passed explicitly
|
||||
// to Substitute().
|
||||
static int CountSubstituteArgs(const SubstituteArg* const* args_array) {
|
||||
int count = 0;
|
||||
while (args_array[count] != nullptr && args_array[count]->size() != -1) {
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
std::string Substitute(const char* format, const SubstituteArg& arg0,
|
||||
const SubstituteArg& arg1, const SubstituteArg& arg2,
|
||||
const SubstituteArg& arg3, const SubstituteArg& arg4,
|
||||
const SubstituteArg& arg5, const SubstituteArg& arg6,
|
||||
const SubstituteArg& arg7, const SubstituteArg& arg8,
|
||||
const SubstituteArg& arg9) {
|
||||
std::string result;
|
||||
SubstituteAndAppend(&result, format, arg0, arg1, arg2, arg3, arg4,
|
||||
arg5, arg6, arg7, arg8, arg9);
|
||||
return result;
|
||||
}
|
||||
|
||||
void SubstituteAndAppend(std::string* output, const char* format,
|
||||
const SubstituteArg& arg0, const SubstituteArg& arg1,
|
||||
const SubstituteArg& arg2, const SubstituteArg& arg3,
|
||||
const SubstituteArg& arg4, const SubstituteArg& arg5,
|
||||
const SubstituteArg& arg6, const SubstituteArg& arg7,
|
||||
const SubstituteArg& arg8, const SubstituteArg& arg9) {
|
||||
const SubstituteArg* const args_array[] = {
|
||||
&arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, nullptr
|
||||
};
|
||||
|
||||
// Determine total size needed.
|
||||
int size = 0;
|
||||
for (int i = 0; format[i] != '\0'; i++) {
|
||||
if (format[i] == '$') {
|
||||
if (ascii_isdigit(format[i+1])) {
|
||||
int index = format[i+1] - '0';
|
||||
if (args_array[index]->size() == -1) {
|
||||
GOOGLE_LOG(DFATAL)
|
||||
<< "strings::Substitute format string invalid: asked for \"$"
|
||||
<< index << "\", but only " << CountSubstituteArgs(args_array)
|
||||
<< " args were given. Full format string was: \""
|
||||
<< CEscape(format) << "\".";
|
||||
return;
|
||||
}
|
||||
size += args_array[index]->size();
|
||||
++i; // Skip next char.
|
||||
} else if (format[i+1] == '$') {
|
||||
++size;
|
||||
++i; // Skip next char.
|
||||
} else {
|
||||
GOOGLE_LOG(DFATAL)
|
||||
<< "Invalid strings::Substitute() format string: \""
|
||||
<< CEscape(format) << "\".";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
++size;
|
||||
}
|
||||
}
|
||||
|
||||
if (size == 0) return;
|
||||
|
||||
// Build the string.
|
||||
int original_size = output->size();
|
||||
STLStringResizeUninitialized(output, original_size + size);
|
||||
char* target = string_as_array(output) + original_size;
|
||||
for (int i = 0; format[i] != '\0'; i++) {
|
||||
if (format[i] == '$') {
|
||||
if (ascii_isdigit(format[i+1])) {
|
||||
unsigned int index = format[i+1] - '0';
|
||||
assert(index < 10);
|
||||
const SubstituteArg* src = args_array[index];
|
||||
memcpy(target, src->data(), src->size());
|
||||
target += src->size();
|
||||
++i; // Skip next char.
|
||||
} else if (format[i+1] == '$') {
|
||||
*target++ = '$';
|
||||
++i; // Skip next char.
|
||||
}
|
||||
} else {
|
||||
*target++ = format[i];
|
||||
}
|
||||
}
|
||||
|
||||
GOOGLE_DCHECK_EQ(target - output->data(), output->size());
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
174
ubuntu/google/protobuf/stubs/substitute.h
Normal file
174
ubuntu/google/protobuf/stubs/substitute.h
Normal file
@@ -0,0 +1,174 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// from google3/strings/substitute.h
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace strings {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// strings::Substitute()
|
||||
// strings::SubstituteAndAppend()
|
||||
// Kind of like StringPrintf, but different.
|
||||
//
|
||||
// Example:
|
||||
// string GetMessage(string first_name, string last_name, int age) {
|
||||
// return strings::Substitute("My name is $0 $1 and I am $2 years old.",
|
||||
// first_name, last_name, age);
|
||||
// }
|
||||
//
|
||||
// Differences from StringPrintf:
|
||||
// * The format string does not identify the types of arguments.
|
||||
// Instead, the magic of C++ deals with this for us. See below
|
||||
// for a list of accepted types.
|
||||
// * Substitutions in the format string are identified by a '$'
|
||||
// followed by a digit. So, you can use arguments out-of-order and
|
||||
// use the same argument multiple times.
|
||||
// * It's much faster than StringPrintf.
|
||||
//
|
||||
// Supported types:
|
||||
// * Strings (const char*, const string&)
|
||||
// * Note that this means you do not have to add .c_str() to all of
|
||||
// your strings. In fact, you shouldn't; it will be slower.
|
||||
// * int32, int64, uint32, uint64: Formatted using SimpleItoa().
|
||||
// * float, double: Formatted using SimpleFtoa() and SimpleDtoa().
|
||||
// * bool: Printed as "true" or "false".
|
||||
//
|
||||
// SubstituteAndAppend() is like Substitute() but appends the result to
|
||||
// *output. Example:
|
||||
//
|
||||
// string str;
|
||||
// strings::SubstituteAndAppend(&str,
|
||||
// "My name is $0 $1 and I am $2 years old.",
|
||||
// first_name, last_name, age);
|
||||
//
|
||||
// Substitute() is significantly faster than StringPrintf(). For very
|
||||
// large strings, it may be orders of magnitude faster.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
namespace internal { // Implementation details.
|
||||
|
||||
class SubstituteArg {
|
||||
public:
|
||||
inline SubstituteArg(const char* value)
|
||||
: text_(value), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(const std::string& value)
|
||||
: text_(value.data()), size_(value.size()) {}
|
||||
|
||||
// Indicates that no argument was given.
|
||||
inline explicit SubstituteArg()
|
||||
: text_(nullptr), size_(-1) {}
|
||||
|
||||
// Primitives
|
||||
// We don't overload for signed and unsigned char because if people are
|
||||
// explicitly declaring their chars as signed or unsigned then they are
|
||||
// probably actually using them as 8-bit integers and would probably
|
||||
// prefer an integer representation. But, we don't really know. So, we
|
||||
// make the caller decide what to do.
|
||||
inline SubstituteArg(char value)
|
||||
: text_(scratch_), size_(1) { scratch_[0] = value; }
|
||||
inline SubstituteArg(short value)
|
||||
: text_(FastInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(unsigned short value)
|
||||
: text_(FastUInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(int value)
|
||||
: text_(FastInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(unsigned int value)
|
||||
: text_(FastUInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(long value)
|
||||
: text_(FastLongToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(unsigned long value)
|
||||
: text_(FastULongToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(long long value)
|
||||
: text_(FastInt64ToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(unsigned long long value)
|
||||
: text_(FastUInt64ToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(float value)
|
||||
: text_(FloatToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(double value)
|
||||
: text_(DoubleToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(bool value)
|
||||
: text_(value ? "true" : "false"), size_(strlen(text_)) {}
|
||||
|
||||
inline const char* data() const { return text_; }
|
||||
inline int size() const { return size_; }
|
||||
|
||||
private:
|
||||
const char* text_;
|
||||
int size_;
|
||||
char scratch_[kFastToBufferSize];
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
PROTOBUF_EXPORT std::string Substitute(
|
||||
const char* format,
|
||||
const internal::SubstituteArg& arg0 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg1 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg2 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg3 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg4 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg5 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg6 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg7 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg8 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg9 = internal::SubstituteArg());
|
||||
|
||||
PROTOBUF_EXPORT void SubstituteAndAppend(
|
||||
std::string* output, const char* format,
|
||||
const internal::SubstituteArg& arg0 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg1 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg2 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg3 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg4 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg5 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg6 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg7 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg8 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg9 = internal::SubstituteArg());
|
||||
|
||||
} // namespace strings
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
|
||||
138
ubuntu/google/protobuf/stubs/template_util.h
Normal file
138
ubuntu/google/protobuf/stubs/template_util.h
Normal file
@@ -0,0 +1,138 @@
|
||||
// Copyright 2005 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ----
|
||||
// Author: lar@google.com (Laramie Leavitt)
|
||||
//
|
||||
// Template metaprogramming utility functions.
|
||||
//
|
||||
// This code is compiled directly on many platforms, including client
|
||||
// platforms like Windows, Mac, and embedded systems. Before making
|
||||
// any changes here, make sure that you're not breaking any platforms.
|
||||
//
|
||||
//
|
||||
// The names chosen here reflect those used in tr1 and the boost::mpl
|
||||
// library, there are similar operations used in the Loki library as
|
||||
// well. I prefer the boost names for 2 reasons:
|
||||
// 1. I think that portions of the Boost libraries are more likely to
|
||||
// be included in the c++ standard.
|
||||
// 2. It is not impossible that some of the boost libraries will be
|
||||
// included in our own build in the future.
|
||||
// Both of these outcomes means that we may be able to directly replace
|
||||
// some of these with boost equivalents.
|
||||
//
|
||||
#ifndef GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
|
||||
#define GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Types small_ and big_ are guaranteed such that sizeof(small_) <
|
||||
// sizeof(big_)
|
||||
typedef char small_;
|
||||
|
||||
struct big_ {
|
||||
char dummy[2];
|
||||
};
|
||||
|
||||
// Identity metafunction.
|
||||
template <class T>
|
||||
struct identity_ {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
// integral_constant, defined in tr1, is a wrapper for an integer
|
||||
// value. We don't really need this generality; we could get away
|
||||
// with hardcoding the integer type to bool. We use the fully
|
||||
// general integer_constant for compatibility with tr1.
|
||||
|
||||
template<class T, T v>
|
||||
struct integral_constant {
|
||||
static const T value = v;
|
||||
typedef T value_type;
|
||||
typedef integral_constant<T, v> type;
|
||||
};
|
||||
|
||||
template <class T, T v> const T integral_constant<T, v>::value;
|
||||
|
||||
|
||||
// Abbreviations: true_type and false_type are structs that represent boolean
|
||||
// true and false values. Also define the boost::mpl versions of those names,
|
||||
// true_ and false_.
|
||||
typedef integral_constant<bool, true> true_type;
|
||||
typedef integral_constant<bool, false> false_type;
|
||||
typedef true_type true_;
|
||||
typedef false_type false_;
|
||||
|
||||
// if_ is a templatized conditional statement.
|
||||
// if_<cond, A, B> is a compile time evaluation of cond.
|
||||
// if_<>::type contains A if cond is true, B otherwise.
|
||||
template<bool cond, typename A, typename B>
|
||||
struct if_{
|
||||
typedef A type;
|
||||
};
|
||||
|
||||
template<typename A, typename B>
|
||||
struct if_<false, A, B> {
|
||||
typedef B type;
|
||||
};
|
||||
|
||||
|
||||
// type_equals_ is a template type comparator, similar to Loki IsSameType.
|
||||
// type_equals_<A, B>::value is true iff "A" is the same type as "B".
|
||||
//
|
||||
// New code should prefer base::is_same, defined in base/type_traits.h.
|
||||
// It is functionally identical, but is_same is the standard spelling.
|
||||
template<typename A, typename B>
|
||||
struct type_equals_ : public false_ {
|
||||
};
|
||||
|
||||
template<typename A>
|
||||
struct type_equals_<A, A> : public true_ {
|
||||
};
|
||||
|
||||
// and_ is a template && operator.
|
||||
// and_<A, B>::value evaluates "A::value && B::value".
|
||||
template<typename A, typename B>
|
||||
struct and_ : public integral_constant<bool, (A::value && B::value)> {
|
||||
};
|
||||
|
||||
// or_ is a template || operator.
|
||||
// or_<A, B>::value evaluates "A::value || B::value".
|
||||
template<typename A, typename B>
|
||||
struct or_ : public integral_constant<bool, (A::value || B::value)> {
|
||||
};
|
||||
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_
|
||||
130
ubuntu/google/protobuf/stubs/template_util_unittest.cc
Normal file
130
ubuntu/google/protobuf/stubs/template_util_unittest.cc
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright 2005 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ----
|
||||
// Author: lar@google.com (Laramie Leavitt)
|
||||
//
|
||||
// These tests are really compile time tests.
|
||||
// If you try to step through this in a debugger
|
||||
// you will not see any evaluations, merely that
|
||||
// value is assigned true or false sequentially.
|
||||
|
||||
#include <google/protobuf/stubs/template_util.h>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace GOOGLE_NAMESPACE = google::protobuf::internal;
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
TEST(TemplateUtilTest, TestSize) {
|
||||
EXPECT_GT(sizeof(GOOGLE_NAMESPACE::big_), sizeof(GOOGLE_NAMESPACE::small_));
|
||||
}
|
||||
|
||||
TEST(TemplateUtilTest, TestIntegralConstants) {
|
||||
// test the built-in types.
|
||||
EXPECT_TRUE(true_type::value);
|
||||
EXPECT_FALSE(false_type::value);
|
||||
|
||||
typedef integral_constant<int, 1> one_type;
|
||||
EXPECT_EQ(1, one_type::value);
|
||||
}
|
||||
|
||||
TEST(TemplateUtilTest, TestTemplateIf) {
|
||||
typedef if_<true, true_type, false_type>::type if_true;
|
||||
EXPECT_TRUE(if_true::value);
|
||||
|
||||
typedef if_<false, true_type, false_type>::type if_false;
|
||||
EXPECT_FALSE(if_false::value);
|
||||
}
|
||||
|
||||
TEST(TemplateUtilTest, TestTemplateTypeEquals) {
|
||||
// Check that the TemplateTypeEquals works correctly.
|
||||
bool value = false;
|
||||
|
||||
// Test the same type is true.
|
||||
value = type_equals_<int, int>::value;
|
||||
EXPECT_TRUE(value);
|
||||
|
||||
// Test different types are false.
|
||||
value = type_equals_<float, int>::value;
|
||||
EXPECT_FALSE(value);
|
||||
|
||||
// Test type aliasing.
|
||||
typedef const int foo;
|
||||
value = type_equals_<const foo, const int>::value;
|
||||
EXPECT_TRUE(value);
|
||||
}
|
||||
|
||||
TEST(TemplateUtilTest, TestTemplateAndOr) {
|
||||
// Check that the TemplateTypeEquals works correctly.
|
||||
bool value = false;
|
||||
|
||||
// Yes && Yes == true.
|
||||
value = and_<true_, true_>::value;
|
||||
EXPECT_TRUE(value);
|
||||
// Yes && No == false.
|
||||
value = and_<true_, false_>::value;
|
||||
EXPECT_FALSE(value);
|
||||
// No && Yes == false.
|
||||
value = and_<false_, true_>::value;
|
||||
EXPECT_FALSE(value);
|
||||
// No && No == false.
|
||||
value = and_<false_, false_>::value;
|
||||
EXPECT_FALSE(value);
|
||||
|
||||
// Yes || Yes == true.
|
||||
value = or_<true_, true_>::value;
|
||||
EXPECT_TRUE(value);
|
||||
// Yes || No == true.
|
||||
value = or_<true_, false_>::value;
|
||||
EXPECT_TRUE(value);
|
||||
// No || Yes == true.
|
||||
value = or_<false_, true_>::value;
|
||||
EXPECT_TRUE(value);
|
||||
// No || No == false.
|
||||
value = or_<false_, false_>::value;
|
||||
EXPECT_FALSE(value);
|
||||
}
|
||||
|
||||
TEST(TemplateUtilTest, TestIdentity) {
|
||||
EXPECT_TRUE(
|
||||
(type_equals_<GOOGLE_NAMESPACE::identity_<int>::type, int>::value));
|
||||
EXPECT_TRUE(
|
||||
(type_equals_<GOOGLE_NAMESPACE::identity_<void>::type, void>::value));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
365
ubuntu/google/protobuf/stubs/time.cc
Normal file
365
ubuntu/google/protobuf/stubs/time.cc
Normal file
@@ -0,0 +1,365 @@
|
||||
#include <google/protobuf/stubs/time.h>
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include <google/protobuf/stubs/stringprintf.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
static const int64 kSecondsPerMinute = 60;
|
||||
static const int64 kSecondsPerHour = 3600;
|
||||
static const int64 kSecondsPerDay = kSecondsPerHour * 24;
|
||||
static const int64 kSecondsPer400Years =
|
||||
kSecondsPerDay * (400 * 365 + 400 / 4 - 3);
|
||||
// Seconds from 0001-01-01T00:00:00 to 1970-01-01T:00:00:00
|
||||
static const int64 kSecondsFromEraToEpoch = 62135596800LL;
|
||||
// The range of timestamp values we support.
|
||||
static const int64 kMinTime = -62135596800LL; // 0001-01-01T00:00:00
|
||||
static const int64 kMaxTime = 253402300799LL; // 9999-12-31T23:59:59
|
||||
|
||||
static const int kNanosPerMillisecond = 1000000;
|
||||
static const int kNanosPerMicrosecond = 1000;
|
||||
|
||||
// Count the seconds from the given year (start at Jan 1, 00:00) to 100 years
|
||||
// after.
|
||||
int64 SecondsPer100Years(int year) {
|
||||
if (year % 400 == 0 || year % 400 > 300) {
|
||||
return kSecondsPerDay * (100 * 365 + 100 / 4);
|
||||
} else {
|
||||
return kSecondsPerDay * (100 * 365 + 100 / 4 - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Count the seconds from the given year (start at Jan 1, 00:00) to 4 years
|
||||
// after.
|
||||
int64 SecondsPer4Years(int year) {
|
||||
if ((year % 100 == 0 || year % 100 > 96) &&
|
||||
!(year % 400 == 0 || year % 400 > 396)) {
|
||||
// No leap years.
|
||||
return kSecondsPerDay * (4 * 365);
|
||||
} else {
|
||||
// One leap years.
|
||||
return kSecondsPerDay * (4 * 365 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsLeapYear(int year) {
|
||||
return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
|
||||
}
|
||||
|
||||
int64 SecondsPerYear(int year) {
|
||||
return kSecondsPerDay * (IsLeapYear(year) ? 366 : 365);
|
||||
}
|
||||
|
||||
static const int kDaysInMonth[13] = {
|
||||
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
int64 SecondsPerMonth(int month, bool leap) {
|
||||
if (month == 2 && leap) {
|
||||
return kSecondsPerDay * (kDaysInMonth[month] + 1);
|
||||
}
|
||||
return kSecondsPerDay * kDaysInMonth[month];
|
||||
}
|
||||
|
||||
static const int kDaysSinceJan[13] = {
|
||||
0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
|
||||
};
|
||||
|
||||
bool ValidateDateTime(const DateTime& time) {
|
||||
if (time.year < 1 || time.year > 9999 ||
|
||||
time.month < 1 || time.month > 12 ||
|
||||
time.day < 1 || time.day > 31 ||
|
||||
time.hour < 0 || time.hour > 23 ||
|
||||
time.minute < 0 || time.minute > 59 ||
|
||||
time.second < 0 || time.second > 59) {
|
||||
return false;
|
||||
}
|
||||
if (time.month == 2 && IsLeapYear(time.year)) {
|
||||
return time.day <= kDaysInMonth[time.month] + 1;
|
||||
} else {
|
||||
return time.day <= kDaysInMonth[time.month];
|
||||
}
|
||||
}
|
||||
|
||||
// Count the number of seconds elapsed from 0001-01-01T00:00:00 to the given
|
||||
// time.
|
||||
int64 SecondsSinceCommonEra(const DateTime& time) {
|
||||
int64 result = 0;
|
||||
// Years should be between 1 and 9999.
|
||||
assert(time.year >= 1 && time.year <= 9999);
|
||||
int year = 1;
|
||||
if ((time.year - year) >= 400) {
|
||||
int count_400years = (time.year - year) / 400;
|
||||
result += kSecondsPer400Years * count_400years;
|
||||
year += count_400years * 400;
|
||||
}
|
||||
while ((time.year - year) >= 100) {
|
||||
result += SecondsPer100Years(year);
|
||||
year += 100;
|
||||
}
|
||||
while ((time.year - year) >= 4) {
|
||||
result += SecondsPer4Years(year);
|
||||
year += 4;
|
||||
}
|
||||
while (time.year > year) {
|
||||
result += SecondsPerYear(year);
|
||||
++year;
|
||||
}
|
||||
// Months should be between 1 and 12.
|
||||
assert(time.month >= 1 && time.month <= 12);
|
||||
int month = time.month;
|
||||
result += kSecondsPerDay * kDaysSinceJan[month];
|
||||
if (month > 2 && IsLeapYear(year)) {
|
||||
result += kSecondsPerDay;
|
||||
}
|
||||
assert(time.day >= 1 &&
|
||||
time.day <= (month == 2 && IsLeapYear(year)
|
||||
? kDaysInMonth[month] + 1
|
||||
: kDaysInMonth[month]));
|
||||
result += kSecondsPerDay * (time.day - 1);
|
||||
result += kSecondsPerHour * time.hour +
|
||||
kSecondsPerMinute * time.minute +
|
||||
time.second;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Format nanoseconds with either 3, 6, or 9 digits depending on the required
|
||||
// precision to represent the exact value.
|
||||
std::string FormatNanos(int32 nanos) {
|
||||
if (nanos % kNanosPerMillisecond == 0) {
|
||||
return StringPrintf("%03d", nanos / kNanosPerMillisecond);
|
||||
} else if (nanos % kNanosPerMicrosecond == 0) {
|
||||
return StringPrintf("%06d", nanos / kNanosPerMicrosecond);
|
||||
} else {
|
||||
return StringPrintf("%09d", nanos);
|
||||
}
|
||||
}
|
||||
|
||||
// Parses an integer from a null-terminated char sequence. The method
|
||||
// consumes at most "width" chars. Returns a pointer after the consumed
|
||||
// integer, or nullptr if the data does not start with an integer or the
|
||||
// integer value does not fall in the range of [min_value, max_value].
|
||||
const char* ParseInt(const char* data, int width, int min_value,
|
||||
int max_value, int* result) {
|
||||
if (!ascii_isdigit(*data)) {
|
||||
return nullptr;
|
||||
}
|
||||
int value = 0;
|
||||
for (int i = 0; i < width; ++i, ++data) {
|
||||
if (ascii_isdigit(*data)) {
|
||||
value = value * 10 + (*data - '0');
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (value >= min_value && value <= max_value) {
|
||||
*result = value;
|
||||
return data;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Consumes the fractional parts of a second into nanos. For example,
|
||||
// "010" will be parsed to 10000000 nanos.
|
||||
const char* ParseNanos(const char* data, int32* nanos) {
|
||||
if (!ascii_isdigit(*data)) {
|
||||
return nullptr;
|
||||
}
|
||||
int value = 0;
|
||||
int len = 0;
|
||||
// Consume as many digits as there are but only take the first 9 into
|
||||
// account.
|
||||
while (ascii_isdigit(*data)) {
|
||||
if (len < 9) {
|
||||
value = value * 10 + *data - '0';
|
||||
}
|
||||
++len;
|
||||
++data;
|
||||
}
|
||||
while (len < 9) {
|
||||
value = value * 10;
|
||||
++len;
|
||||
}
|
||||
*nanos = value;
|
||||
return data;
|
||||
}
|
||||
|
||||
const char* ParseTimezoneOffset(const char* data, int64* offset) {
|
||||
// Accept format "HH:MM". E.g., "08:00"
|
||||
int hour;
|
||||
if ((data = ParseInt(data, 2, 0, 23, &hour)) == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (*data++ != ':') {
|
||||
return nullptr;
|
||||
}
|
||||
int minute;
|
||||
if ((data = ParseInt(data, 2, 0, 59, &minute)) == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
*offset = (hour * 60 + minute) * 60;
|
||||
return data;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool SecondsToDateTime(int64 seconds, DateTime* time) {
|
||||
if (seconds < kMinTime || seconds > kMaxTime) {
|
||||
return false;
|
||||
}
|
||||
// It's easier to calculate the DateTime starting from 0001-01-01T00:00:00
|
||||
seconds = seconds + kSecondsFromEraToEpoch;
|
||||
int year = 1;
|
||||
if (seconds >= kSecondsPer400Years) {
|
||||
int count_400years = seconds / kSecondsPer400Years;
|
||||
year += 400 * count_400years;
|
||||
seconds %= kSecondsPer400Years;
|
||||
}
|
||||
while (seconds >= SecondsPer100Years(year)) {
|
||||
seconds -= SecondsPer100Years(year);
|
||||
year += 100;
|
||||
}
|
||||
while (seconds >= SecondsPer4Years(year)) {
|
||||
seconds -= SecondsPer4Years(year);
|
||||
year += 4;
|
||||
}
|
||||
while (seconds >= SecondsPerYear(year)) {
|
||||
seconds -= SecondsPerYear(year);
|
||||
year += 1;
|
||||
}
|
||||
bool leap = IsLeapYear(year);
|
||||
int month = 1;
|
||||
while (seconds >= SecondsPerMonth(month, leap)) {
|
||||
seconds -= SecondsPerMonth(month, leap);
|
||||
++month;
|
||||
}
|
||||
int day = 1 + seconds / kSecondsPerDay;
|
||||
seconds %= kSecondsPerDay;
|
||||
int hour = seconds / kSecondsPerHour;
|
||||
seconds %= kSecondsPerHour;
|
||||
int minute = seconds / kSecondsPerMinute;
|
||||
seconds %= kSecondsPerMinute;
|
||||
time->year = year;
|
||||
time->month = month;
|
||||
time->day = day;
|
||||
time->hour = hour;
|
||||
time->minute = minute;
|
||||
time->second = static_cast<int>(seconds);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DateTimeToSeconds(const DateTime& time, int64* seconds) {
|
||||
if (!ValidateDateTime(time)) {
|
||||
return false;
|
||||
}
|
||||
*seconds = SecondsSinceCommonEra(time) - kSecondsFromEraToEpoch;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GetCurrentTime(int64* seconds, int32* nanos) {
|
||||
// TODO(xiaofeng): Improve the accuracy of this implementation (or just
|
||||
// remove this method from protobuf).
|
||||
*seconds = time(nullptr);
|
||||
*nanos = 0;
|
||||
}
|
||||
|
||||
std::string FormatTime(int64 seconds, int32 nanos) {
|
||||
DateTime time;
|
||||
if (nanos < 0 || nanos > 999999999 || !SecondsToDateTime(seconds, &time)) {
|
||||
return "InvalidTime";
|
||||
}
|
||||
std::string result =
|
||||
StringPrintf("%04d-%02d-%02dT%02d:%02d:%02d", time.year, time.month,
|
||||
time.day, time.hour, time.minute, time.second);
|
||||
if (nanos != 0) {
|
||||
result += "." + FormatNanos(nanos);
|
||||
}
|
||||
return result + "Z";
|
||||
}
|
||||
|
||||
bool ParseTime(const std::string& value, int64* seconds, int32* nanos) {
|
||||
DateTime time;
|
||||
const char* data = value.c_str();
|
||||
// We only accept:
|
||||
// Z-normalized: 2015-05-20T13:29:35.120Z
|
||||
// With UTC offset: 2015-05-20T13:29:35.120-08:00
|
||||
|
||||
// Parse year
|
||||
if ((data = ParseInt(data, 4, 1, 9999, &time.year)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
// Expect '-'
|
||||
if (*data++ != '-') return false;
|
||||
// Parse month
|
||||
if ((data = ParseInt(data, 2, 1, 12, &time.month)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
// Expect '-'
|
||||
if (*data++ != '-') return false;
|
||||
// Parse day
|
||||
if ((data = ParseInt(data, 2, 1, 31, &time.day)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
// Expect 'T'
|
||||
if (*data++ != 'T') return false;
|
||||
// Parse hour
|
||||
if ((data = ParseInt(data, 2, 0, 23, &time.hour)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
// Expect ':'
|
||||
if (*data++ != ':') return false;
|
||||
// Parse minute
|
||||
if ((data = ParseInt(data, 2, 0, 59, &time.minute)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
// Expect ':'
|
||||
if (*data++ != ':') return false;
|
||||
// Parse second
|
||||
if ((data = ParseInt(data, 2, 0, 59, &time.second)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (!DateTimeToSeconds(time, seconds)) {
|
||||
return false;
|
||||
}
|
||||
// Parse nanoseconds.
|
||||
if (*data == '.') {
|
||||
++data;
|
||||
// Parse nanoseconds.
|
||||
if ((data = ParseNanos(data, nanos)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
*nanos = 0;
|
||||
}
|
||||
// Parse UTC offsets.
|
||||
if (*data == 'Z') {
|
||||
++data;
|
||||
} else if (*data == '+') {
|
||||
++data;
|
||||
int64 offset;
|
||||
if ((data = ParseTimezoneOffset(data, &offset)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
*seconds -= offset;
|
||||
} else if (*data == '-') {
|
||||
++data;
|
||||
int64 offset;
|
||||
if ((data = ParseTimezoneOffset(data, &offset)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
*seconds += offset;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// Done with parsing.
|
||||
return *data == 0;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
80
ubuntu/google/protobuf/stubs/time.h
Normal file
80
ubuntu/google/protobuf/stubs/time.h
Normal file
@@ -0,0 +1,80 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_TIME_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_TIME_H_
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <google/protobuf/port_def.inc>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
struct DateTime {
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
int hour;
|
||||
int minute;
|
||||
int second;
|
||||
};
|
||||
|
||||
// Converts a timestamp (seconds elapsed since 1970-01-01T00:00:00, could be
|
||||
// negative to represent time before 1970-01-01) to DateTime. Returns false
|
||||
// if the timestamp is not in the range between 0001-01-01T00:00:00 and
|
||||
// 9999-12-31T23:59:59.
|
||||
bool PROTOBUF_EXPORT SecondsToDateTime(int64 seconds, DateTime* time);
|
||||
// Converts DateTime to a timestamp (seconds since 1970-01-01T00:00:00).
|
||||
// Returns false if the DateTime is not valid or is not in the valid range.
|
||||
bool PROTOBUF_EXPORT DateTimeToSeconds(const DateTime& time, int64* seconds);
|
||||
|
||||
void PROTOBUF_EXPORT GetCurrentTime(int64* seconds, int32* nanos);
|
||||
|
||||
// Formats a time string in RFC3339 format.
|
||||
//
|
||||
// For example, "2015-05-20T13:29:35.120Z". For nanos, 0, 3, 6 or 9 fractional
|
||||
// digits will be used depending on how many are required to represent the exact
|
||||
// value.
|
||||
//
|
||||
// Note that "nanos" must in the range of [0, 999999999].
|
||||
std::string PROTOBUF_EXPORT FormatTime(int64 seconds, int32 nanos);
|
||||
// Parses a time string. This method accepts RFC3339 date/time string with UTC
|
||||
// offset. For example, "2015-05-20T13:29:35.120-08:00".
|
||||
bool PROTOBUF_EXPORT ParseTime(const std::string& value, int64* seconds,
|
||||
int32* nanos);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include <google/protobuf/port_undef.inc>
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_TIME_H_
|
||||
261
ubuntu/google/protobuf/stubs/time_test.cc
Normal file
261
ubuntu/google/protobuf/stubs/time_test.cc
Normal file
@@ -0,0 +1,261 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <google/protobuf/stubs/time.h>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
namespace {
|
||||
static const int64 kSecondsPerDay = 3600 * 24;
|
||||
|
||||
// For DateTime, tests will mostly focus on the date part because that's
|
||||
// the tricky one.
|
||||
int64 CreateTimestamp(int year, int month, int day) {
|
||||
DateTime time;
|
||||
time.year = year;
|
||||
time.month = month;
|
||||
time.day = day;
|
||||
time.hour = time.minute = time.second = 0;
|
||||
int64 result;
|
||||
GOOGLE_CHECK(DateTimeToSeconds(time, &result));
|
||||
// Check that a roundtrip produces the same result.
|
||||
GOOGLE_CHECK(SecondsToDateTime(result, &time));
|
||||
GOOGLE_CHECK(time.year == year);
|
||||
GOOGLE_CHECK(time.month == month);
|
||||
GOOGLE_CHECK(time.day == day);
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST(DateTimeTest, SimpleTime) {
|
||||
DateTime time;
|
||||
ASSERT_TRUE(SecondsToDateTime(1, &time));
|
||||
EXPECT_EQ(1970, time.year);
|
||||
EXPECT_EQ(1, time.month);
|
||||
EXPECT_EQ(1, time.day);
|
||||
EXPECT_EQ(0, time.hour);
|
||||
EXPECT_EQ(0, time.minute);
|
||||
EXPECT_EQ(1, time.second);
|
||||
int64 seconds;
|
||||
ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
|
||||
EXPECT_EQ(1, seconds);
|
||||
|
||||
ASSERT_TRUE(SecondsToDateTime(-1, &time));
|
||||
EXPECT_EQ(1969, time.year);
|
||||
EXPECT_EQ(12, time.month);
|
||||
EXPECT_EQ(31, time.day);
|
||||
EXPECT_EQ(23, time.hour);
|
||||
EXPECT_EQ(59, time.minute);
|
||||
EXPECT_EQ(59, time.second);
|
||||
ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
|
||||
EXPECT_EQ(-1, seconds);
|
||||
|
||||
DateTime start, end;
|
||||
start.year = 1;
|
||||
start.month = 1;
|
||||
start.day = 1;
|
||||
start.hour = 0;
|
||||
start.minute = 0;
|
||||
start.second = 0;
|
||||
end.year = 9999;
|
||||
end.month = 12;
|
||||
end.day = 31;
|
||||
end.hour = 23;
|
||||
end.minute = 59;
|
||||
end.second = 59;
|
||||
int64 start_time, end_time;
|
||||
ASSERT_TRUE(DateTimeToSeconds(start, &start_time));
|
||||
ASSERT_TRUE(DateTimeToSeconds(end, &end_time));
|
||||
EXPECT_EQ(315537897599LL, end_time - start_time);
|
||||
ASSERT_TRUE(SecondsToDateTime(start_time, &time));
|
||||
ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
|
||||
EXPECT_EQ(start_time, seconds);
|
||||
ASSERT_TRUE(SecondsToDateTime(end_time, &time));
|
||||
ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
|
||||
EXPECT_EQ(end_time, seconds);
|
||||
}
|
||||
|
||||
TEST(DateTimeTest, DayInMonths) {
|
||||
// Check that month boundaries are handled correctly.
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 1, 1) - CreateTimestamp(2014, 12, 31));
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 2, 1) - CreateTimestamp(2015, 1, 31));
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 3, 1) - CreateTimestamp(2015, 2, 28));
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 4, 1) - CreateTimestamp(2015, 3, 31));
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 5, 1) - CreateTimestamp(2015, 4, 30));
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 6, 1) - CreateTimestamp(2015, 5, 31));
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 7, 1) - CreateTimestamp(2015, 6, 30));
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 8, 1) - CreateTimestamp(2015, 7, 31));
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 9, 1) - CreateTimestamp(2015, 8, 31));
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 10, 1) - CreateTimestamp(2015, 9, 30));
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 11, 1) - CreateTimestamp(2015, 10, 31));
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 12, 1) - CreateTimestamp(2015, 11, 30));
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2016, 1, 1) - CreateTimestamp(2015, 12, 31));
|
||||
}
|
||||
|
||||
TEST(DateTimeTest, LeapYear) {
|
||||
// Non-leap year.
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2015, 3, 1) - CreateTimestamp(2015, 2, 28));
|
||||
// Leap year.
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2016, 3, 1) - CreateTimestamp(2016, 2, 29));
|
||||
// Non-leap year.
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2100, 3, 1) - CreateTimestamp(2100, 2, 28));
|
||||
// Leap year.
|
||||
EXPECT_EQ(kSecondsPerDay,
|
||||
CreateTimestamp(2400, 3, 1) - CreateTimestamp(2400, 2, 29));
|
||||
}
|
||||
|
||||
TEST(DateTimeTest, WrongDays) {
|
||||
int64 seconds;
|
||||
DateTime time;
|
||||
time.hour = 0;
|
||||
time.minute = 0;
|
||||
time.second = 0;
|
||||
time.month = 2;
|
||||
|
||||
// Non-leap year.
|
||||
time.year = 2015;
|
||||
time.day = 29;
|
||||
ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
|
||||
|
||||
// Leap year.
|
||||
time.year = 2016;
|
||||
time.day = 29;
|
||||
ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
|
||||
time.day = 30;
|
||||
ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
|
||||
|
||||
// Non-leap year.
|
||||
time.year = 2100;
|
||||
time.day = 29;
|
||||
ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
|
||||
|
||||
// Leap year.
|
||||
time.year = 2400;
|
||||
time.day = 29;
|
||||
ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
|
||||
time.day = 30;
|
||||
ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
|
||||
|
||||
// Non-february
|
||||
time.year = 2015;
|
||||
time.month = 1;
|
||||
time.day = 0;
|
||||
ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
|
||||
time.day = 1;
|
||||
ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
|
||||
time.day = 31;
|
||||
ASSERT_TRUE(DateTimeToSeconds(time, &seconds));
|
||||
time.day = 32;
|
||||
ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
|
||||
|
||||
// Bad month
|
||||
time.year = 2015;
|
||||
time.month = 0;
|
||||
time.day = 1;
|
||||
ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
|
||||
time.month = 13;
|
||||
ASSERT_FALSE(DateTimeToSeconds(time, &seconds));
|
||||
}
|
||||
|
||||
TEST(DateTimeTest, StringFormat) {
|
||||
DateTime start, end;
|
||||
start.year = 1;
|
||||
start.month = 1;
|
||||
start.day = 1;
|
||||
start.hour = 0;
|
||||
start.minute = 0;
|
||||
start.second = 0;
|
||||
end.year = 9999;
|
||||
end.month = 12;
|
||||
end.day = 31;
|
||||
end.hour = 23;
|
||||
end.minute = 59;
|
||||
end.second = 59;
|
||||
int64 start_time, end_time;
|
||||
ASSERT_TRUE(DateTimeToSeconds(start, &start_time));
|
||||
ASSERT_TRUE(DateTimeToSeconds(end, &end_time));
|
||||
|
||||
EXPECT_EQ("0001-01-01T00:00:00Z", FormatTime(start_time, 0));
|
||||
EXPECT_EQ("9999-12-31T23:59:59Z", FormatTime(end_time, 0));
|
||||
|
||||
// Make sure the nanoseconds part is formatted correctly.
|
||||
EXPECT_EQ("1970-01-01T00:00:00.010Z", FormatTime(0, 10000000));
|
||||
EXPECT_EQ("1970-01-01T00:00:00.000010Z", FormatTime(0, 10000));
|
||||
EXPECT_EQ("1970-01-01T00:00:00.000000010Z", FormatTime(0, 10));
|
||||
}
|
||||
|
||||
TEST(DateTimeTest, ParseString) {
|
||||
int64 seconds;
|
||||
int32 nanos;
|
||||
ASSERT_TRUE(ParseTime("0001-01-01T00:00:00Z", &seconds, &nanos));
|
||||
EXPECT_EQ("0001-01-01T00:00:00Z", FormatTime(seconds, nanos));
|
||||
ASSERT_TRUE(ParseTime("9999-12-31T23:59:59.999999999Z", &seconds, &nanos));
|
||||
EXPECT_EQ("9999-12-31T23:59:59.999999999Z", FormatTime(seconds, nanos));
|
||||
|
||||
// Test time zone offsets.
|
||||
ASSERT_TRUE(ParseTime("1970-01-01T00:00:00-08:00", &seconds, &nanos));
|
||||
EXPECT_EQ("1970-01-01T08:00:00Z", FormatTime(seconds, nanos));
|
||||
ASSERT_TRUE(ParseTime("1970-01-01T00:00:00+08:00", &seconds, &nanos));
|
||||
EXPECT_EQ("1969-12-31T16:00:00Z", FormatTime(seconds, nanos));
|
||||
|
||||
// Test nanoseconds.
|
||||
ASSERT_TRUE(ParseTime("1970-01-01T00:00:00.01Z", &seconds, &nanos));
|
||||
EXPECT_EQ("1970-01-01T00:00:00.010Z", FormatTime(seconds, nanos));
|
||||
ASSERT_TRUE(ParseTime("1970-01-01T00:00:00.00001-08:00", &seconds, &nanos));
|
||||
EXPECT_EQ("1970-01-01T08:00:00.000010Z", FormatTime(seconds, nanos));
|
||||
ASSERT_TRUE(ParseTime("1970-01-01T00:00:00.00000001+08:00", &seconds, &nanos));
|
||||
EXPECT_EQ("1969-12-31T16:00:00.000000010Z", FormatTime(seconds, nanos));
|
||||
// Fractional parts less than 1 nanosecond will be ignored.
|
||||
ASSERT_TRUE(ParseTime("1970-01-01T00:00:00.0123456789Z", &seconds, &nanos));
|
||||
EXPECT_EQ("1970-01-01T00:00:00.012345678Z", FormatTime(seconds, nanos));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
Reference in New Issue
Block a user