From 59f5bcdcadb13019b29482eb55814e89a823f478 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 25 Jan 2015 17:27:41 +0300 Subject: [PATCH] Fixes #10926. Generalized id formatting. Also, different hex-based formatting routines now use the common character table, which should reduce binary size a little. --- doc/changelog.qbk | 1 + src/dump.cpp | 9 ++++--- src/dump_avx2.cpp | 5 ++-- src/dump_ssse3.cpp | 5 ++-- src/id_formatting.hpp | 61 +++++++++++++++++++++++++++++++++++++++++++ src/process_id.cpp | 12 ++++----- src/thread_id.cpp | 34 +++--------------------- 7 files changed, 81 insertions(+), 46 deletions(-) create mode 100644 src/id_formatting.hpp diff --git a/doc/changelog.qbk b/doc/changelog.qbk index de7c565..03fbc31 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -14,6 +14,7 @@ [*Bug fixes:] * Fixed thread id formatting. The thread identifiers could be presented as zeros on big-endian platforms. Also the lower 4 bits of the ids were lost in the output. +* Fixed process id formatting. Process ids could have misplaced filler zeros. ([ticket 10926]) [heading 2.4, Boost 1.57] diff --git a/src/dump.cpp b/src/dump.cpp index de320cf..a25e387 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -52,8 +52,11 @@ extern dump_data_char32_t dump_data_char32_avx2; enum { stride = 256 }; -extern const char g_lowercase_dump_char_table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; -extern const char g_uppercase_dump_char_table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; +extern const char g_hex_char_table[2][16] = +{ + { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }, + { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' } +}; template< typename CharT > void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< CharT >& strm) @@ -62,7 +65,7 @@ void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< C char_type buf[stride * 3u]; - const char* const char_table = (strm.flags() & std::ios_base::uppercase) ? g_uppercase_dump_char_table : g_lowercase_dump_char_table; + const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0]; const std::size_t stride_count = size / stride, tail_size = size % stride; const uint8_t* p = static_cast< const uint8_t* >(data); diff --git a/src/dump_avx2.cpp b/src/dump_avx2.cpp index d7a997c..04933d5 100644 --- a/src/dump_avx2.cpp +++ b/src/dump_avx2.cpp @@ -34,8 +34,7 @@ BOOST_LOG_OPEN_NAMESPACE namespace aux { -extern const char g_lowercase_dump_char_table[]; -extern const char g_uppercase_dump_char_table[]; +extern const char g_hex_char_table[2][16]; template< typename CharT > extern void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< CharT >& strm); @@ -274,7 +273,7 @@ BOOST_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::b } _mm256_zeroall(); // need to zero all ymm registers to avoid register spills/restores the compler generates around the function call - const char* const char_table = (strm.flags() & std::ios_base::uppercase) ? g_uppercase_dump_char_table : g_lowercase_dump_char_table; + const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0]; for (unsigned int i = 0; i < tail_size; ++i, ++p, b += 3u) { uint32_t n = *p; diff --git a/src/dump_ssse3.cpp b/src/dump_ssse3.cpp index 41ee4d8..fcecc57 100644 --- a/src/dump_ssse3.cpp +++ b/src/dump_ssse3.cpp @@ -34,8 +34,7 @@ BOOST_LOG_OPEN_NAMESPACE namespace aux { -extern const char g_lowercase_dump_char_table[]; -extern const char g_uppercase_dump_char_table[]; +extern const char g_hex_char_table[2][16]; template< typename CharT > extern void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< CharT >& strm); @@ -236,7 +235,7 @@ BOOST_FORCEINLINE void dump_data_ssse3(const void* data, std::size_t size, std:: tail_size -= 16u; } - const char* const char_table = (strm.flags() & std::ios_base::uppercase) ? g_uppercase_dump_char_table : g_lowercase_dump_char_table; + const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0]; for (unsigned int i = 0; i < tail_size; ++i, ++p, b += 3u) { uint32_t n = *p; diff --git a/src/id_formatting.hpp b/src/id_formatting.hpp new file mode 100644 index 0000000..00091bb --- /dev/null +++ b/src/id_formatting.hpp @@ -0,0 +1,61 @@ +/* + * Copyright Andrey Semashev 2007 - 2014. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file id_formatting.hpp + * \author Andrey Semashev + * \date 25.01.2015 + * + * \brief This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. + */ + +#ifndef BOOST_LOG_ID_FORMATTING_HPP_INCLUDED_ +#define BOOST_LOG_ID_FORMATTING_HPP_INCLUDED_ + +#include +#include +#include + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace aux { + +// Defined in dump.cpp +extern const char g_hex_char_table[2][16]; + +template< std::size_t IdSize, typename CharT, typename IdT > +inline void format_id(CharT* buf, std::size_t size, IdT id, bool uppercase) BOOST_NOEXCEPT +{ + const char* const char_table = g_hex_char_table[uppercase]; + + // Input buffer is assumed to be always larger than 2 chars + *buf++ = static_cast< CharT >(char_table[0]); // '0' + *buf++ = static_cast< CharT >(char_table[10] + ('x' - 'a')); // 'x' + + size -= 3; // reserve space for the terminating 0 + std::size_t i = 0; + const std::size_t n = (size > (IdSize * 2u)) ? IdSize * 2u : size; + for (std::size_t shift = n * 4u - 4u; i < n; ++i, shift -= 4u) + { + buf[i] = static_cast< CharT >(char_table[(id >> shift) & 15u]); + } + + buf[i] = static_cast< CharT >('\0'); +} + +} // namespace aux + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_ID_FORMATTING_HPP_INCLUDED_ + diff --git a/src/process_id.cpp b/src/process_id.cpp index 33a0d7d..04c05d8 100644 --- a/src/process_id.cpp +++ b/src/process_id.cpp @@ -14,9 +14,8 @@ */ #include -#include -#include #include +#include "id_formatting.hpp" #include #if defined(BOOST_WINDOWS) @@ -95,11 +94,10 @@ operator<< (std::basic_ostream< CharT, TraitsT >& strm, process::id const& pid) { if (strm.good()) { - io::ios_flags_saver flags_saver(strm, std::ios_base::hex | std::ios_base::showbase); - // The width is set calculated to accommodate pid in hex + "0x" prefix - io::ios_width_saver width_saver(strm, static_cast< std::streamsize >(pid_size * 2 + 2)); - io::basic_ios_fill_saver< CharT, TraitsT > fill_saver(strm, static_cast< CharT >('0')); - strm << static_cast< uint_t< pid_size * 8 >::least >(pid.native_id()); + CharT buf[pid_size * 2 + 3]; // 2 chars per byte + 3 chars for the leading 0x and terminating zero + format_id< pid_size >(buf, sizeof(buf) / sizeof(*buf), pid.native_id(), (strm.flags() & std::ios_base::uppercase) != 0); + + strm << buf; } return strm; diff --git a/src/thread_id.cpp b/src/thread_id.cpp index e36bcb5..b590f29 100644 --- a/src/thread_id.cpp +++ b/src/thread_id.cpp @@ -39,6 +39,7 @@ #if !defined(BOOST_LOG_USE_COMPILER_TLS) #include #endif +#include "id_formatting.hpp" #include #if defined(BOOST_WINDOWS) @@ -232,46 +233,19 @@ BOOST_LOG_API thread::id const& get_id() } // namespace this_thread -BOOST_LOG_ANONYMOUS_NAMESPACE { - -template< typename CharT > -inline void format_thread_id_impl(CharT* buf, std::size_t size, thread::id tid, const CharT (&char_table)[18]) -{ - // Input buffer is assumed to be always larger than 2 chars - *buf++ = char_table[0]; // '0' - *buf++ = char_table[16]; // 'x' - - size -= 3; // reserve space for the terminating 0 - thread::id::native_type id = tid.native_id(); - unsigned int i = 0; - const unsigned int n = (size > (tid_size * 2u)) ? static_cast< unsigned int >(tid_size * 2u) : static_cast< unsigned int >(size); - for (unsigned int shift = n * 4u - 4u; i < n; ++i, shift -= 4u) - { - buf[i] = char_table[(id >> shift) & 15u]; - } - - buf[i] = '\0'; -} - -} // namespace - // Used in default_sink.cpp void format_thread_id(char* buf, std::size_t size, thread::id tid) { - format_thread_id_impl(buf, size, tid, "0123456789abcdefx"); + format_id< tid_size >(buf, size, tid.native_id(), false); } template< typename CharT, typename TraitsT > -std::basic_ostream< CharT, TraitsT >& -operator<< (std::basic_ostream< CharT, TraitsT >& strm, thread::id const& tid) +std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, thread::id const& tid) { if (strm.good()) { - static const CharT lowercase[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'x', '\0' }; - static const CharT uppercase[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'X', '\0' }; - CharT buf[tid_size * 2 + 3]; // 2 chars per byte + 3 chars for the leading 0x and terminating zero - format_thread_id_impl(buf, sizeof(buf) / sizeof(*buf), tid, (strm.flags() & std::ios_base::uppercase) ? uppercase : lowercase); + format_id< tid_size >(buf, sizeof(buf) / sizeof(*buf), tid.native_id(), (strm.flags() & std::ios_base::uppercase) != 0); strm << buf; }