summaryrefslogtreecommitdiff
path: root/src/utils
diff options
context:
space:
mode:
authorKlaus Aehlig <klaus.aehlig@huawei.com>2022-02-22 17:03:21 +0100
committerKlaus Aehlig <klaus.aehlig@huawei.com>2022-02-22 17:03:21 +0100
commit619def44c1cca9f3cdf63544d5f24f2c7a7d9b77 (patch)
tree01868de723cb82c86842f33743fa7b14e24c1fa3 /src/utils
downloadjustbuild-619def44c1cca9f3cdf63544d5f24f2c7a7d9b77.tar.gz
Initial self-hosting commit
This is the initial version of our tool that is able to build itself. In can be bootstrapped by ./bin/bootstrap.py Co-authored-by: Oliver Reiche <oliver.reiche@huawei.com> Co-authored-by: Victor Moreno <victor.moreno1@huawei.com>
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/TARGETS1
-rw-r--r--src/utils/cpp/TARGETS40
-rw-r--r--src/utils/cpp/atomic.hpp119
-rw-r--r--src/utils/cpp/concepts.hpp55
-rw-r--r--src/utils/cpp/hash_combine.hpp15
-rw-r--r--src/utils/cpp/hex_string.hpp19
-rw-r--r--src/utils/cpp/json.hpp83
-rw-r--r--src/utils/cpp/type_safe_arithmetic.hpp197
8 files changed, 529 insertions, 0 deletions
diff --git a/src/utils/TARGETS b/src/utils/TARGETS
new file mode 100644
index 00000000..9e26dfee
--- /dev/null
+++ b/src/utils/TARGETS
@@ -0,0 +1 @@
+{} \ No newline at end of file
diff --git a/src/utils/cpp/TARGETS b/src/utils/cpp/TARGETS
new file mode 100644
index 00000000..6b4347a2
--- /dev/null
+++ b/src/utils/cpp/TARGETS
@@ -0,0 +1,40 @@
+{ "hash_combine":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["hash_combine"]
+ , "hdrs": ["hash_combine.hpp"]
+ , "deps": [["@", "gsl-lite", "", "gsl-lite"]]
+ , "stage": ["src", "utils", "cpp"]
+ }
+, "type_safe_arithmetic":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["type_safe_arithmetic"]
+ , "hdrs": ["type_safe_arithmetic.hpp"]
+ , "deps": [["@", "gsl-lite", "", "gsl-lite"]]
+ , "stage": ["src", "utils", "cpp"]
+ }
+, "json":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["json"]
+ , "hdrs": ["json.hpp"]
+ , "deps": [["@", "json", "", "json"], ["@", "gsl-lite", "", "gsl-lite"]]
+ , "stage": ["src", "utils", "cpp"]
+ }
+, "concepts":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["concepts"]
+ , "hdrs": ["concepts.hpp"]
+ , "stage": ["src", "utils", "cpp"]
+ }
+, "atomic":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["atomic"]
+ , "hdrs": ["atomic.hpp"]
+ , "stage": ["src", "utils", "cpp"]
+ }
+, "hex_string":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["hex_string"]
+ , "hdrs": ["hex_string.hpp"]
+ , "stage": ["src", "utils", "cpp"]
+ }
+} \ No newline at end of file
diff --git a/src/utils/cpp/atomic.hpp b/src/utils/cpp/atomic.hpp
new file mode 100644
index 00000000..7f7631d0
--- /dev/null
+++ b/src/utils/cpp/atomic.hpp
@@ -0,0 +1,119 @@
+#ifndef INCLUDED_SRC_UTILS_CPP_ATOMIC_HPP
+#define INCLUDED_SRC_UTILS_CPP_ATOMIC_HPP
+
+#include <atomic>
+#include <condition_variable>
+#include <shared_mutex>
+
+// Atomic wrapper with notify/wait capabilities.
+// TODO(modernize): Replace any use this class by C++20's std::atomic<T>, once
+// libcxx adds support for notify_*() and wait().
+// [https://libcxx.llvm.org/docs/Cxx2aStatus.html]
+template <class T>
+class atomic {
+ public:
+ atomic() = default;
+ explicit atomic(T value) : value_{std::move(value)} {}
+ atomic(atomic const& other) = delete;
+ atomic(atomic&& other) = delete;
+ ~atomic() = default;
+
+ auto operator=(atomic const& other) -> atomic& = delete;
+ auto operator=(atomic&& other) -> atomic& = delete;
+ auto operator=(T desired) -> T { // NOLINT
+ std::shared_lock lock(mutex_);
+ value_ = desired;
+ return desired;
+ }
+ operator T() const { return static_cast<T>(value_); } // NOLINT
+
+ void store(T desired, std::memory_order order = std::memory_order_seq_cst) {
+ std::shared_lock lock(mutex_);
+ value_.store(std::move(desired), order);
+ }
+ [[nodiscard]] auto load(
+ std::memory_order order = std::memory_order_seq_cst) const -> T {
+ return value_.load(order);
+ }
+
+ template <class U = T, class = std::enable_if_t<std::is_integral_v<U>>>
+ auto operator++() -> T {
+ std::shared_lock lock(mutex_);
+ return ++value_;
+ }
+ template <class U = T, class = std::enable_if_t<std::is_integral_v<U>>>
+ [[nodiscard]] auto operator++(int) -> T {
+ std::shared_lock lock(mutex_);
+ return value_++;
+ }
+ template <class U = T, class = std::enable_if_t<std::is_integral_v<U>>>
+ auto operator--() -> T {
+ std::shared_lock lock(mutex_);
+ return --value_;
+ }
+ template <class U = T, class = std::enable_if_t<std::is_integral_v<U>>>
+ [[nodiscard]] auto operator--(int) -> T {
+ std::shared_lock lock(mutex_);
+ return value_--;
+ }
+
+ void notify_one() { cv_.notify_one(); }
+ void notify_all() { cv_.notify_all(); }
+ void wait(T old,
+ std::memory_order order = std::memory_order::seq_cst) const {
+ std::unique_lock lock(mutex_);
+ cv_.wait(lock,
+ [this, &old, order]() { return value_.load(order) != old; });
+ }
+
+ private:
+ std::atomic<T> value_{};
+ mutable std::shared_mutex mutex_{};
+ mutable std::condition_variable_any cv_{};
+};
+
+// Atomic shared_pointer with notify/wait capabilities.
+// TODO(modernize): Replace any use this class by C++20's
+// std::atomic<std::shared_ptr<T>>, once libcxx adds support for it.
+// [https://libcxx.llvm.org/docs/Cxx2aStatus.html]
+template <class T>
+class atomic_shared_ptr {
+ using ptr_t = std::shared_ptr<T>;
+
+ public:
+ atomic_shared_ptr() = default;
+ explicit atomic_shared_ptr(ptr_t value) : value_{std::move(value)} {}
+ atomic_shared_ptr(atomic_shared_ptr const& other) = delete;
+ atomic_shared_ptr(atomic_shared_ptr&& other) = delete;
+ ~atomic_shared_ptr() = default;
+
+ auto operator=(atomic_shared_ptr const& other)
+ -> atomic_shared_ptr& = delete;
+ auto operator=(atomic_shared_ptr&& other) -> atomic_shared_ptr& = delete;
+ auto operator=(ptr_t desired) -> ptr_t { // NOLINT
+ std::shared_lock lock(mutex_);
+ value_ = desired;
+ return desired;
+ }
+ operator ptr_t() const { value_; } // NOLINT
+
+ void store(ptr_t desired) {
+ std::shared_lock lock(mutex_);
+ value_ = std::move(desired);
+ }
+ [[nodiscard]] auto load() const -> ptr_t { return value_; }
+
+ void notify_one() { cv_.notify_one(); }
+ void notify_all() { cv_.notify_all(); }
+ void wait(ptr_t old) const {
+ std::unique_lock lock(mutex_);
+ cv_.wait(lock, [this, &old]() { return value_ != old; });
+ }
+
+ private:
+ ptr_t value_{};
+ mutable std::shared_mutex mutex_{};
+ mutable std::condition_variable_any cv_{};
+};
+
+#endif // INCLUDED_SRC_UTILS_CPP_ATOMIC_HPP
diff --git a/src/utils/cpp/concepts.hpp b/src/utils/cpp/concepts.hpp
new file mode 100644
index 00000000..92718b43
--- /dev/null
+++ b/src/utils/cpp/concepts.hpp
@@ -0,0 +1,55 @@
+#ifndef INCLUDED_SRC_UTILS_CPP_CONCEPTS_HPP
+#define INCLUDED_SRC_UTILS_CPP_CONCEPTS_HPP
+
+#include <string>
+#include <type_traits>
+
+// TODO(modernize): remove this once std::derived_from is shipped with libcxx
+template <class T, class U>
+concept derived_from = std::is_base_of_v<U, T>&&
+ std::is_convertible_v<const volatile T*, const volatile U*>;
+
+// TODO(modernize): remove this once std::same_as is shipped with libcxx
+template <class T, class U>
+concept same_as = std::is_same_v<T, U>and std::is_same_v<U, T>;
+
+template <class T>
+concept ContainsString = requires {
+ typename T::value_type;
+}
+and std::is_same_v<typename T::value_type, std::string>;
+
+template <class T>
+concept HasSize = requires(T const c) {
+ { c.size() }
+ ->same_as<std::size_t>; // TODO(modernize): replace by std::same_as
+};
+
+template <typename T>
+concept HasToString = requires(T const t) {
+ { t.ToString() }
+ ->same_as<std::string>; // TODO(modernize): replace by std::same_as
+};
+
+template <class T>
+concept InputIterableContainer = requires(T const c) {
+ { c.begin() }
+ ->same_as<typename T::const_iterator>; // TODO(modernize): replace by
+ // std::input_iterator
+ { c.end() }
+ ->same_as<typename T::const_iterator>; // TODO(modernize): replace by
+ // std::input_iterator
+};
+
+template <class T>
+concept OutputIterableContainer = InputIterableContainer<T>and requires(T c) {
+ { std::inserter(c, c.begin()) }
+ ->same_as<std::insert_iterator<T>>; // TODO(modernize): replace by
+ // std::output_iterator
+};
+
+template <class T>
+concept InputIterableStringContainer =
+ InputIterableContainer<T>and ContainsString<T>;
+
+#endif // INCLUDED_SRC_UTILS_CPP_CONCEPTS_HPP
diff --git a/src/utils/cpp/hash_combine.hpp b/src/utils/cpp/hash_combine.hpp
new file mode 100644
index 00000000..65c0c8ad
--- /dev/null
+++ b/src/utils/cpp/hash_combine.hpp
@@ -0,0 +1,15 @@
+#ifndef INCLUDED_SRC_UTILS_CPP_HASH_COMBINE_HPP
+#define INCLUDED_SRC_UTILS_CPP_HASH_COMBINE_HPP
+
+#include "gsl-lite/gsl-lite.hpp"
+
+// Taken from Boost, as hash_combine did not yet make it to STL.
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0814r0.pdf
+template <class T>
+inline auto hash_combine(gsl::not_null<std::size_t*> const& seed, T const& v)
+ -> void {
+ *seed ^=
+ std::hash<T>{}(v) + 0x9e3779b9 + (*seed << 6) + (*seed >> 2); // NOLINT
+}
+
+#endif
diff --git a/src/utils/cpp/hex_string.hpp b/src/utils/cpp/hex_string.hpp
new file mode 100644
index 00000000..86ea1b9e
--- /dev/null
+++ b/src/utils/cpp/hex_string.hpp
@@ -0,0 +1,19 @@
+#ifndef INCLUDED_SRC_UTILS_CPP_HEX_STRING_HPP
+#define INCLUDED_SRC_UTILS_CPP_HEX_STRING_HPP
+
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+[[nodiscard]] static inline auto ToHexString(std::string const& bytes)
+ -> std::string {
+ std::ostringstream ss{};
+ ss << std::hex << std::setfill('0');
+ for (auto const& b : bytes) {
+ ss << std::setw(2)
+ << static_cast<int>(static_cast<unsigned char const>(b));
+ }
+ return ss.str();
+}
+
+#endif // INCLUDED_SRC_UTILS_CPP_HEX_STRING_HPP
diff --git a/src/utils/cpp/json.hpp b/src/utils/cpp/json.hpp
new file mode 100644
index 00000000..8945e975
--- /dev/null
+++ b/src/utils/cpp/json.hpp
@@ -0,0 +1,83 @@
+#ifndef INCLUDED_SRC_UTILS_CPP_JSON_HPP
+#define INCLUDED_SRC_UTILS_CPP_JSON_HPP
+
+#include <algorithm>
+#include <optional>
+#include <sstream>
+#include <string>
+
+#include "nlohmann/json.hpp"
+#include "gsl-lite/gsl-lite.hpp"
+
+template <typename ValueT>
+auto ExtractValueAs(
+ nlohmann::json const& j,
+ std::string const& key,
+ std::function<void(std::string const& error)>&& logger =
+ [](std::string const & /*unused*/) -> void {}) noexcept
+ -> std::optional<ValueT> {
+ try {
+ auto it = j.find(key);
+ if (it == j.end()) {
+ logger("key " + key + " cannot be found in JSON object");
+ return std::nullopt;
+ }
+ return it.value().template get<ValueT>();
+ } catch (std::exception& e) {
+ logger(e.what());
+ return std::nullopt;
+ }
+}
+
+namespace detail {
+
+[[nodiscard]] static inline auto IndentListsOnlyUntilDepth(
+ nlohmann::json const& json,
+ std::string const& indent,
+ std::size_t until,
+ std::size_t depth) -> std::string {
+ using iterator = std::ostream_iterator<std::string>;
+ if (json.is_object()) {
+ std::size_t i{};
+ std::ostringstream oss{};
+ oss << '{' << std::endl;
+ for (auto const& [key, value] : json.items()) {
+ std::fill_n(iterator{oss}, depth + 1, indent);
+ oss << nlohmann::json(key).dump() << ": "
+ << IndentListsOnlyUntilDepth(value, indent, until, depth + 1)
+ << (++i == json.size() ? "" : ",") << std::endl;
+ }
+ std::fill_n(iterator{oss}, depth, indent);
+ oss << '}';
+ gsl_EnsuresAudit(nlohmann::json::parse(oss.str()) == json);
+ return oss.str();
+ }
+ if (json.is_array() and depth < until) {
+ std::size_t i{};
+ std::ostringstream oss{};
+ oss << '[' << std::endl;
+ for (auto const& value : json) {
+ std::fill_n(iterator{oss}, depth + 1, indent);
+ oss << IndentListsOnlyUntilDepth(value, indent, until, depth + 1)
+ << (++i == json.size() ? "" : ",") << std::endl;
+ }
+ std::fill_n(iterator{oss}, depth, indent);
+ oss << ']';
+ gsl_EnsuresAudit(nlohmann::json::parse(oss.str()) == json);
+ return oss.str();
+ }
+ return json.dump();
+}
+
+} // namespace detail
+
+/// \brief Dump json with indent. Indent lists only until specified depth.
+[[nodiscard]] static inline auto IndentListsOnlyUntilDepth(
+ nlohmann::json const& json,
+ std::size_t indent,
+ std::size_t until_depth = 0) -> std::string {
+ return detail::IndentListsOnlyUntilDepth(
+ json, std::string(indent, ' '), until_depth, 0);
+}
+
+#endif // INCLUDED_SRC_UTILS_CPP_JSON_HPP
diff --git a/src/utils/cpp/type_safe_arithmetic.hpp b/src/utils/cpp/type_safe_arithmetic.hpp
new file mode 100644
index 00000000..21bba0b5
--- /dev/null
+++ b/src/utils/cpp/type_safe_arithmetic.hpp
@@ -0,0 +1,197 @@
+#ifndef INCLUDED_SRC_UTILS_CPP_TYPE_SAFE_ARITHMETIC_HPP
+#define INCLUDED_SRC_UTILS_CPP_TYPE_SAFE_ARITHMETIC_HPP
+
+#include <limits>
+#include <type_traits>
+
+#include "gsl-lite/gsl-lite.hpp"
+
+/// \struct type_safe_arithmetic_tag
+/// \brief Abstract tag defining types and limits for custom arithmetic types.
+/// Usage example:
+/// struct my_type_tag : type_safe_arithmetic_tag<int, -2, +3> {};
+/// using my_type_t = type_safe_arithmetic<my_type_tag>;
+template <typename T,
+ T MIN_VALUE = std::numeric_limits<T>::lowest(),
+ T MAX_VALUE = std::numeric_limits<T>::max(),
+ T SMALLEST_VALUE = std::numeric_limits<T>::min()>
+struct type_safe_arithmetic_tag {
+ static_assert(std::is_arithmetic<T>::value,
+ "T must be an arithmetic type (integer or floating-point)");
+
+ using value_t = T;
+ using reference_t = T&;
+ using const_reference_t = T const&;
+ using pointer_t = T*;
+ using const_pointer_t = T const*;
+
+ static constexpr value_t max_value = MAX_VALUE;
+ static constexpr value_t min_value = MIN_VALUE;
+ static constexpr value_t smallest_value = SMALLEST_VALUE;
+};
+
+/// \class type_safe_arithmetic
+/// \brief Abstract class for defining custom arithmetic types.
+/// \tparam TAG The actual \ref type_safe_arithmetic_tag
+template <typename TAG>
+class type_safe_arithmetic {
+ typename TAG::value_t m_value{};
+
+ public:
+ using tag_t = TAG;
+ using value_t = typename tag_t::value_t;
+ using reference_t = typename tag_t::reference_t;
+ using const_reference_t = typename tag_t::const_reference_t;
+ using pointer_t = typename tag_t::pointer_t;
+ using const_pointer_t = typename tag_t::const_pointer_t;
+
+ static constexpr value_t max_value = tag_t::max_value;
+ static constexpr value_t min_value = tag_t::min_value;
+ static constexpr value_t smallest_value = tag_t::smallest_value;
+
+ constexpr type_safe_arithmetic() = default;
+
+ // NOLINTNEXTLINE
+ constexpr /*explicit*/ type_safe_arithmetic(value_t value) { set(value); }
+
+ type_safe_arithmetic(type_safe_arithmetic const&) = default;
+ type_safe_arithmetic(type_safe_arithmetic&&) noexcept = default;
+ auto operator=(type_safe_arithmetic const&)
+ -> type_safe_arithmetic& = default;
+ auto operator=(type_safe_arithmetic&&) noexcept
+ -> type_safe_arithmetic& = default;
+ ~type_safe_arithmetic() = default;
+
+ auto operator=(value_t value) -> type_safe_arithmetic& {
+ set(value);
+ return *this;
+ }
+
+ // NOLINTNEXTLINE
+ constexpr /*explicit*/ operator value_t() const { return m_value; }
+
+ constexpr auto get() const -> value_t { return m_value; }
+
+ constexpr void set(value_t value) {
+ gsl_Expects(value >= min_value && value <= max_value &&
+ "value output of range");
+ m_value = value;
+ }
+
+ auto pointer() const -> const_pointer_t { return &m_value; }
+};
+
+// template <typename TAG>
+// bool operator==(type_safe_arithmetic<TAG> lhs, type_safe_arithmetic<TAG> rhs)
+// {
+// return lhs.get() == rhs.get();
+// }
+//
+// template <typename TAG>
+// bool operator!=(type_safe_arithmetic<TAG> lhs, type_safe_arithmetic<TAG> rhs)
+// {
+// return !(lhs == rhs);
+// }
+//
+// template <typename TAG>
+// bool operator>(type_safe_arithmetic<TAG> lhs, type_safe_arithmetic<TAG> rhs)
+// {
+// return lhs.get() > rhs.get();
+// }
+//
+// template <typename TAG>
+// bool operator>=(type_safe_arithmetic<TAG> lhs, type_safe_arithmetic<TAG> rhs)
+// {
+// return lhs.get() >= rhs.get();
+// }
+//
+// template <typename TAG>
+// bool operator<(type_safe_arithmetic<TAG> lhs, type_safe_arithmetic<TAG> rhs)
+// {
+// return lhs.get() < rhs.get();
+// }
+//
+// template <typename TAG>
+// bool operator<=(type_safe_arithmetic<TAG> lhs, type_safe_arithmetic<TAG> rhs)
+// {
+// return lhs.get() <= rhs.get();
+// }
+//
+// template <typename TAG>
+// type_safe_arithmetic<TAG> operator+(type_safe_arithmetic<TAG> lhs,
+// type_safe_arithmetic<TAG> rhs) {
+// return type_safe_arithmetic<TAG>{lhs.get() + rhs.get()};
+// }
+
+template <typename TAG>
+auto operator+=(type_safe_arithmetic<TAG>& lhs, type_safe_arithmetic<TAG> rhs)
+ -> type_safe_arithmetic<TAG>& {
+ lhs.set(lhs.get() + rhs.get());
+ return lhs;
+}
+
+// template <typename TAG>
+// type_safe_arithmetic<TAG> operator-(type_safe_arithmetic<TAG> lhs,
+// type_safe_arithmetic<TAG> rhs) {
+// return type_safe_arithmetic<TAG>{lhs.get() - rhs.get()};
+// }
+//
+// template <typename TAG>
+// type_safe_arithmetic<TAG>& operator-=(type_safe_arithmetic<TAG>& lhs,
+// type_safe_arithmetic<TAG> rhs) {
+// lhs.set(lhs.get() - rhs.get());
+// return lhs;
+// }
+//
+// template <typename TAG>
+// type_safe_arithmetic<TAG> operator*(type_safe_arithmetic<TAG> lhs,
+// typename TAG::value_t rhs) {
+// return type_safe_arithmetic<TAG>{lhs.get() - rhs};
+// }
+//
+// template <typename TAG>
+// type_safe_arithmetic<TAG>& operator*=(type_safe_arithmetic<TAG>& lhs,
+// typename TAG::value_t rhs) {
+// lhs.set(lhs.get() * rhs);
+// return lhs;
+// }
+//
+// template <typename TAG>
+// type_safe_arithmetic<TAG> operator/(type_safe_arithmetic<TAG> lhs,
+// typename TAG::value_t rhs) {
+// return type_safe_arithmetic<TAG>{lhs.get() / rhs};
+// }
+//
+// template <typename TAG>
+// type_safe_arithmetic<TAG>& operator/=(type_safe_arithmetic<TAG>& lhs,
+// typename TAG::value_t rhs) {
+// lhs.set(lhs.get() / rhs);
+// return lhs;
+// }
+//
+// template <typename TAG>
+// type_safe_arithmetic<TAG>& operator++(type_safe_arithmetic<TAG>& a) {
+// return a += type_safe_arithmetic<TAG>{1};
+// }
+
+template <typename TAG>
+auto operator++(type_safe_arithmetic<TAG>& a, int)
+ -> type_safe_arithmetic<TAG> {
+ auto r = a;
+ a += type_safe_arithmetic<TAG>{1};
+ return r;
+}
+
+// template <typename TAG>
+// type_safe_arithmetic<TAG>& operator--(type_safe_arithmetic<TAG>& a) {
+// return a -= type_safe_arithmetic<TAG>{1};
+// }
+//
+// template <typename TAG>
+// type_safe_arithmetic<TAG> operator--(type_safe_arithmetic<TAG>& a, int) {
+// auto r = a;
+// a += type_safe_arithmetic<TAG>{1};
+// return r;
+// }
+
+#endif // INCLUDED_SRC_UTILS_CPP_TYPE_SAFE_ARITHMETIC_HPP