mirror of https://github.com/djcb/mu.git
utils: add async-queue, ansio-printer
Add an async-queue (rougly, GAsyncQueue but in c++ using a deque) Add an ANSI color printer.
This commit is contained in:
parent
281a4cc7db
commit
73f4c49364
|
@ -0,0 +1,185 @@
|
||||||
|
/*
|
||||||
|
** Copyright (C) 2019 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
**
|
||||||
|
** This program is free software; you can redistribute it and/or modify it
|
||||||
|
** under the terms of the GNU General Public License as published by the
|
||||||
|
** Free Software Foundation; either version 3, or (at your option) any
|
||||||
|
** later version.
|
||||||
|
**
|
||||||
|
** This program is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
** GNU General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License
|
||||||
|
** along with this program; if not, write to the Free Software Foundation,
|
||||||
|
** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __MU_ASYNC_QUEUE_HH__
|
||||||
|
#define __MU_ASYNC_QUEUE_HH__
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <mutex>
|
||||||
|
#include <chrono>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
namespace Mu {
|
||||||
|
|
||||||
|
constexpr std::size_t UnlimitedAsyncQueueSize{0};
|
||||||
|
|
||||||
|
template <typename ItemType, /**< the type of Item to queue */
|
||||||
|
std::size_t MaxSize = UnlimitedAsyncQueueSize, /**< maximum size for the queue */
|
||||||
|
typename Allocator = std::allocator<ItemType>> /**< allocator the items */
|
||||||
|
|
||||||
|
class AsyncQueue {
|
||||||
|
public:
|
||||||
|
using value_type = ItemType;
|
||||||
|
using allocator_type = Allocator;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using reference = value_type&;
|
||||||
|
using const_reference = const value_type&;
|
||||||
|
using pointer = typename std::allocator_traits<allocator_type>::pointer;
|
||||||
|
using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
|
||||||
|
using Timeout = std::chrono::steady_clock::duration;
|
||||||
|
|
||||||
|
bool push (const value_type& item, Timeout timeout = {}) {
|
||||||
|
return push(std::move(value_type(item)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push an item to the end of the queue by moving it. If the queue is unlimited,
|
||||||
|
* the timeout is ignored.
|
||||||
|
*
|
||||||
|
* @param item the item to move to the end of the queue
|
||||||
|
* @param timeout and optional timeout
|
||||||
|
*
|
||||||
|
* @return true if the item was pushed; false otherwise.
|
||||||
|
*/
|
||||||
|
bool push (value_type&& item, Timeout timeout={}) {
|
||||||
|
|
||||||
|
std::lock_guard lock{m_};
|
||||||
|
|
||||||
|
if constexpr (!unlimited()) {
|
||||||
|
const auto rv = cv_full_.wait_for(lock, timeout,[&](){
|
||||||
|
return !full_unlocked();}) && !full_unlocked();
|
||||||
|
if (!rv)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
q_.emplace_back(std::move(item));
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
cv_empty_.notify_one();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pop and item from the queue
|
||||||
|
*
|
||||||
|
* @param item receives the popped item (or nothing)
|
||||||
|
* @param timeout optional time to wait for an item to become available
|
||||||
|
*
|
||||||
|
* @return true if item was set; false otherwise.
|
||||||
|
*/
|
||||||
|
bool pop (value_type& item, Timeout timeout = Timeout{}) {
|
||||||
|
|
||||||
|
std::lock_guard lock{m_};
|
||||||
|
|
||||||
|
if (timeout != Timeout{}) {
|
||||||
|
const auto rv = cv_empty_.wait_for(lock, timeout,[&]() {
|
||||||
|
return !q_.empty(); }) && !q_.empty();
|
||||||
|
if (!rv)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} else if (q_.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
item = std::move(q_.front());
|
||||||
|
q_.pop_front();
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
cv_full_.notify_one();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the queue
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void clear() {
|
||||||
|
LOCKED;
|
||||||
|
q_.clear();
|
||||||
|
lock.unlock();
|
||||||
|
cv_full_.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of the queue
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return the size
|
||||||
|
*/
|
||||||
|
size_type size() const {
|
||||||
|
std::lock_guard lock{m_};
|
||||||
|
return q_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum size of the queue if specified through the template
|
||||||
|
* parameter; otherwise the (theoretical) max_size of the inner
|
||||||
|
* container.
|
||||||
|
*
|
||||||
|
* @return the maximum size
|
||||||
|
*/
|
||||||
|
size_type max_size() const {
|
||||||
|
if constexpr (unlimited())
|
||||||
|
return q_.max_size();
|
||||||
|
else
|
||||||
|
return MaxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the queue empty?
|
||||||
|
*
|
||||||
|
* @return true or false
|
||||||
|
*/
|
||||||
|
bool empty() const {
|
||||||
|
std::lock_guard lock{m_};
|
||||||
|
return q_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the queue full? Returns false unless a maximum size was specified
|
||||||
|
* (as a template argument)
|
||||||
|
*
|
||||||
|
* @return true or false.
|
||||||
|
*/
|
||||||
|
bool full() const {
|
||||||
|
if constexpr (unlimited())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::lock_guard lock{m_};
|
||||||
|
return full_unlocked();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this queue (theoretically) unlimited in size?
|
||||||
|
*
|
||||||
|
* @return true or false
|
||||||
|
*/
|
||||||
|
constexpr static bool unlimited() { return MaxSize == UnlimitedAsyncQueueSize; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool full_unlocked() const { return q_.size() >= max_size(); }
|
||||||
|
|
||||||
|
std::deque<ItemType, Allocator> q_;
|
||||||
|
mutable std::mutex m_;
|
||||||
|
std::condition_variable cv_full_, cv_empty_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mu
|
||||||
|
|
||||||
|
#endif /* __MU_ASYNC_QUEUE_HH__ */
|
|
@ -46,6 +46,7 @@ noinst_LTLIBRARIES= \
|
||||||
libmu-utils.la
|
libmu-utils.la
|
||||||
|
|
||||||
libmu_utils_la_SOURCES= \
|
libmu_utils_la_SOURCES= \
|
||||||
|
mu-async-queue.hh \
|
||||||
mu-date.c \
|
mu-date.c \
|
||||||
mu-date.h \
|
mu-date.h \
|
||||||
mu-error.hh \
|
mu-error.hh \
|
||||||
|
|
|
@ -163,10 +163,8 @@ Mu::log_init (const std::string& path, Mu::LogOptions opts)
|
||||||
void
|
void
|
||||||
Mu::log_uninit ()
|
Mu::log_uninit ()
|
||||||
{
|
{
|
||||||
if (!MuLogInitialized) {
|
if (!MuLogInitialized)
|
||||||
g_warning ("logging was not initialized");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (MuStream.is_open())
|
if (MuStream.is_open())
|
||||||
MuStream.close();
|
MuStream.close();
|
||||||
|
|
|
@ -23,9 +23,11 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <chrono>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace Mu {
|
namespace Mu {
|
||||||
|
|
||||||
|
@ -117,7 +119,14 @@ std::string date_to_time_t_string (const std::string& date, bool first);
|
||||||
*/
|
*/
|
||||||
std::string date_to_time_t_string (int64_t t);
|
std::string date_to_time_t_string (int64_t t);
|
||||||
|
|
||||||
|
using SteadyClock = std::chrono::steady_clock;
|
||||||
|
|
||||||
|
static inline int64_t to_ms (SteadyClock::duration dur) {
|
||||||
|
return std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
|
||||||
|
}
|
||||||
|
static inline int64_t to_us (SteadyClock::duration dur) {
|
||||||
|
return std::chrono::duration_cast<std::chrono::microseconds>(dur).count();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a size string to a size in bytes
|
* Convert a size string to a size in bytes
|
||||||
|
@ -157,6 +166,44 @@ static inline std::string to_string (const T& val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct MaybeAnsi {
|
||||||
|
explicit MaybeAnsi(bool use_color): color_{use_color} {}
|
||||||
|
|
||||||
|
enum struct Color {
|
||||||
|
Black = 30,
|
||||||
|
Red = 31,
|
||||||
|
Green = 32,
|
||||||
|
Yellow = 33,
|
||||||
|
Blue = 34,
|
||||||
|
Magenta = 35,
|
||||||
|
Cyan = 36,
|
||||||
|
White = 37,
|
||||||
|
|
||||||
|
BrightBlack = 90,
|
||||||
|
BrightRed = 91,
|
||||||
|
BrightGreen = 92,
|
||||||
|
BrightYellow = 93,
|
||||||
|
BrightBlue = 94,
|
||||||
|
BrightMagenta = 95,
|
||||||
|
BrightCyan = 96,
|
||||||
|
BrightWhite = 97,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string fg(Color c) const { return ansi(c, true); }
|
||||||
|
std::string bg(Color c) const { return ansi(c, false); }
|
||||||
|
|
||||||
|
std::string reset() const { return color_ ? "\x1b[0m" : ""; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string ansi(Color c, bool fg=true) const {
|
||||||
|
return color_ ? format("\x1b[%dm", static_cast<int>(c) + (fg ? 0 : 10)) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool color_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* don't repeat these catch blocks everywhere...
|
* don't repeat these catch blocks everywhere...
|
||||||
|
|
Loading…
Reference in New Issue