diff --git a/legacy/simulation_oop/core_operations.h b/legacy/simulation_oop/core_operations.h deleted file mode 100644 index 0926572905053cdf5c762f73545642f1ffe3d4f8..0000000000000000000000000000000000000000 --- a/legacy/simulation_oop/core_operations.h +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef ASIC_SIMULATION_CORE_OPERATIONS_H -#define ASIC_SIMULATION_CORE_OPERATIONS_H - -#define NOMINMAX -#include "../debug.h" -#include "../number.h" -#include "operation.h" - -#include <algorithm> -#include <cmath> -#include <cstddef> -#include <stdexcept> -#include <utility> - -namespace asic { - -class constant_operation final : public abstract_operation { -public: - constant_operation(result_key key, number value) - : abstract_operation(std::move(key)) - , m_value(value) {} - - [[nodiscard]] std::size_t output_count() const noexcept final { - return 1; - } - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const&) const final { - ASIC_DEBUG_MSG("Evaluating constant."); - return m_value; - } - - number m_value; -}; - -class addition_operation final : public binary_operation { -public: - explicit addition_operation(result_key key) - : binary_operation(std::move(key)) {} - - [[nodiscard]] std::size_t output_count() const noexcept final { - return 1; - } - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final { - ASIC_DEBUG_MSG("Evaluating addition."); - return this->evaluate_lhs(context) + this->evaluate_rhs(context); - } -}; - -class subtraction_operation final : public binary_operation { -public: - explicit subtraction_operation(result_key key) - : binary_operation(std::move(key)) {} - - [[nodiscard]] std::size_t output_count() const noexcept final { - return 1; - } - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final { - ASIC_DEBUG_MSG("Evaluating subtraction."); - return this->evaluate_lhs(context) - this->evaluate_rhs(context); - } -}; - -class multiplication_operation final : public binary_operation { -public: - explicit multiplication_operation(result_key key) - : binary_operation(std::move(key)) {} - - [[nodiscard]] std::size_t output_count() const noexcept final { - return 1; - } - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final { - ASIC_DEBUG_MSG("Evaluating multiplication."); - return this->evaluate_lhs(context) * this->evaluate_rhs(context); - } -}; - -class division_operation final : public binary_operation { -public: - explicit division_operation(result_key key) - : binary_operation(std::move(key)) {} - - [[nodiscard]] std::size_t output_count() const noexcept final { - return 1; - } - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final { - ASIC_DEBUG_MSG("Evaluating division."); - return this->evaluate_lhs(context) / this->evaluate_rhs(context); - } -}; - -class min_operation final : public binary_operation { -public: - explicit min_operation(result_key key) - : binary_operation(std::move(key)) {} - - [[nodiscard]] std::size_t output_count() const noexcept final { - return 1; - } - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final { - ASIC_DEBUG_MSG("Evaluating min."); - auto const lhs = this->evaluate_lhs(context); - if (lhs.imag() != 0) { - throw std::runtime_error{"Min does not support complex numbers."}; - } - auto const rhs = this->evaluate_rhs(context); - if (rhs.imag() != 0) { - throw std::runtime_error{"Min does not support complex numbers."}; - } - return std::min(lhs.real(), rhs.real()); - } -}; - -class max_operation final : public binary_operation { -public: - explicit max_operation(result_key key) - : binary_operation(std::move(key)) {} - - [[nodiscard]] std::size_t output_count() const noexcept final { - return 1; - } - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final { - ASIC_DEBUG_MSG("Evaluating max."); - auto const lhs = this->evaluate_lhs(context); - if (lhs.imag() != 0) { - throw std::runtime_error{"Max does not support complex numbers."}; - } - auto const rhs = this->evaluate_rhs(context); - if (rhs.imag() != 0) { - throw std::runtime_error{"Max does not support complex numbers."}; - } - return std::max(lhs.real(), rhs.real()); - } -}; - -class square_root_operation final : public unary_operation { -public: - explicit square_root_operation(result_key key) - : unary_operation(std::move(key)) {} - - [[nodiscard]] std::size_t output_count() const noexcept final { - return 1; - } - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final { - ASIC_DEBUG_MSG("Evaluating sqrt."); - return std::sqrt(this->evaluate_input(context)); - } -}; - -class complex_conjugate_operation final : public unary_operation { -public: - explicit complex_conjugate_operation(result_key key) - : unary_operation(std::move(key)) {} - - [[nodiscard]] std::size_t output_count() const noexcept final { - return 1; - } - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final { - ASIC_DEBUG_MSG("Evaluating conj."); - return std::conj(this->evaluate_input(context)); - } -}; - -class absolute_operation final : public unary_operation { -public: - explicit absolute_operation(result_key key) - : unary_operation(std::move(key)) {} - - [[nodiscard]] std::size_t output_count() const noexcept final { - return 1; - } - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final { - ASIC_DEBUG_MSG("Evaluating abs."); - return std::abs(this->evaluate_input(context)); - } -}; - -class constant_multiplication_operation final : public unary_operation { -public: - constant_multiplication_operation(result_key key, number value) - : unary_operation(std::move(key)) - , m_value(value) {} - - [[nodiscard]] std::size_t output_count() const noexcept final { - return 1; - } - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final { - ASIC_DEBUG_MSG("Evaluating cmul."); - return this->evaluate_input(context) * m_value; - } - - number m_value; -}; - -class butterfly_operation final : public binary_operation { -public: - explicit butterfly_operation(result_key key) - : binary_operation(std::move(key)) {} - - [[nodiscard]] std::size_t output_count() const noexcept final { - return 2; - } - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t index, evaluation_context const& context) const final { - ASIC_DEBUG_MSG("Evaluating bfly."); - if (index == 0) { - return this->evaluate_lhs(context) + this->evaluate_rhs(context); - } - return this->evaluate_lhs(context) - this->evaluate_rhs(context); - } -}; - -} // namespace asic - -#endif // ASIC_SIMULATION_CORE_OPERATIONS_H \ No newline at end of file diff --git a/legacy/simulation_oop/custom_operation.h b/legacy/simulation_oop/custom_operation.h deleted file mode 100644 index 8a11aaacbc8c17500069522d9d8f56d9c416d804..0000000000000000000000000000000000000000 --- a/legacy/simulation_oop/custom_operation.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef ASIC_SIMULATION_CUSTOM_OPERATION_H -#define ASIC_SIMULATION_CUSTOM_OPERATION_H - -#include "../algorithm.h" -#include "../debug.h" -#include "../number.h" -#include "operation.h" - -#include <cstddef> -#include <fmt/format.h> -#include <functional> -#include <pybind11/pybind11.h> -#include <stdexcept> -#include <utility> - -namespace asic { - -class custom_operation final : public nary_operation { -public: - custom_operation(result_key key, pybind11::object evaluate_output, pybind11::object truncate_input, std::size_t output_count); - - [[nodiscard]] std::size_t output_count() const noexcept final; - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t index, evaluation_context const& context) const final; - [[nodiscard]] number truncate_input(std::size_t index, number value, std::size_t bits) const final; - - pybind11::object m_evaluate_output; - pybind11::object m_truncate_input; - std::size_t m_output_count; -}; - -} // namespace asic - -#endif // ASIC_SIMULATION_CUSTOM_OPERATION_H \ No newline at end of file diff --git a/legacy/simulation_oop/operation.h b/legacy/simulation_oop/operation.h deleted file mode 100644 index 344eacc1482c40021b3d0ff686cbef5c71085f58..0000000000000000000000000000000000000000 --- a/legacy/simulation_oop/operation.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef ASIC_SIMULATION_OPERATION_H -#define ASIC_SIMULATION_OPERATION_H - -#include "../number.h" -#include "../span.h" - -#include <cstddef> -#include <cstdint> -#include <fmt/format.h> -#include <memory> -#include <optional> -#include <stdexcept> -#include <string> -#include <unordered_map> -#include <utility> -#include <vector> - -namespace asic { - -class operation; -class signal_source; - -using result_key = std::string; -using result_map = std::unordered_map<result_key, std::optional<number>>; -using delay_map = std::unordered_map<result_key, number>; -using delay_queue = std::vector<std::pair<result_key, signal_source const*>>; - -struct evaluation_context final { - result_map* results; - delay_map* delays; - delay_queue* deferred_delays; - std::optional<std::size_t> bits_override; - bool truncate; -}; - -class signal_source final { -public: - signal_source() noexcept = default; - signal_source(std::shared_ptr<const operation> op, std::size_t index, std::optional<std::size_t> bits); - - [[nodiscard]] explicit operator bool() const noexcept; - - [[nodiscard]] std::optional<number> current_output(delay_map const& delays) const; - [[nodiscard]] number evaluate_output(evaluation_context const& context) const; - - [[nodiscard]] std::optional<std::size_t> bits() const noexcept; - -private: - std::shared_ptr<const operation> m_operation; - std::size_t m_index = 0; - std::optional<std::size_t> m_bits; -}; - -class operation { -public: - virtual ~operation() = default; - [[nodiscard]] virtual std::size_t output_count() const noexcept = 0; - [[nodiscard]] virtual std::optional<number> current_output(std::size_t index, delay_map const& delays) const = 0; - [[nodiscard]] virtual number evaluate_output(std::size_t index, evaluation_context const& context) const = 0; -}; - -class abstract_operation : public operation { -public: - explicit abstract_operation(result_key key); - virtual ~abstract_operation() = default; - - [[nodiscard]] std::optional<number> current_output(std::size_t, delay_map const&) const override; - [[nodiscard]] number evaluate_output(std::size_t index, evaluation_context const& context) const override; - -protected: - [[nodiscard]] virtual number evaluate_output_impl(std::size_t index, evaluation_context const& context) const = 0; - [[nodiscard]] virtual number truncate_input(std::size_t index, number value, std::size_t bits) const; - - [[nodiscard]] result_key const& key_base() const; - [[nodiscard]] result_key key_of_output(std::size_t index) const; - -private: - result_key m_key; -}; - -class unary_operation : public abstract_operation { -public: - explicit unary_operation(result_key key); - virtual ~unary_operation() = default; - - void connect(signal_source in); - -protected: - [[nodiscard]] bool connected() const noexcept; - [[nodiscard]] signal_source const& input() const noexcept; - [[nodiscard]] number evaluate_input(evaluation_context const& context) const; - -private: - signal_source m_in; -}; - -class binary_operation : public abstract_operation { -public: - explicit binary_operation(result_key key); - virtual ~binary_operation() = default; - - void connect(signal_source lhs, signal_source rhs); - -protected: - [[nodiscard]] signal_source const& lhs() const noexcept; - [[nodiscard]] signal_source const& rhs() const noexcept; - [[nodiscard]] number evaluate_lhs(evaluation_context const& context) const; - [[nodiscard]] number evaluate_rhs(evaluation_context const& context) const; - -private: - signal_source m_lhs; - signal_source m_rhs; -}; - -class nary_operation : public abstract_operation { -public: - explicit nary_operation(result_key key); - virtual ~nary_operation() = default; - - void connect(std::vector<signal_source> inputs); - -protected: - [[nodiscard]] span<signal_source const> inputs() const noexcept; - [[nodiscard]] std::vector<number> evaluate_inputs(evaluation_context const& context) const; - -private: - std::vector<signal_source> m_inputs; -}; - -} // namespace asic - -#endif // ASIC_SIMULATION_OPERATION_H \ No newline at end of file diff --git a/legacy/simulation_oop/signal_flow_graph.h b/legacy/simulation_oop/signal_flow_graph.h deleted file mode 100644 index f06788249e367d3e8e0602f04c6dcf91c71b7a96..0000000000000000000000000000000000000000 --- a/legacy/simulation_oop/signal_flow_graph.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef ASIC_SIMULATION_SIGNAL_FLOW_GRAPH_H -#define ASIC_SIMULATION_SIGNAL_FLOW_GRAPH_H - -#include "../algorithm.h" -#include "../debug.h" -#include "../number.h" -#include "core_operations.h" -#include "custom_operation.h" -#include "operation.h" -#include "special_operations.h" - -#include <Python.h> -#include <cstddef> -#include <fmt/format.h> -#include <functional> -#include <memory> -#include <pybind11/pybind11.h> -#include <stdexcept> -#include <string_view> -#include <unordered_map> -#include <utility> -#include <vector> - -namespace asic { - -class signal_flow_graph_operation final : public abstract_operation { -public: - using added_operation_cache = std::unordered_map<PyObject const*, std::shared_ptr<operation>>; - - signal_flow_graph_operation(result_key key); - - void create(pybind11::handle sfg, added_operation_cache& added); - - [[nodiscard]] std::vector<std::shared_ptr<input_operation>> const& inputs() noexcept; - [[nodiscard]] std::size_t output_count() const noexcept final; - - [[nodiscard]] number evaluate_output(std::size_t index, evaluation_context const& context) const final; - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t index, evaluation_context const& context) const final; - - [[nodiscard]] static signal_source make_source(pybind11::handle op, std::size_t input_index, added_operation_cache& added, - std::string_view prefix); - - template <typename Operation, typename... Args> - [[nodiscard]] static std::shared_ptr<Operation> add_operation(pybind11::handle op, added_operation_cache& added, Args&&... args) { - return std::static_pointer_cast<Operation>( - added.try_emplace(op.ptr(), std::make_shared<Operation>(std::forward<Args>(args)...)).first->second); - } - - template <typename Operation, typename... Args> - [[nodiscard]] static std::shared_ptr<Operation> add_unary_operation(pybind11::handle op, added_operation_cache& added, - std::string_view prefix, Args&&... args) { - auto const new_op = add_operation<Operation>(op, added, std::forward<Args>(args)...); - new_op->connect(make_source(op, 0, added, prefix)); - return new_op; - } - - template <typename Operation, typename... Args> - [[nodiscard]] static std::shared_ptr<Operation> add_binary_operation(pybind11::handle op, added_operation_cache& added, - std::string_view prefix, Args&&... args) { - auto const new_op = add_operation<Operation>(op, added, std::forward<Args>(args)...); - new_op->connect(make_source(op, 0, added, prefix), make_source(op, 1, added, prefix)); - return new_op; - } - - [[nodiscard]] static std::shared_ptr<operation> add_signal_flow_graph_operation(pybind11::handle sfg, added_operation_cache& added, - std::string_view prefix, result_key key); - - [[nodiscard]] static std::shared_ptr<custom_operation> add_custom_operation(pybind11::handle op, added_operation_cache& added, - std::string_view prefix, result_key key); - - [[nodiscard]] static std::shared_ptr<operation> make_operation(pybind11::handle op, added_operation_cache& added, - std::string_view prefix); - - std::vector<output_operation> m_output_operations; - std::vector<std::shared_ptr<input_operation>> m_input_operations; -}; - -} // namespace asic - -#endif // ASIC_SIMULATION_SIGNAL_FLOW_GRAPH_H \ No newline at end of file diff --git a/legacy/simulation_oop/simulation.h b/legacy/simulation_oop/simulation.h deleted file mode 100644 index 38e2771b877772bd28048cae16d791bb4e0b45e3..0000000000000000000000000000000000000000 --- a/legacy/simulation_oop/simulation.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef ASIC_SIMULATION_OOP_H -#define ASIC_SIMULATION_OOP_H - -#include "../number.h" -#include "core_operations.h" -#include "custom_operation.h" -#include "operation.h" -#include "signal_flow_graph.h" -#include "special_operations.h" - -#include <cstddef> -#include <cstdint> -#include <fmt/format.h> -#include <functional> -#include <limits> -#include <memory> -#include <optional> -#include <pybind11/functional.h> -#include <pybind11/numpy.h> -#include <pybind11/pybind11.h> -#include <pybind11/stl.h> -#include <string_view> -#include <unordered_map> -#include <utility> -#include <variant> -#include <vector> - -namespace asic { - -using iteration_t = std::uint32_t; -using result_array_map = std::unordered_map<std::string, std::vector<number>>; -using input_function_t = std::function<number(iteration_t)>; -using input_provider_t = std::variant<number, std::vector<number>, input_function_t>; - -class simulation final { -public: - simulation(pybind11::handle sfg, std::optional<std::vector<std::optional<input_provider_t>>> input_providers = std::nullopt); - - void set_input(std::size_t index, input_provider_t input_provider); - void set_inputs(std::vector<std::optional<input_provider_t>> input_providers); - - [[nodiscard]] std::vector<number> step(bool save_results, std::optional<std::size_t> bits_override, bool truncate); - [[nodiscard]] std::vector<number> run_until(iteration_t iteration, bool save_results, std::optional<std::size_t> bits_override, - bool truncate); - [[nodiscard]] std::vector<number> run_for(iteration_t iterations, bool save_results, std::optional<std::size_t> bits_override, - bool truncate); - [[nodiscard]] std::vector<number> run(bool save_results, std::optional<std::size_t> bits_override, bool truncate); - - [[nodiscard]] iteration_t iteration() const noexcept; - [[nodiscard]] pybind11::dict results() const noexcept; - - void clear_results() noexcept; - void clear_state() noexcept; - -private: - signal_flow_graph_operation m_sfg; - result_array_map m_results; - delay_map m_delays; - iteration_t m_iteration = 0; - std::vector<input_function_t> m_input_functions; - std::optional<iteration_t> m_input_length; -}; - -} // namespace asic - -#endif // ASIC_SIMULATION_OOP_H \ No newline at end of file diff --git a/legacy/simulation_oop/special_operations.h b/legacy/simulation_oop/special_operations.h deleted file mode 100644 index 88fb087e84378e36f423364d2c7d83a083828784..0000000000000000000000000000000000000000 --- a/legacy/simulation_oop/special_operations.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef ASIC_SIMULATION_SPECIAL_OPERATIONS_H -#define ASIC_SIMULATION_SPECIAL_OPERATIONS_H - -#include "../debug.h" -#include "../number.h" -#include "operation.h" - -#include <cassert> -#include <cstddef> -#include <utility> - -namespace asic { - -class input_operation final : public unary_operation { -public: - explicit input_operation(result_key key); - - [[nodiscard]] std::size_t output_count() const noexcept final; - [[nodiscard]] number value() const noexcept; - void value(number value) noexcept; - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t index, evaluation_context const& context) const final; - - number m_value{}; -}; - -class output_operation final : public unary_operation { -public: - explicit output_operation(result_key key); - - [[nodiscard]] std::size_t output_count() const noexcept final; - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t index, evaluation_context const& context) const final; -}; - -class delay_operation final : public unary_operation { -public: - delay_operation(result_key key, number initial_value); - - [[nodiscard]] std::size_t output_count() const noexcept final; - - [[nodiscard]] std::optional<number> current_output(std::size_t index, delay_map const& delays) const final; - [[nodiscard]] number evaluate_output(std::size_t index, evaluation_context const& context) const final; - -private: - [[nodiscard]] number evaluate_output_impl(std::size_t index, evaluation_context const& context) const final; - - number m_initial_value; -}; - -} // namespace asic - -#endif // ASIC_SIMULATION_SPECIAL_OPERATIONS_H \ No newline at end of file diff --git a/src/algorithm.h b/src/algorithm.h deleted file mode 100644 index c86275d1c4ef09a525372d38a4c07a0beb11e8c4..0000000000000000000000000000000000000000 --- a/src/algorithm.h +++ /dev/null @@ -1,325 +0,0 @@ -#ifndef ASIC_ALGORITHM_H -#define ASIC_ALGORITHM_H - -#include <cstddef> -#include <iterator> -#include <memory> -#include <type_traits> -#include <utility> - -namespace asic { -namespace detail { - -template <typename Reference> -class arrow_proxy final { -public: - template <typename Ref> - constexpr explicit arrow_proxy(Ref&& r) : m_r(std::forward<Ref>(r)) {} - - Reference* operator->() { - return std::addressof(m_r); - } - -private: - Reference m_r; -}; - -template <typename T> -struct range_view final { - class iterator final { - public: - using difference_type = std::ptrdiff_t; - using value_type = T const; - using reference = value_type&; - using pointer = value_type*; - using iterator_category = std::random_access_iterator_tag; - - constexpr iterator() noexcept = default; - constexpr explicit iterator(T value) noexcept : m_value(value) {} - - [[nodiscard]] constexpr bool operator==(iterator const& other) const noexcept { - return m_value == other.m_value; - } - - [[nodiscard]] constexpr bool operator!=(iterator const& other) const noexcept { - return m_value != other.m_value; - } - - [[nodiscard]] constexpr bool operator<(iterator const& other) const noexcept { - return m_value < other.m_value; - } - - [[nodiscard]] constexpr bool operator>(iterator const& other) const noexcept { - return m_value > other.m_value; - } - - [[nodiscard]] constexpr bool operator<=(iterator const& other) const noexcept { - return m_value <= other.m_value; - } - - [[nodiscard]] constexpr bool operator>=(iterator const& other) const noexcept { - return m_value >= other.m_value; - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return m_value; - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return std::addressof(**this); - } - - constexpr iterator& operator++() noexcept { - ++m_value; - return *this; - } - - constexpr iterator operator++(int) noexcept { - return iterator{m_value++}; - } - - constexpr iterator& operator--() noexcept { - --m_value; - return *this; - } - - constexpr iterator operator--(int) noexcept { - return iterator{m_value--}; - } - - constexpr iterator& operator+=(difference_type n) noexcept { - m_value += n; - return *this; - } - - constexpr iterator& operator-=(difference_type n) noexcept { - m_value -= n; - return *this; - } - - [[nodiscard]] constexpr T operator[](difference_type n) noexcept { - return m_value + static_cast<T>(n); - } - - [[nodiscard]] constexpr friend iterator operator+(iterator const& lhs, difference_type rhs) noexcept { - return iterator{lhs.m_value + rhs}; - } - - [[nodiscard]] constexpr friend iterator operator+(difference_type lhs, iterator const& rhs) noexcept { - return iterator{lhs + rhs.m_value}; - } - - [[nodiscard]] constexpr friend iterator operator-(iterator const& lhs, difference_type rhs) noexcept { - return iterator{lhs.m_value - rhs}; - } - - [[nodiscard]] constexpr friend difference_type operator-(iterator const& lhs, iterator const& rhs) noexcept { - return static_cast<difference_type>(lhs.m_value - rhs.m_value); - } - - private: - T m_value{}; - }; - - using sentinel = iterator; - - template <typename First, typename Last> - constexpr range_view(First&& first, Last&& last) noexcept : m_begin(std::forward<First>(first)), m_end(std::forward<Last>(last)) {} - - [[nodiscard]] constexpr iterator begin() const noexcept { - return m_begin; - } - [[nodiscard]] constexpr sentinel end() const noexcept { - return m_end; - } - - iterator m_begin; - sentinel m_end; -}; - -template <typename Range, typename Iterator, typename Sentinel> -struct enumerate_view final { - using sentinel = Sentinel; - - class iterator final { - public: - using difference_type = typename std::iterator_traits<Iterator>::difference_type; - using value_type = typename std::iterator_traits<Iterator>::value_type; - using reference = std::pair<std::size_t const&, decltype(*std::declval<Iterator const>())>; - using pointer = arrow_proxy<reference>; - using iterator_category = - std::common_type_t<typename std::iterator_traits<Iterator>::iterator_category, std::bidirectional_iterator_tag>; - - constexpr iterator() = default; - - constexpr iterator(Iterator it, std::size_t index) : m_it(std::move(it)), m_index(index) {} - - [[nodiscard]] constexpr bool operator==(iterator const& other) const { - return m_it == other.m_it; - } - - [[nodiscard]] constexpr bool operator!=(iterator const& other) const { - return m_it != other.m_it; - } - - [[nodiscard]] constexpr bool operator==(sentinel const& other) const { - return m_it == other; - } - - [[nodiscard]] constexpr bool operator!=(sentinel const& other) const { - return m_it != other; - } - - [[nodiscard]] constexpr reference operator*() const { - return reference{m_index, *m_it}; - } - - [[nodiscard]] constexpr pointer operator->() const { - return pointer{**this}; - } - - constexpr iterator& operator++() { - ++m_it; - ++m_index; - return *this; - } - - constexpr iterator operator++(int) { - return iterator{m_it++, m_index++}; - } - - constexpr iterator& operator--() { - --m_it; - --m_index; - return *this; - } - - constexpr iterator operator--(int) { - return iterator{m_it--, m_index--}; - } - - private: - Iterator m_it; - std::size_t m_index = 0; - }; - - constexpr iterator begin() const { - return iterator{std::begin(m_range), 0}; - } - - constexpr sentinel end() const { - return std::end(m_range); - } - - Range m_range; -}; - -template <typename Range1, typename Range2, typename Iterator1, typename Iterator2, typename Sentinel1, typename Sentinel2> -struct zip_view final { - using sentinel = std::pair<Sentinel1, Sentinel2>; - - class iterator final { - public: - using difference_type = std::common_type_t<typename std::iterator_traits<Iterator1>::difference_type, - typename std::iterator_traits<Iterator2>::difference_type>; - using value_type = - std::pair<typename std::iterator_traits<Iterator1>::value_type, typename std::iterator_traits<Iterator2>::value_type>; - using reference = std::pair<decltype(*std::declval<Iterator1 const>()), decltype(*std::declval<Iterator2 const>())>; - using pointer = arrow_proxy<reference>; - using iterator_category = std::common_type_t<typename std::iterator_traits<Iterator1>::iterator_category, - typename std::iterator_traits<Iterator2>::iterator_category, std::bidirectional_iterator_tag>; - - constexpr iterator() = default; - - constexpr iterator(Iterator1 it1, Iterator2 it2) : m_it1(std::move(it1)), m_it2(std::move(it2)) {} - - [[nodiscard]] constexpr bool operator==(iterator const& other) const { - return m_it1 == other.m_it1 && m_it2 == other.m_it2; - } - - [[nodiscard]] constexpr bool operator!=(iterator const& other) const { - return !(*this == other); - } - - [[nodiscard]] constexpr bool operator==(sentinel const& other) const { - return m_it1 == other.first || m_it2 == other.second; - } - - [[nodiscard]] constexpr bool operator!=(sentinel const& other) const { - return !(*this == other); - } - - [[nodiscard]] constexpr reference operator*() const { - return reference{*m_it1, *m_it2}; - } - - [[nodiscard]] constexpr pointer operator->() const { - return pointer{**this}; - } - - constexpr iterator& operator++() { - ++m_it1; - ++m_it2; - return *this; - } - - constexpr iterator operator++(int) { - return iterator{m_it1++, m_it2++}; - } - - constexpr iterator& operator--() { - --m_it1; - --m_it2; - return *this; - } - - constexpr iterator operator--(int) { - return iterator{m_it1--, m_it2--}; - } - - private: - Iterator1 m_it1; - Iterator2 m_it2; - }; - - constexpr iterator begin() const { - return iterator{std::begin(m_range1), std::begin(m_range2)}; - } - - constexpr sentinel end() const { - return sentinel{std::end(m_range1), std::end(m_range2)}; - } - - Range1 m_range1; - Range2 m_range2; -}; - -} // namespace detail - -template <typename First, typename Last, typename T = std::remove_cv_t<std::remove_reference_t<First>>> -[[nodiscard]] constexpr auto range(First&& first, Last&& last) { - return detail::range_view<T>{std::forward<First>(first), std::forward<Last>(last)}; -} - -template <typename Last, typename T = std::remove_cv_t<std::remove_reference_t<Last>>> -[[nodiscard]] constexpr auto range(Last&& last) { - return detail::range_view<T>{T{}, std::forward<Last>(last)}; -} - -template <typename Range, typename Iterator = decltype(std::begin(std::declval<Range>())), - typename Sentinel = decltype(std::end(std::declval<Range>()))> -[[nodiscard]] constexpr auto enumerate(Range&& range) { - return detail::enumerate_view<Range, Iterator, Sentinel>{std::forward<Range>(range)}; -} - -template <typename Range1, typename Range2, typename Iterator1 = decltype(std::begin(std::declval<Range1>())), - typename Iterator2 = decltype(std::begin(std::declval<Range2>())), typename Sentinel1 = decltype(std::end(std::declval<Range1>())), - typename Sentinel2 = decltype(std::end(std::declval<Range2>()))> -[[nodiscard]] constexpr auto zip(Range1&& range1, Range2&& range2) { - return detail::zip_view<Range1, Range2, Iterator1, Iterator2, Sentinel1, Sentinel2>{ - std::forward<Range1>(range1), std::forward<Range2>(range2)}; -} - -} // namespace asic - -#endif // ASIC_ALGORITHM_H \ No newline at end of file diff --git a/src/debug.h b/src/debug.h deleted file mode 100644 index a11aa057db644dbe2d29399398a1f48ca599876f..0000000000000000000000000000000000000000 --- a/src/debug.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef ASIC_DEBUG_H -#define ASIC_DEBUG_H - -#ifndef NDEBUG -#define ASIC_ENABLE_DEBUG_LOGGING 1 -#define ASIC_ENABLE_ASSERTS 1 -#else -#define ASIC_ENABLE_DEBUG_LOGGING 0 -#define ASIC_ENABLE_ASSERTS 0 -#endif // NDEBUG - -#if ASIC_ENABLE_DEBUG_LOGGING -#include <filesystem> -#include <fmt/format.h> -#include <fstream> -#include <ostream> -#include <string_view> -#include <utility> -#endif // ASIC_ENABLE_DEBUG_LOGGING - -#if ASIC_ENABLE_ASSERTS -#include <filesystem> -#include <cstdlib> -#include <cstdio> -#include <string_view> -#include <fmt/format.h> -#endif // ASIC_ENABLE_ASSERTS - -namespace asic { - -constexpr auto debug_log_filename = "_b_asic_debug_log.txt"; - -namespace detail { - -#if ASIC_ENABLE_DEBUG_LOGGING -inline void log_debug_msg_string(std::string_view file, int line, std::string_view string) { - static auto log_file = std::ofstream{debug_log_filename, std::ios::trunc}; - log_file << fmt::format("{:<40}: {}", fmt::format("{}:{}", std::filesystem::path{file}.filename().generic_string(), line), string) - << std::endl; -} - -template <typename Format, typename... Args> -inline void log_debug_msg(std::string_view file, int line, Format&& format, Args&&... args) { - log_debug_msg_string(file, line, fmt::format(std::forward<Format>(format), std::forward<Args>(args)...)); -} -#endif // ASIC_ENABLE_DEBUG_LOGGING - -#if ASIC_ENABLE_ASSERTS -inline void fail_assert(std::string_view file, int line, std::string_view condition_string) { -#if ASIC_ENABLE_DEBUG_LOGGING - log_debug_msg(file, line, "Assertion failed: {}", condition_string); -#endif // ASIC_ENABLE_DEBUG_LOGGING - fmt::print(stderr, "{}:{}: Assertion failed: {}\n", std::filesystem::path{file}.filename().generic_string(), line, condition_string); - std::abort(); -} - -template <typename BoolConvertible> -inline void check_assert(std::string_view file, int line, std::string_view condition_string, BoolConvertible&& condition) { - if (!static_cast<bool>(condition)) { - fail_assert(file, line, condition_string); - } -} -#endif // ASIC_ENABLE_ASSERTS - -} // namespace detail -} // namespace asic - -#if ASIC_ENABLE_DEBUG_LOGGING -#define ASIC_DEBUG_MSG(...) (asic::detail::log_debug_msg(__FILE__, __LINE__, __VA_ARGS__)) -#else -#define ASIC_DEBUG_MSG(...) ((void)0) -#endif // ASIC_ENABLE_DEBUG_LOGGING - -#if ASIC_ENABLE_ASSERTS -#define ASIC_ASSERT(condition) (asic::detail::check_assert(__FILE__, __LINE__, #condition, (condition))) -#else -#define ASIC_ASSERT(condition) ((void)0) -#endif - -#endif // ASIC_DEBUG_H \ No newline at end of file diff --git a/src/number.h b/src/number.h deleted file mode 100644 index 9cb5b42f53be4eb0cfcc86d00be65005147384e2..0000000000000000000000000000000000000000 --- a/src/number.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef ASIC_NUMBER_H -#define ASIC_NUMBER_H - -#include <complex> -#include <pybind11/complex.h> - -namespace asic { - -using number = std::complex<double>; - -} // namespace asic - -#endif // ASIC_NUMBER_H \ No newline at end of file diff --git a/src/simulation.h b/src/simulation.h deleted file mode 100644 index aefa3a4e92b861b9c7b795c7301f900dc54ace6f..0000000000000000000000000000000000000000 --- a/src/simulation.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef ASIC_SIMULATION_H -#define ASIC_SIMULATION_H - -#include <pybind11/pybind11.h> - -namespace asic { - -void define_simulation_class(pybind11::module& module); - -} // namespace asic - -#endif // ASIC_SIMULATION_H \ No newline at end of file diff --git a/src/simulation/compile.h b/src/simulation/compile.h deleted file mode 100644 index 883f4c5832978ea1bfd33c767fc947c1efde718e..0000000000000000000000000000000000000000 --- a/src/simulation/compile.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef ASIC_SIMULATION_COMPILE_H -#define ASIC_SIMULATION_COMPILE_H - -#include "instruction.h" - -#include <cstddef> -#include <pybind11/pybind11.h> -#include <string> -#include <vector> - -namespace asic { - -using result_key = std::string; - -struct simulation_code final { - struct custom_operation final { - // Python function used to evaluate the custom operation. - pybind11::object evaluate_output; - // Number of inputs that the custom operation takes. - std::size_t input_count; - // Number of outputs that the custom operation gives. - std::size_t output_count; - }; - - struct custom_source final { - // Index into custom_operations where the custom_operation corresponding to this custom_source is located. - std::size_t custom_operation_index; - // Output index of the custom_operation that this source gets it value from. - std::size_t output_index; - }; - - struct delay_info final { - // Initial value to set at the start of the simulation. - number initial_value; - // The result index where the current value should be stored at the start of each iteration. - result_index_t result_index; - }; - - // Instructions to execute for one full iteration of the simulation. - std::vector<instruction> instructions; - // Custom operations used by the simulation. - std::vector<custom_operation> custom_operations; - // Signal sources that use custom operations. - std::vector<custom_source> custom_sources; - // Info about the delay operations used in the simulation. - std::vector<delay_info> delays; - // Keys for each result produced by the simulation. The index of the key matches the index of the result in the simulation state. - std::vector<result_key> result_keys; - // Number of values expected as input to the simulation. - std::size_t input_count; - // Number of values given as output from the simulation. This will be the number of values left on the stack after a full iteration of the simulation has been run. - std::size_t output_count; - // Maximum number of values that need to be able to fit on the stack in order to run a full iteration of the simulation. - std::size_t required_stack_size; -}; - -[[nodiscard]] simulation_code compile_simulation(pybind11::handle sfg); - -} // namespace asic - -#endif // ASIC_SIMULATION_COMPILE_H \ No newline at end of file diff --git a/src/simulation/format_code.h b/src/simulation/format_code.h deleted file mode 100644 index 5ebbb95d1f11eb18b915dbab9fbccbb82d83304c..0000000000000000000000000000000000000000 --- a/src/simulation/format_code.h +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef ASIC_SIMULATION_FORMAT_CODE_H -#define ASIC_SIMULATION_FORMAT_CODE_H - -#include "../algorithm.h" -#include "../debug.h" -#include "../number.h" -#include "compile.h" -#include "instruction.h" - -#include <fmt/format.h> -#include <string> - -namespace asic { - -[[nodiscard]] inline std::string format_number(number const& value) { - if (value.imag() == 0) { - return fmt::to_string(value.real()); - } - if (value.real() == 0) { - return fmt::format("{}j", value.imag()); - } - if (value.imag() < 0) { - return fmt::format("{}-{}j", value.real(), -value.imag()); - } - return fmt::format("{}+{}j", value.real(), value.imag()); -} - -[[nodiscard]] inline std::string format_compiled_simulation_code_result_keys(simulation_code const& code) { - auto result = std::string{}; - for (auto const& [i, result_key] : enumerate(code.result_keys)) { - result += fmt::format("{:>2}: \"{}\"\n", i, result_key); - } - return result; -} - -[[nodiscard]] inline std::string format_compiled_simulation_code_delays(simulation_code const& code) { - auto result = std::string{}; - for (auto const& [i, delay] : enumerate(code.delays)) { - ASIC_ASSERT(delay.result_index < code.result_keys.size()); - result += fmt::format("{:>2}: Initial value: {}, Result: {}: \"{}\"\n", - i, - format_number(delay.initial_value), - delay.result_index, - code.result_keys[delay.result_index]); - } - return result; -} - -[[nodiscard]] inline std::string format_compiled_simulation_code_instruction(instruction const& instruction) { - switch (instruction.type) { - // clang-format off - case instruction_type::push_input: return fmt::format("push_input inputs[{}]", instruction.index); - case instruction_type::push_result: return fmt::format("push_result results[{}]", instruction.index); - case instruction_type::push_delay: return fmt::format("push_delay delays[{}]", instruction.index); - case instruction_type::push_constant: return fmt::format("push_constant {}", format_number(instruction.value)); - case instruction_type::truncate: return fmt::format("truncate {:#018x}", instruction.bit_mask); - case instruction_type::addition: return "addition"; - case instruction_type::subtraction: return "subtraction"; - case instruction_type::multiplication: return "multiplication"; - case instruction_type::division: return "division"; - case instruction_type::min: return "min"; - case instruction_type::max: return "max"; - case instruction_type::square_root: return "square_root"; - case instruction_type::complex_conjugate: return "complex_conjugate"; - case instruction_type::absolute: return "absolute"; - case instruction_type::constant_multiplication: return fmt::format("constant_multiplication {}", format_number(instruction.value)); - case instruction_type::update_delay: return fmt::format("update_delay delays[{}]", instruction.index); - case instruction_type::custom: return fmt::format("custom custom_sources[{}]", instruction.index); - case instruction_type::forward_value: return "forward_value"; - // clang-format on - } - return std::string{}; -} - -[[nodiscard]] inline std::string format_compiled_simulation_code_instructions(simulation_code const& code) { - auto result = std::string{}; - for (auto const& [i, instruction] : enumerate(code.instructions)) { - auto instruction_string = format_compiled_simulation_code_instruction(instruction); - if (instruction.result_index < code.result_keys.size()) { - instruction_string = fmt::format( - "{:<26} -> {}: \"{}\"", instruction_string, instruction.result_index, code.result_keys[instruction.result_index]); - } - result += fmt::format("{:>2}: {}\n", i, instruction_string); - } - return result; -} - -[[nodiscard]] inline std::string format_compiled_simulation_code(simulation_code const& code) { - return fmt::format( - "==============================================\n" - "> Code stats\n" - "==============================================\n" - "Input count: {}\n" - "Output count: {}\n" - "Instruction count: {}\n" - "Required stack size: {}\n" - "Delay count: {}\n" - "Result count: {}\n" - "Custom operation count: {}\n" - "Custom source count: {}\n" - "==============================================\n" - "> Delays\n" - "==============================================\n" - "{}" - "==============================================\n" - "> Result keys\n" - "==============================================\n" - "{}" - "==============================================\n" - "> Instructions\n" - "==============================================\n" - "{}" - "==============================================", - code.input_count, - code.output_count, - code.instructions.size(), - code.required_stack_size, - code.delays.size(), - code.result_keys.size(), - code.custom_operations.size(), - code.custom_sources.size(), - format_compiled_simulation_code_delays(code), - format_compiled_simulation_code_result_keys(code), - format_compiled_simulation_code_instructions(code)); -} - -} // namespace asic - -#endif // ASIC_SIMULATION_FORMAT_CODE \ No newline at end of file diff --git a/src/simulation/instruction.h b/src/simulation/instruction.h deleted file mode 100644 index d650c651394a243c52eee7e5ad2fe463f96bdad7..0000000000000000000000000000000000000000 --- a/src/simulation/instruction.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef ASIC_SIMULATION_INSTRUCTION_H -#define ASIC_SIMULATION_INSTRUCTION_H - -#include "../number.h" - -#include <cstddef> -#include <cstdint> -#include <optional> - -namespace asic { - -enum class instruction_type : std::uint8_t { - push_input, // push(inputs[index]) - push_result, // push(results[index]) - push_delay, // push(delays[index]) - push_constant, // push(value) - truncate, // push(trunc(pop(), bit_mask)) - addition, // push(pop() + pop()) - subtraction, // push(pop() - pop()) - multiplication, // push(pop() * pop()) - division, // push(pop() / pop()) - min, // push(min(pop(), pop())) - max, // push(max(pop(), pop())) - square_root, // push(sqrt(pop())) - complex_conjugate, // push(conj(pop())) - absolute, // push(abs(pop())) - constant_multiplication, // push(pop() * value) - update_delay, // delays[index] = pop() - custom, // Custom operation. Uses custom_source[index]. - forward_value // Forward the current value on the stack (push(pop()), i.e. do nothing). -}; - -using result_index_t = std::uint16_t; - -struct instruction final { - constexpr instruction() noexcept - : index(0) - , result_index(0) - , type(instruction_type::forward_value) {} - - union { - // Index used by push_input, push_result, delay and custom. - std::size_t index; - // Bit mask used by truncate. - std::int64_t bit_mask; - // Constant value used by push_constant and constant_multiplication. - number value; - }; - // Index into where the result of the instruction will be stored. If the result should be ignored, this index will be one past the last valid result index. - result_index_t result_index; - // Specifies what kind of operation the instruction should execute. - instruction_type type; -}; - -} // namespace asic - -#endif // ASIC_SIMULATION_INSTRUCTION_H \ No newline at end of file diff --git a/src/simulation/run.h b/src/simulation/run.h deleted file mode 100644 index 2174c571ef59f3e12236471e3e064f2619c38a60..0000000000000000000000000000000000000000 --- a/src/simulation/run.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef ASIC_SIMULATION_RUN_H -#define ASIC_SIMULATION_RUN_H - -#include "../number.h" -#include "../span.h" -#include "compile.h" - -#include <cstdint> -#include <vector> - -namespace asic { - -struct simulation_state final { - std::vector<number> stack; - std::vector<number> results; -}; - -simulation_state run_simulation(simulation_code const& code, span<number const> inputs, span<number> delays, - std::optional<std::uint8_t> bits_override, bool truncate); - -} // namespace asic - -#endif // ASIC_SIMULATION_RUN_H \ No newline at end of file diff --git a/src/simulation/simulation.h b/src/simulation/simulation.h deleted file mode 100644 index c1a36cbc93492494af14a198c970a6a534477794..0000000000000000000000000000000000000000 --- a/src/simulation/simulation.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef ASIC_SIMULATION_DOD_H -#define ASIC_SIMULATION_DOD_H - -#include "../number.h" -#include "compile.h" - -#include <cstddef> -#include <cstdint> -#include <functional> -#include <optional> -#include <pybind11/functional.h> -#include <pybind11/pybind11.h> -#include <pybind11/stl.h> -#include <variant> -#include <vector> - -namespace asic { - -using iteration_t = std::uint32_t; -using input_function_t = std::function<number(iteration_t)>; -using input_provider_t = std::variant<number, std::vector<number>, input_function_t>; - -class simulation final { -public: - simulation(pybind11::handle sfg, std::optional<std::vector<std::optional<input_provider_t>>> input_providers = std::nullopt); - - void set_input(std::size_t index, input_provider_t input_provider); - void set_inputs(std::vector<std::optional<input_provider_t>> input_providers); - - [[nodiscard]] std::vector<number> step(bool save_results, std::optional<std::uint8_t> bits_override, bool truncate); - [[nodiscard]] std::vector<number> run_until(iteration_t iteration, bool save_results, std::optional<std::uint8_t> bits_override, - bool truncate); - [[nodiscard]] std::vector<number> run_for(iteration_t iterations, bool save_results, std::optional<std::uint8_t> bits_override, - bool truncate); - [[nodiscard]] std::vector<number> run(bool save_results, std::optional<std::uint8_t> bits_override, bool truncate); - - [[nodiscard]] iteration_t iteration() const noexcept; - [[nodiscard]] pybind11::dict results() const noexcept; - - void clear_results() noexcept; - void clear_state() noexcept; - -private: - simulation_code m_code; - std::vector<number> m_delays; - std::vector<input_function_t> m_input_functions; - std::optional<iteration_t> m_input_length; - iteration_t m_iteration = 0; - std::vector<std::vector<number>> m_results; -}; - -} // namespace asic - -#endif // ASIC_SIMULATION_DOD_H \ No newline at end of file diff --git a/src/span.h b/src/span.h deleted file mode 100644 index 2ad454e13e3978c74355ae3ca0f955fad1bb9753..0000000000000000000000000000000000000000 --- a/src/span.h +++ /dev/null @@ -1,314 +0,0 @@ -#ifndef ASIC_SPAN_H -#define ASIC_SPAN_H - -#include <cstddef> -#include <type_traits> -#include <utility> -#include <iterator> -#include <limits> -#include <array> -#include <algorithm> -#include <cassert> - -namespace asic { - -constexpr auto dynamic_size = static_cast<std::size_t>(-1); - -// C++17-compatible std::span substitute. -template <typename T, std::size_t Size = dynamic_size> -class span; - -namespace detail { - -template <typename T> -struct is_span_impl : std::false_type {}; - -template <typename T, std::size_t Size> -struct is_span_impl<span<T, Size>> : std::true_type {}; - -template <typename T> -struct is_span : is_span_impl<std::remove_cv_t<T>> {}; - -template <typename T> -constexpr auto is_span_v = is_span<T>::value; - -template <typename T> -struct is_std_array_impl : std::false_type {}; - -template <typename T, std::size_t Size> -struct is_std_array_impl<std::array<T, Size>> : std::true_type {}; - -template <typename T> -struct is_std_array : is_std_array_impl<std::remove_cv_t<T>> {}; - -template <typename T> -constexpr auto is_std_array_v = is_std_array<T>::value; - -template <std::size_t From, std::size_t To> -struct is_size_convertible : std::bool_constant<From == To || From == dynamic_size || To == dynamic_size> {}; - -template <std::size_t From, std::size_t To> -constexpr auto is_size_convertible_v = is_size_convertible<From, To>::value; - -template <typename From, typename To> -struct is_element_type_convertible : std::bool_constant<std::is_convertible_v<From(*)[], To(*)[]>> {}; - -template <typename From, typename To> -constexpr auto is_element_type_convertible_v = is_element_type_convertible<From, To>::value; - -template <typename T, std::size_t Size> -struct span_base { - using element_type = T; - using pointer = element_type*; - using size_type = std::size_t; - - constexpr span_base() noexcept = default; - constexpr span_base(pointer data, [[maybe_unused]] size_type size) : m_data(data) { assert(size == Size); } - - template <size_type N> - constexpr span_base(span_base<T, N> other) : m_data(other.data()) { - static_assert(N == Size || N == dynamic_size); - assert(other.size() == Size); - } - - [[nodiscard]] constexpr pointer data() const noexcept { return m_data; } - [[nodiscard]] constexpr size_type size() const noexcept { return Size; } - -private: - pointer m_data = nullptr; -}; - -template <typename T> -struct span_base<T, dynamic_size> { - using element_type = T; - using pointer = element_type*; - using size_type = std::size_t; - - constexpr span_base() noexcept = default; - constexpr span_base(pointer data, size_type size) : m_data(data), m_size(size) {} - - template <size_type N> - explicit constexpr span_base(span_base<T, N> other) : m_data(other.data()), m_size(other.size()) {} - - [[nodiscard]] constexpr pointer data() const noexcept { return m_data; } - [[nodiscard]] constexpr size_type size() const noexcept { return m_size; } - -private: - pointer m_data = nullptr; - size_type m_size = 0; -}; - -template <typename T, std::size_t Size, std::size_t Offset, std::size_t N> -struct subspan_type { - using type = span< - T, - (N != dynamic_size) ? - N : - (Size != dynamic_size) ? - Size - Offset : - Size - >; -}; - -template <typename T, std::size_t Size, std::size_t Offset, std::size_t Count> -using subspan_type_t = typename subspan_type<T, Size, Offset, Count>::type; - -} // namespace detail - -template <typename T, std::size_t Size> -class span final : public detail::span_base<T, Size> { -public: - using element_type = typename detail::span_base<T, Size>::element_type; - using pointer = typename detail::span_base<T, Size>::pointer; - using size_type = typename detail::span_base<T, Size>::size_type; - using value_type = std::remove_cv_t<element_type>; - using reference = element_type&; - using iterator = element_type*; - using const_iterator = const element_type*; - using reverse_iterator = std::reverse_iterator<iterator>; - using const_reverse_iterator = std::reverse_iterator<const_iterator>; - - // Default constructor. - constexpr span() noexcept = default; - - // Construct from pointer, size. - constexpr span(pointer data, size_type size) : detail::span_base<T, Size>(data, size) {} - - // Copy constructor. - template < - typename U, std::size_t N, - typename = std::enable_if_t<detail::is_size_convertible_v<N, Size>>, - typename = std::enable_if_t<detail::is_element_type_convertible_v<U, T>> - > - constexpr span(span<U, N> const& other) : span(other.data(), other.size()) {} - - // Copy assignment. - constexpr span& operator=(span const&) noexcept = default; - - // Destructor. - ~span() = default; - - // Construct from begin, end. - constexpr span(pointer begin, pointer end) : span(begin, end - begin) {} - - // Construct from C array. - template <std::size_t N> - constexpr span(element_type(&arr)[N]) noexcept : span(std::data(arr), N) {} - - // Construct from std::array. - template < - std::size_t N, - typename = std::enable_if_t<N != 0> - > - constexpr span(std::array<value_type, N>& arr) noexcept : span(std::data(arr), N) {} - - // Construct from empty std::array. - constexpr span(std::array<value_type, 0>&) noexcept : span() {} - - // Construct from const std::array. - template < - std::size_t N, - typename = std::enable_if_t<N != 0> - > - constexpr span(std::array<value_type, N> const& arr) noexcept : span(std::data(arr), N) {} - - // Construct from empty const std::array. - constexpr span(std::array<value_type, 0> const&) noexcept : span() {} - - // Construct from other container. - template < - typename Container, - typename = std::enable_if_t<!detail::is_span_v<Container>>, - typename = std::enable_if_t<!detail::is_std_array_v<Container>>, - typename = decltype(std::data(std::declval<Container>())), - typename = decltype(std::size(std::declval<Container>())), - typename = std::enable_if_t<std::is_convertible_v<typename Container::pointer, pointer>>, - typename = std::enable_if_t<std::is_convertible_v<typename Container::pointer, decltype(std::data(std::declval<Container>()))>> - > - constexpr span(Container& container) : span(std::data(container), std::size(container)) {} - - // Construct from other const container. - template < - typename Container, - typename Element = element_type, - typename = std::enable_if_t<std::is_const_v<Element>>, - typename = std::enable_if_t<!detail::is_span_v<Container>>, - typename = std::enable_if_t<!detail::is_std_array_v<Container>>, - typename = decltype(std::data(std::declval<Container>())), - typename = decltype(std::size(std::declval<Container>())), - typename = std::enable_if_t<std::is_convertible_v<typename Container::pointer, pointer>>, - typename = std::enable_if_t<std::is_convertible_v<typename Container::pointer, decltype(std::data(std::declval<Container>()))>> - > - constexpr span(Container const& container) : span(std::data(container), std::size(container)) {} - - [[nodiscard]] constexpr iterator begin() const noexcept { return this->data(); } - [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return this->data(); } - [[nodiscard]] constexpr iterator end() const noexcept { return this->data() + this->size(); } - [[nodiscard]] constexpr const_iterator cend() const noexcept { return this->data() + this->size(); } - [[nodiscard]] constexpr reverse_iterator rbegin() const noexcept { return std::make_reverse_iterator(this->end()); } - [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return std::make_reverse_iterator(this->cend()); } - [[nodiscard]] constexpr reverse_iterator rend() const noexcept { return std::make_reverse_iterator(this->begin()); } - [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return std::make_reverse_iterator(this->cbegin()); } - - [[nodiscard]] constexpr reference operator[](size_type i) const noexcept { assert(i < this->size()); return this->data()[i]; } - [[nodiscard]] constexpr reference operator()(size_type i) const noexcept { assert(i < this->size()); return this->data()[i]; } - - [[nodiscard]] constexpr size_type size_bytes() const noexcept { return this->size() * sizeof(element_type); } - [[nodiscard]] constexpr bool empty() const noexcept { return this->size() == 0; } - - [[nodiscard]] constexpr reference front() const noexcept { assert(!this->empty()); return this->data()[0]; } - [[nodiscard]] constexpr reference back() const noexcept { assert(!this->empty()); return this->data()[this->size() - 1]; } - - template <std::size_t N> - [[nodiscard]] constexpr span<T, N> first() const { - static_assert(N != dynamic_size && N <= Size); - return {this->data(), N}; - } - - template <std::size_t N> - [[nodiscard]] constexpr span<T, N> last() const { - static_assert(N != dynamic_size && N <= Size); - return {this->data() + (Size - N), N}; - } - - template <std::size_t Offset, std::size_t N = dynamic_size> - [[nodiscard]] constexpr auto subspan() const -> detail::subspan_type_t<T, Size, Offset, N> { - static_assert(Offset <= Size); - return {this->data() + Offset, (N == dynamic_size) ? this->size() - Offset : N}; - } - - [[nodiscard]] constexpr span<T, dynamic_size> first(size_type n) const { - assert(n <= this->size()); - return { this->data(), n }; - } - - [[nodiscard]] constexpr span<T, dynamic_size> last(size_type n) const { - return this->subspan(this->size() - n); - } - - [[nodiscard]] constexpr span<T, dynamic_size> subspan(size_type offset, size_type n = dynamic_size) const { - if constexpr (Size == dynamic_size) { - assert(offset <= this->size()); - if (n == dynamic_size) { - return { this->data() + offset, this->size() - offset }; - } - assert(n <= this->size()); - assert(offset + n <= this->size()); - return {this->data() + offset, n}; - } else { - return span<T, dynamic_size>{*this}.subspan(offset, n); - } - } -}; - -template <typename T, std::size_t LhsSize, std::size_t RhsSize> -[[nodiscard]] constexpr bool operator==(span<T, LhsSize> lhs, span<T, RhsSize> rhs) { - return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); -} - -template <typename T, std::size_t LhsSize, std::size_t RhsSize> -[[nodiscard]] constexpr bool operator!=(span<T, LhsSize> lhs, span<T, RhsSize> rhs) { - return !(lhs == rhs); -} - -template <typename T, std::size_t LhsSize, std::size_t RhsSize> -[[nodiscard]] constexpr bool operator<(span<T, LhsSize> lhs, span<T, RhsSize> rhs) { - return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); -} - -template <typename T, std::size_t LhsSize, std::size_t RhsSize> -[[nodiscard]] constexpr bool operator<=(span<T, LhsSize> lhs, span<T, RhsSize> rhs) { - return !(lhs > rhs); -} - -template <typename T, std::size_t LhsSize, std::size_t RhsSize> -[[nodiscard]] constexpr bool operator>(span<T, LhsSize> lhs, span<T, RhsSize> rhs) { - return rhs < lhs; -} - -template <typename T, std::size_t LhsSize, std::size_t RhsSize> -[[nodiscard]] constexpr bool operator>=(span<T, LhsSize> lhs, span<T, RhsSize> rhs) { - return !(lhs < rhs); -} - -template <typename Container> -span(Container&) -> span<typename Container::value_type>; - -template <typename Container> -span(Container const&) -> span<typename Container::value_type const>; - -template <typename T, std::size_t N> -span(T(&)[N]) -> span<T, N>; - -template <typename T, std::size_t N> -span(std::array<T, N>&) -> span<T, N>; - -template <typename T, std::size_t N> -span(std::array<T, N> const&) -> span<T const, N>; - -template <typename T, typename Dummy> -span(T, Dummy&&) -> span<std::remove_reference_t<decltype(std::declval<T>()[0])>>; - -} // namespace asic - -#endif // ASIC_SPAN_H \ No newline at end of file