1 // 2 // libsemigroups - C++ library for semigroups and monoids 3 // Copyright (C) 2019 James D. Mitchell 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 // 18 19 #include "libsemigroups/report.hpp" 20 21 #include <iostream> 22 23 #include "libsemigroups/libsemigroups-config.hpp" 24 25 namespace libsemigroups { 26 detail::Reporter REPORTER; 27 detail::ThreadIdManager THREAD_ID_MANAGER; 28 29 namespace detail { 30 ThreadIdManager()31 ThreadIdManager::ThreadIdManager() : _mtx(), _next_tid(0), _thread_map() { 32 tid(std::this_thread::get_id()); 33 } 34 reset()35 void ThreadIdManager::reset() { 36 // Only do this from the main thread 37 LIBSEMIGROUPS_ASSERT(tid(std::this_thread::get_id()) == 0); 38 // Delete all thread_ids 39 _thread_map.clear(); 40 _next_tid = 0; 41 // Reinsert the main thread's id 42 tid(std::this_thread::get_id()); 43 } 44 tid(std::thread::id t)45 size_t ThreadIdManager::tid(std::thread::id t) { 46 std::lock_guard<std::mutex> lg(_mtx); 47 auto it = _thread_map.find(t); 48 if (it != _thread_map.end()) { 49 return (*it).second; 50 } else { 51 // Don't check the assert below because on a single thread machine 52 // (such as those used by appveyor), for an fp-semigroup more than 1 53 // thread will be used, and this assertion will fail. 54 // LIBSEMIGROUPS_ASSERT(_next_tid <= 55 // std::thread::hardware_concurrency()); 56 _thread_map.emplace(t, _next_tid++); 57 return _next_tid - 1; 58 } 59 } 60 Reporter(bool report)61 Reporter::Reporter(bool report) 62 : _last_msg(), _mtx(), _msg(), _options(), _report(report) {} 63 64 #ifdef LIBSEMIGROUPS_FMT_ENABLED color(fmt::color c)65 Reporter& Reporter::color(fmt::color c) { 66 if (_report) { 67 size_t tid = THREAD_ID_MANAGER.tid(std::this_thread::get_id()); 68 resize(tid + 1); 69 _options[tid].color = c; 70 } 71 return *this; 72 } 73 thread_color()74 Reporter& Reporter::thread_color() { 75 if (_report) { 76 std::lock_guard<std::mutex> lg(_mtx); 77 size_t tid = THREAD_ID_MANAGER.tid(std::this_thread::get_id()); 78 resize(tid + 1); 79 _options[tid].color = thread_colors[tid % thread_colors.size()]; 80 } 81 return *this; 82 } 83 #endif 84 prefix()85 Reporter& Reporter::prefix() { 86 if (_report) { 87 std::lock_guard<std::mutex> lg(_mtx); 88 size_t tid = THREAD_ID_MANAGER.tid(std::this_thread::get_id()); 89 resize(tid + 1); 90 _options[tid].prefix = ""; 91 } 92 return *this; 93 } 94 flush_right()95 Reporter& Reporter::flush_right() { 96 if (_report) { 97 std::lock_guard<std::mutex> lg(_mtx); 98 size_t tid = THREAD_ID_MANAGER.tid(std::this_thread::get_id()); 99 resize(tid + 1); 100 _options[tid].flush_right = true; 101 } 102 return *this; 103 } 104 flush()105 void Reporter::flush() { 106 if (_report) { 107 std::lock_guard<std::mutex> lg(_mtx); 108 size_t tid = THREAD_ID_MANAGER.tid(std::this_thread::get_id()); 109 size_t pad = 0; 110 _msg[tid] = _options[tid].prefix + _msg[tid]; 111 if (_options[tid].flush_right 112 && _last_msg[tid].size() + unicode_string_length(_msg[tid]) < 80) { 113 pad = (80 - _last_msg[tid].size()) - unicode_string_length(_msg[tid]); 114 _msg[tid] = std::string(pad, ' ') + _msg[tid]; 115 } 116 #ifdef LIBSEMIGROUPS_VERBOSE 117 if (_msg[tid].back() != '\n') { 118 _msg[tid] += "\n"; 119 } 120 #endif 121 _msg[tid] = wrap(_options[tid].prefix.length(), _msg[tid]); 122 #ifdef LIBSEMIGROUPS_FMT_ENABLED 123 fmt::print(fg(_options[tid].color), _msg[tid]); 124 #else 125 std::cout << _msg[tid]; 126 #endif 127 _options[tid] = Options(); 128 } 129 } 130 resize(size_t n)131 void Reporter::resize(size_t n) { 132 if (n > _msg.size()) { 133 _last_msg.resize(n); 134 _msg.resize(n); 135 _options.resize(n); 136 } 137 } 138 } // namespace detail 139 } // namespace libsemigroups 140