2019-04-27 07:08:19 +08:00
|
|
|
#ifndef FISH_ENUM_SET_H
|
|
|
|
#define FISH_ENUM_SET_H
|
2018-10-03 01:30:23 +08:00
|
|
|
|
2019-04-27 07:08:19 +08:00
|
|
|
#include <array>
|
2018-10-03 01:30:23 +08:00
|
|
|
#include <bitset>
|
2019-02-17 06:19:59 +08:00
|
|
|
#include <cassert>
|
|
|
|
#include <iterator>
|
2018-10-03 01:30:23 +08:00
|
|
|
|
2019-02-17 06:19:59 +08:00
|
|
|
/// A type (to specialize) that provides a count for an enum.
|
|
|
|
/// Example:
|
|
|
|
/// template<> struct enum_info_t<MyEnum>
|
|
|
|
/// { static constexpr auto count = MyEnum::COUNT; };
|
2018-10-03 01:30:23 +08:00
|
|
|
template <typename T>
|
2019-02-17 06:19:59 +08:00
|
|
|
struct enum_info_t {};
|
|
|
|
|
2019-02-12 12:23:15 +08:00
|
|
|
/// \return the count of an enum.
|
2019-02-17 06:19:59 +08:00
|
|
|
template <typename T>
|
2019-02-12 12:23:15 +08:00
|
|
|
constexpr size_t enum_count() {
|
|
|
|
return static_cast<size_t>(enum_info_t<T>::count);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A bit set indexed by an enum type.
|
|
|
|
template <typename T>
|
|
|
|
class enum_set_t : private std::bitset<enum_count<T>()> {
|
2018-10-03 01:30:23 +08:00
|
|
|
private:
|
2019-02-12 12:23:15 +08:00
|
|
|
using super = std::bitset<enum_count<T>()>;
|
2019-02-17 06:19:59 +08:00
|
|
|
static size_t index_of(T t) { return static_cast<size_t>(t); }
|
|
|
|
|
|
|
|
explicit enum_set_t(unsigned long raw) : super(raw) {}
|
2019-04-26 02:22:17 +08:00
|
|
|
explicit enum_set_t(super sup) : super(sup) {}
|
2018-10-03 01:30:23 +08:00
|
|
|
|
|
|
|
public:
|
2019-02-17 06:19:59 +08:00
|
|
|
enum_set_t() = default;
|
|
|
|
|
Introduce topic monitoring
topic_monitor allows for querying changes posted to one or more topics,
initially sigchld. This will eventually replace the waitpid logic in
process_mark_finished_children().
Comment from the new header:
Topic monitoring support. Topics are conceptually "a thing that can
happen." For example, delivery of a SIGINT, a child process exits, etc. It
is possible to post to a topic, which means that that thing happened.
Associated with each topic is a current generation, which is a 64 bit
value. When you query a topic, you get back a generation. If on the next
query the generation has increased, then it indicates someone posted to
the topic.
For example, if you are monitoring a child process, you can query the
sigchld topic. If it has increased since your last query, it is possible
that your child process has exited.
Topic postings may be coalesced. That is there may be two posts to a given
topic, yet the generation only increases by 1. The only guarantee is that
after a topic post, the current generation value is larger than any value
previously queried.
Tying this all together is the topic_monitor_t. This provides the current
topic generations, and also provides the ability to perform a blocking
wait for any topic to change in a particular topic set. This is the real
power of topics: you can wait for a sigchld signal OR a thread exit.
2019-02-03 07:39:04 +08:00
|
|
|
/*implicit*/ enum_set_t(T v) { set(v); }
|
2019-02-17 06:19:59 +08:00
|
|
|
|
2019-02-15 12:55:43 +08:00
|
|
|
/*implicit*/ enum_set_t(std::initializer_list<T> vs) {
|
|
|
|
for (T v : vs) set(v);
|
|
|
|
}
|
|
|
|
|
2019-02-17 06:19:59 +08:00
|
|
|
static enum_set_t from_raw(unsigned long v) { return enum_set_t{v}; }
|
|
|
|
|
|
|
|
unsigned long to_raw() const { return super::to_ulong(); }
|
|
|
|
|
|
|
|
bool get(T t) const { return super::test(index_of(t)); }
|
|
|
|
|
|
|
|
void set(T t, bool v = true) { super::set(index_of(t), v); }
|
|
|
|
|
|
|
|
void clear(T t) { super::reset(index_of(t)); }
|
|
|
|
|
|
|
|
bool none() const { return super::none(); }
|
|
|
|
|
|
|
|
bool any() const { return super::any(); }
|
2018-10-03 01:30:23 +08:00
|
|
|
|
2019-02-17 06:19:59 +08:00
|
|
|
bool operator==(const enum_set_t &rhs) const { return super::operator==(rhs); }
|
|
|
|
|
|
|
|
bool operator!=(const enum_set_t &rhs) const { return super::operator!=(rhs); }
|
2019-04-26 02:22:17 +08:00
|
|
|
|
|
|
|
/// OR in a single flag, returning a new set.
|
|
|
|
enum_set_t operator|(T rhs) const {
|
|
|
|
enum_set_t result = *this;
|
|
|
|
result.set(rhs);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Compute the union of two sets.
|
|
|
|
enum_set_t operator|(enum_set_t rhs) const { return from_raw(to_raw() | rhs.to_raw()); }
|
|
|
|
|
|
|
|
/// OR in a single flag, modifying the set in place.
|
|
|
|
enum_set_t operator|=(T rhs) {
|
|
|
|
*this = *this | rhs;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set this to the union of two sets.
|
|
|
|
enum_set_t operator|=(enum_set_t rhs) {
|
|
|
|
*this = *this | rhs;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Test a value of a single flag. Note this does not return an enum_set_t; there is no such
|
|
|
|
/// boolean conversion. This simply makes flags work more naturally as bit masks.
|
|
|
|
bool operator&(T rhs) const { return get(rhs); }
|
2019-02-17 06:19:59 +08:00
|
|
|
};
|
|
|
|
|
2019-02-12 12:23:15 +08:00
|
|
|
/// An array of Elem indexed by an enum class.
|
|
|
|
template <typename Elem, typename T>
|
|
|
|
class enum_array_t : public std::array<Elem, enum_count<T>()> {
|
|
|
|
using super = std::array<Elem, enum_count<T>()>;
|
|
|
|
using base_type_t = typename std::underlying_type<T>::type;
|
|
|
|
|
|
|
|
static int index_of(T t) { return static_cast<base_type_t>(t); }
|
|
|
|
|
|
|
|
public:
|
|
|
|
Elem &at(T t) { return super::at(index_of(t)); }
|
|
|
|
const Elem &at(T t) const { return super::at(index_of(t)); }
|
|
|
|
Elem &operator[](T t) { return super::operator[](index_of(t)); }
|
|
|
|
const Elem &operator[](T t) const { return super::operator[](index_of(t)); }
|
|
|
|
};
|
|
|
|
|
2019-02-17 06:19:59 +08:00
|
|
|
/// A counting iterator for an enum class.
|
|
|
|
/// This enumerates the values of an enum class from 0 up to (not including) count.
|
|
|
|
/// Example:
|
|
|
|
/// for (auto v : enum_iter_t<MyEnum>) {...}
|
|
|
|
template <typename T>
|
|
|
|
class enum_iter_t {
|
|
|
|
using base_type_t = typename std::underlying_type<T>::type;
|
|
|
|
struct iterator_t {
|
|
|
|
friend class enum_iter_t;
|
|
|
|
using iterator_category = std::forward_iterator_tag;
|
|
|
|
using value_type = T;
|
|
|
|
using difference_type = long;
|
|
|
|
|
|
|
|
explicit iterator_t(base_type_t v) : v_(v) {}
|
|
|
|
|
|
|
|
T operator*() const { return static_cast<T>(v_); }
|
|
|
|
const T *operator->() const { return static_cast<const T *>(v_); }
|
|
|
|
|
|
|
|
iterator_t &operator++() {
|
|
|
|
v_ += 1;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator_t operator++(int) {
|
|
|
|
auto res = *this;
|
|
|
|
v_ += 1;
|
|
|
|
return res;
|
2018-10-03 01:30:23 +08:00
|
|
|
}
|
|
|
|
|
2019-02-17 06:19:59 +08:00
|
|
|
bool operator==(iterator_t rhs) const { return v_ == rhs.v_; }
|
|
|
|
bool operator!=(iterator_t rhs) const { return v_ != rhs.v_; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
base_type_t v_{};
|
|
|
|
};
|
2018-10-03 01:30:23 +08:00
|
|
|
|
2019-02-17 06:19:59 +08:00
|
|
|
public:
|
|
|
|
iterator_t begin() const { return iterator_t{0}; }
|
2019-02-12 12:23:15 +08:00
|
|
|
iterator_t end() const { return iterator_t{static_cast<base_type_t>(enum_count<T>())}; }
|
2018-10-03 01:30:23 +08:00
|
|
|
};
|
2019-04-27 07:08:19 +08:00
|
|
|
|
|
|
|
#endif
|