Commit 798e9a11 authored by gejun's avatar gejun

Move BinaryPrinter into separate files and make it more generic

parent ee8587ee
......@@ -216,6 +216,7 @@ BUTIL_SRCS = [
"src/butil/crc32c.cc",
"src/butil/containers/case_ignored_flat_map.cpp",
"src/butil/iobuf.cpp",
"src/butil/binary_printer.cpp",
"src/butil/popen.cpp",
] + select({
":darwin": [
......
......@@ -305,6 +305,7 @@ set(BUTIL_SOURCES
${PROJECT_SOURCE_DIR}/src/butil/crc32c.cc
${PROJECT_SOURCE_DIR}/src/butil/containers/case_ignored_flat_map.cpp
${PROJECT_SOURCE_DIR}/src/butil/iobuf.cpp
${PROJECT_SOURCE_DIR}/src/butil/binary_printer.cpp
${PROJECT_SOURCE_DIR}/src/butil/popen.cpp
)
......
......@@ -145,6 +145,7 @@ BUTIL_SOURCES = \
src/butil/crc32c.cc \
src/butil/containers/case_ignored_flat_map.cpp \
src/butil/iobuf.cpp \
src/butil/binary_printer.cpp \
src/butil/popen.cpp
ifeq ($(SYSTEM), Linux)
......
// Copyright (c) 2012 Baidu, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Author: Ge,Jun (gejun@baidu.com)
// Date: Thu Nov 22 13:57:56 CST 2012
#include <inttypes.h>
#include "butil/iobuf.h"
#include "butil/binary_printer.h"
namespace butil {
static char s_binary_char_map[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'
};
template <typename Appender>
class BinaryCharPrinter {
public:
static const size_t BUF_SIZE = 127;
explicit BinaryCharPrinter(Appender* a) : _n(0), _appender(a) {}
~BinaryCharPrinter() { Flush(); }
void PushChar(unsigned char c);
void Flush();
private:
uint32_t _n;
Appender* _appender;
char _buf[BUF_SIZE];
};
template <typename Appender>
void BinaryCharPrinter<Appender>::Flush() {
if (_n > 0) {
_appender->Append(_buf, _n);
_n = 0;
}
}
template <typename Appender>
void BinaryCharPrinter<Appender>::PushChar(unsigned char c) {
if (_n > BUF_SIZE - 3) {
_appender->Append(_buf, _n);
_n = 0;
}
if (c >= 32 && c <= 126) { // displayable ascii characters
if (c != '\\') {
_buf[_n++] = c;
} else {
_buf[_n++] = '\\';
_buf[_n++] = '\\';
}
} else {
_buf[_n++] = '\\';
switch (c) {
case '\b': _buf[_n++] = 'b'; break;
case '\t': _buf[_n++] = 't'; break;
case '\n': _buf[_n++] = 'n'; break;
case '\r': _buf[_n++] = 'r'; break;
default:
_buf[_n++] = s_binary_char_map[c >> 4];
_buf[_n++] = s_binary_char_map[c & 0xF];
break;
}
}
}
class OStreamAppender {
public:
OStreamAppender(std::ostream& os) : _os(&os) {}
void Append(const char* b, size_t n) { _os->write(b, n); }
private:
std::ostream* _os;
};
class StringAppender {
public:
StringAppender(std::string* str) : _str(str) {}
void Append(const char* b, size_t n) { _str->append(b, n); }
private:
std::string* _str;
};
template <typename Appender>
static void PrintIOBuf(Appender* appender, const IOBuf& b, size_t max_length) {
BinaryCharPrinter<Appender> printer(appender);
const size_t n = b.backing_block_num();
size_t nw = 0;
for (size_t i = 0; i < n; ++i) {
StringPiece blk = b.backing_block(i);
for (size_t j = 0; j < blk.size(); ++j) {
if (nw >= max_length) {
printer.Flush();
char buf[48];
int len = snprintf(buf, sizeof(buf), "...<skipping %" PRIu64 " bytes>",
b.size() - nw);
appender->Append(buf, len);
return;
}
++nw;
printer.PushChar(blk[j]);
}
}
}
template <typename Appender>
static void PrintString(Appender* appender, const StringPiece& s, size_t max_length) {
BinaryCharPrinter<Appender> printer(appender);
for (size_t i = 0; i < s.size(); ++i) {
if (i >= max_length) {
printer.Flush();
char buf[48];
int len = snprintf(buf, sizeof(buf), "...<skipping %" PRIu64 " bytes>",
s.size() - i);
appender->Append(buf, len);
return;
}
printer.PushChar(s[i]);
}
}
void BinaryPrinter::Print(std::ostream& os) const {
OStreamAppender appender(os);
if (_iobuf) {
PrintIOBuf(&appender, *_iobuf, _max_length);
} else if (!_str.empty()) {
PrintString(&appender, _str, _max_length);
}
}
std::string ToPrintableString(const IOBuf& data, size_t max_length) {
std::string result;
StringAppender appender(&result);
PrintIOBuf(&appender, data, max_length);
return result;
}
std::string ToPrintableString(const StringPiece& data, size_t max_length) {
std::string result;
StringAppender appender(&result);
PrintString(&appender, data, max_length);
return result;
}
std::string ToPrintableString(const void* data, size_t n, size_t max_length) {
std::string result;
StringAppender appender(&result);
PrintString(&appender, StringPiece((const char*)data, n), max_length);
return result;
}
} // namespace butil
// Copyright (c) 2012 Baidu, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Author: Ge,Jun (gejun@baidu.com)
// Date: Thu Nov 22 13:57:56 CST 2012
#ifndef BUTIL_BINARY_PRINTER_H
#define BUTIL_BINARY_PRINTER_H
#include "butil/strings/string_piece.h"
namespace butil {
class IOBuf;
// Print binary content within max length.
// The printing format is optimized for humans and may change in future.
class BinaryPrinter {
public:
static const size_t DEFAULT_MAX_LENGTH = 64;
explicit BinaryPrinter(const IOBuf& data)
: _iobuf(&data), _max_length(DEFAULT_MAX_LENGTH) {}
BinaryPrinter(const IOBuf& b, size_t max_length)
: _iobuf(&b), _max_length(max_length) {}
explicit BinaryPrinter(const StringPiece& str)
: _iobuf(NULL), _str(str), _max_length(DEFAULT_MAX_LENGTH) {}
BinaryPrinter(const StringPiece& str, size_t max_length)
: _iobuf(NULL), _str(str), _max_length(max_length) {}
explicit BinaryPrinter(const void* data, size_t n)
: _iobuf(NULL), _str((const char*)data, n), _max_length(DEFAULT_MAX_LENGTH) {}
explicit BinaryPrinter(const void* data, size_t n, size_t max_length)
: _iobuf(NULL), _str((const char*)data, n), _max_length(max_length) {}
void Print(std::ostream& os) const;
private:
const IOBuf* _iobuf;
StringPiece _str;
size_t _max_length;
};
// Keep old name for compatibility.
typedef BinaryPrinter PrintedAsBinary;
inline std::ostream& operator<<(std::ostream& os, const BinaryPrinter& p) {
p.Print(os);
return os;
}
// Convert binary data to a printable string.
std::string ToPrintableString(const IOBuf& data,
size_t max_length = BinaryPrinter::DEFAULT_MAX_LENGTH);
std::string ToPrintableString(const StringPiece& data,
size_t max_length = BinaryPrinter::DEFAULT_MAX_LENGTH);
std::string ToPrintableString(const void* data, size_t n,
size_t max_length = BinaryPrinter::DEFAULT_MAX_LENGTH);
} // namespace butil
#endif // BUTIL_BINARY_PRINTER_H
......@@ -1466,94 +1466,6 @@ std::ostream& operator<<(std::ostream& os, const IOBuf& buf) {
return os;
}
static char s_binary_char_map[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'
};
class BinaryCharPrinter {
public:
static const size_t BUF_SIZE = 127;
explicit BinaryCharPrinter(std::ostream& os)
: _n(0), _os(&os) {}
~BinaryCharPrinter() { flush(); }
void operator<<(unsigned char c);
void flush();
private:
uint32_t _n;
std::ostream* _os;
char _buf[BUF_SIZE];
};
void BinaryCharPrinter::flush() {
if (_n > 0) {
_os->write(_buf, _n);
_n = 0;
}
}
inline void BinaryCharPrinter::operator<<(unsigned char c) {
if (_n > BUF_SIZE - 3) {
_os->write(_buf, _n);
_n = 0;
}
if (c >= 32 && c <= 126) { // displayable ascii characters
if (c != '\\') {
_buf[_n++] = c;
} else {
_buf[_n++] = '\\';
_buf[_n++] = '\\';
}
} else {
_buf[_n++] = '\\';
switch (c) {
case '\b': _buf[_n++] = 'b'; break;
case '\t': _buf[_n++] = 't'; break;
case '\n': _buf[_n++] = 'n'; break;
case '\r': _buf[_n++] = 'r'; break;
default:
_buf[_n++] = s_binary_char_map[c >> 4];
_buf[_n++] = s_binary_char_map[c & 0xF];
break;
}
}
}
void PrintedAsBinary::print(std::ostream& os) const {
if (_iobuf) {
const size_t n = _iobuf->backing_block_num();
size_t nw = 0;
BinaryCharPrinter printer(os);
for (size_t i = 0; i < n; ++i) {
StringPiece blk = _iobuf->backing_block(i);
for (size_t j = 0; j < blk.size(); ++j) {
if (nw >= _max_length) {
printer.flush();
os << "...<skipping " << _iobuf->size() - nw << " bytes>";
return;
}
++nw;
printer << blk[j];
}
}
} else if (!_data.empty()) {
BinaryCharPrinter printer(os);
for (size_t i = 0; i < _data.size(); ++i) {
if (i >= _max_length) {
printer.flush();
os << "...<skipping " << _data.size() - i << " bytes>";
return;
}
printer << _data[i];
}
}
}
std::ostream& operator<<(std::ostream& os, const PrintedAsBinary& binary_buf) {
binary_buf.print(os);
return os;
}
bool IOBuf::equals(const butil::StringPiece& s) const {
if (size() != s.size()) {
return false;
......
......@@ -29,6 +29,7 @@
#include "butil/zero_copy_stream_as_streambuf.h"
#include "butil/macros.h"
#include "butil/reader_writer.h"
#include "butil/binary_printer.h"
// For IOBuf::appendv(const const_iovec*, size_t). The only difference of this
// struct from iovec (defined in sys/uio.h) is that iov_base is `const void*'
......@@ -403,25 +404,6 @@ private:
std::ostream& operator<<(std::ostream&, const IOBuf& buf);
// Print binary content within max length,
// working for both butil::IOBuf and std::string
struct PrintedAsBinary {
explicit PrintedAsBinary(const IOBuf& b)
: _iobuf(&b), _max_length(64) {}
explicit PrintedAsBinary(const std::string& b)
: _iobuf(NULL), _data(b), _max_length(64) {}
PrintedAsBinary(const IOBuf& b, size_t max_length)
: _iobuf(&b), _max_length(max_length) {}
PrintedAsBinary(const std::string& b, size_t max_length)
: _iobuf(NULL), _data(b), _max_length(max_length) {}
void print(std::ostream& os) const;
private:
const IOBuf* _iobuf;
std::string _data;
size_t _max_length;
};
std::ostream& operator<<(std::ostream&, const PrintedAsBinary& buf);
inline bool operator==(const butil::IOBuf& b, const butil::StringPiece& s)
{ return b.equals(s); }
inline bool operator==(const butil::StringPiece& s, const butil::IOBuf& b)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment