Verified Commit 70a8dfb7 authored by Alberto Miranda's avatar Alberto Miranda ♨️
Browse files

Separate managed_rpc_type lifetime management from type conversion

This commit separates the functionality of managed_rpc_type<T> into
dedicated lifetime management types and conversion functions. This
makes for clearer the code since it is now possible to know when
a conversion is performed.

Lifetime management for C-types is now done with the managed_ctype<T>
types, which act only as holders of dynamically allocated C types and do not
perform any type conversions whatsoever.

Type conversions are now done with the T1 convert(T2 obj) family of functions.
When converting from CXX to C API types, these functions effectively
return instances of the appropriate managed_ctype<T>s. If one wishes to
relinquish ownership of the content of the managed_ctype<T> (e.g. to
pass it to a pure C function that will release it), this can be done
with the managed_ctype<T>::release() function.
parent 13ae1a15
Loading
Loading
Loading
Loading
Loading
+75 −0
Original line number Diff line number Diff line
@@ -22,4 +22,79 @@
 * SPDX-License-Identifier: GPL-3.0-or-later
 *****************************************************************************/

#include <algorithm>
#include "convert.hpp"

// forward declarations
ADM_job_t
ADM_job_create(uint64_t id);

namespace admire::api {

managed_ctype<ADM_adhoc_context_t>
convert(const adhoc_storage::ctx& ctx) {
    return managed_ctype<ADM_adhoc_context_t>{ADM_adhoc_context_create(
            static_cast<ADM_adhoc_mode_t>(ctx.exec_mode()),
            static_cast<ADM_adhoc_access_t>(ctx.access_type()), ctx.nodes(),
            ctx.walltime(), ctx.should_flush())};
}

managed_ctype<ADM_storage_t>
convert(const admire::adhoc_storage& st) {

    auto managed_ctx =
            convert(*std::static_pointer_cast<admire::adhoc_storage::ctx>(
                    st.context()));

    ADM_storage_t c_st = ADM_storage_create(
            st.id().c_str(), static_cast<ADM_storage_type_t>(st.type()),
            managed_ctx.get());

    return managed_ctype<ADM_storage_t>{c_st, std::move(managed_ctx)};
}

managed_ctype_array<ADM_dataset_t>
convert(const std::vector<admire::dataset>& datasets) {

    std::vector<ADM_dataset_t> tmp;

    std::transform(datasets.cbegin(), datasets.cend(), std::back_inserter(tmp),
                   [](const admire::dataset& d) {
                       return ADM_dataset_create(d.id().c_str());
                   });

    return managed_ctype_array<ADM_dataset_t>{std::move(tmp)};
}

managed_ctype<ADM_job_requirements_t>
convert(const admire::job_requirements& reqs) {

    const auto& adhoc_storage =
            *std::dynamic_pointer_cast<admire::adhoc_storage>(reqs.storage());

    auto managed_storage = convert(adhoc_storage);
    auto managed_inputs = convert(reqs.inputs());
    auto managed_outputs = convert(reqs.outputs());

    ADM_job_requirements_t c_reqs = ADM_job_requirements_create(
            managed_inputs.data(), managed_inputs.size(),
            managed_outputs.data(), managed_outputs.size(),
            managed_storage.get());

    return managed_ctype<ADM_job_requirements_t>{
            c_reqs, std::move(managed_inputs), std::move(managed_outputs),
            std::move(managed_storage)};
}


managed_ctype<ADM_job_t>
convert(const job& j) {
    return managed_ctype<ADM_job_t>(ADM_job_create(j.id()));
}

job
convert(ADM_job_t j) {
    return admire::job{j};
}

} // namespace admire::api
+85 −95
Original line number Diff line number Diff line
@@ -30,11 +30,33 @@

namespace admire::api {

// convenience types for managing the types from the C API in a RAII fashion
template <typename T>
struct managed_rpc_type;
struct managed_ctype;

template <typename T>
struct unmanaged_rpc_type;
struct managed_ctype_array;

// conversion functions between C API and CXX API types

managed_ctype<ADM_adhoc_context_t>
convert(const adhoc_storage::ctx& ctx);

managed_ctype<ADM_storage_t>
convert(const admire::adhoc_storage& st);

managed_ctype_array<ADM_dataset_t>
convert(const std::vector<admire::dataset>& datasets);

managed_ctype<ADM_job_requirements_t>
convert(const admire::job_requirements& reqs);

managed_ctype<ADM_job_t>
convert(const job& j);

job
convert(ADM_job_t j);


} // namespace admire::api

@@ -44,160 +66,128 @@ struct unmanaged_rpc_type;
////////////////////////////////////////////////////////////////////////////////

template <>
struct admire::api::managed_rpc_type<admire::adhoc_storage::ctx> {

    template <typename T, auto Deleter>
    using managed_ptr = scord::utils::ctype_ptr<T, Deleter>;
struct admire::api::managed_ctype<ADM_adhoc_context_t> {

    explicit managed_rpc_type(const admire::adhoc_storage::ctx& ctx)
        : m_adhoc_context(ADM_adhoc_context_create(
                  static_cast<ADM_adhoc_mode_t>(ctx.exec_mode()),
                  static_cast<ADM_adhoc_access_t>(ctx.access_type()),
                  ctx.nodes(), ctx.walltime(), ctx.should_flush())) {}
    explicit managed_ctype(ADM_adhoc_context_t ctx) : m_adhoc_context(ctx) {}

    ADM_adhoc_context_t
    get() const {
        return m_adhoc_context.get();
    }

    managed_ptr<ADM_adhoc_context_t, ADM_adhoc_context_destroy> m_adhoc_context;
};
    ADM_adhoc_context_t
    release() {
        return m_adhoc_context.release();
    }

    scord::utils::ctype_ptr<ADM_adhoc_context_t, ADM_adhoc_context_destroy>
            m_adhoc_context;
};

template <>
struct admire::api::managed_rpc_type<admire::adhoc_storage> {

    template <typename T, auto Deleter>
    using rpc_storage_ptr = scord::utils::ctype_ptr<T, Deleter>;

    template <typename T, auto Deleter>
    using managed_ptr = scord::utils::ctype_ptr<T, Deleter>;
struct admire::api::managed_ctype<ADM_storage_t> {

    explicit managed_rpc_type(const admire::adhoc_storage& st)
        : m_adhoc_context(*std::static_pointer_cast<admire::adhoc_storage::ctx>(
                  st.context())),
          m_storage(ADM_storage_create(
                  st.id().c_str(), static_cast<ADM_storage_type_t>(st.type()),
                  m_adhoc_context.get())) {}
    explicit managed_ctype(ADM_storage_t st,
                           managed_ctype<ADM_adhoc_context_t>&& ctx)
        : m_storage(st), m_ctx(std::move(ctx)) {}

    ADM_storage_t
    get() const {
        return m_storage.get();
    }

    managed_rpc_type<admire::adhoc_storage::ctx> m_adhoc_context;
    rpc_storage_ptr<ADM_storage_t, ADM_storage_destroy> m_storage;
    ADM_storage_t
    release() {
        return m_storage.release();
    }

    scord::utils::ctype_ptr<ADM_storage_t, ADM_storage_destroy> m_storage;
    managed_ctype<ADM_adhoc_context_t> m_ctx;
};

template <>
struct admire::api::managed_rpc_type<std::vector<admire::dataset>> {
struct admire::api::managed_ctype_array<ADM_dataset_t> {

    template <typename T, auto Deleter>
    using managed_ptr_vector = scord::utils::ctype_ptr_vector<T, Deleter>;
    explicit managed_ctype_array(ADM_dataset_t* data, size_t size)
        : m_datasets(data, size) {}

    explicit managed_rpc_type(const std::vector<admire::dataset>& datasets) {
        m_datasets.reserve(datasets.size());
    explicit managed_ctype_array(std::vector<ADM_dataset_t>&& v)
        : m_datasets(v.data(), v.size()) {}

        for(const auto& d : datasets) {
            m_datasets.emplace_back(ADM_dataset_create(d.id().c_str()));
        }
    constexpr size_t
    size() const {
        return m_datasets.size();
    }

    const ADM_dataset_t*
    data() const {
    constexpr const ADM_dataset_t*
    data() const noexcept {
        return m_datasets.data();
    }

    ADM_dataset_t*
    data() {
    constexpr ADM_dataset_t*
    data() noexcept {
        return m_datasets.data();
    }

    std::size_t
    size() const {
        return m_datasets.size();
    constexpr ADM_dataset_t*
    release() noexcept {
        return m_datasets.release();
    }

    managed_ptr_vector<ADM_dataset_t, ADM_dataset_destroy> m_datasets;
    scord::utils::ctype_ptr_vector<ADM_dataset_t, ADM_dataset_destroy>
            m_datasets;
};

template <>
struct admire::api::managed_rpc_type<admire::job_requirements> {
struct admire::api::managed_ctype<ADM_job_requirements_t> {

    template <typename T, auto Deleter>
    using rpc_requirements_ptr = scord::utils::ctype_ptr<T, Deleter>;

    explicit managed_rpc_type(const admire::job_requirements& reqs)
        : m_inputs(reqs.inputs()), m_outputs(reqs.outputs()),
          m_storage(*std::dynamic_pointer_cast<admire::adhoc_storage>(
                  reqs.storage())),
          m_reqs(ADM_job_requirements_create(m_inputs.data(), m_inputs.size(),
                                             m_outputs.data(), m_outputs.size(),
                                             m_storage.get())) {}
    explicit managed_ctype(ADM_job_requirements_t reqs,
                           managed_ctype_array<ADM_dataset_t>&& inputs,
                           managed_ctype_array<ADM_dataset_t>&& outputs,
                           managed_ctype<ADM_storage_t>&& storage)
        : m_reqs(reqs), m_inputs(std::move(inputs)),
          m_outputs(std::move(outputs)), m_storage(std::move(storage)) {}

    ADM_job_requirements_t
    get() const {
        return m_reqs.get();
    }

    managed_rpc_type<std::vector<admire::dataset>> m_inputs;
    managed_rpc_type<std::vector<admire::dataset>> m_outputs;
    managed_rpc_type<admire::adhoc_storage> m_storage;
    rpc_requirements_ptr<ADM_job_requirements_t, ADM_job_requirements_destroy>
    ADM_job_requirements_t
    release() {
        return m_reqs.release();
    }


    scord::utils::ctype_ptr<ADM_job_requirements_t,
                            ADM_job_requirements_destroy>
            m_reqs;
    managed_ctype_array<ADM_dataset_t> m_inputs;
    managed_ctype_array<ADM_dataset_t> m_outputs;
    managed_ctype<ADM_storage_t> m_storage;
};


// forward declarations
ADM_job_t
ADM_job_create(uint64_t id);
ADM_return_t
ADM_job_destroy(ADM_job_t job);

template <>
struct admire::api::managed_rpc_type<admire::job> {

    template <typename T, auto Deleter>
    using rpc_job_ptr = scord::utils::ctype_ptr<T, Deleter>;
struct admire::api::managed_ctype<ADM_job_t> {

    explicit managed_rpc_type(const admire::job& j)
        : m_job(ADM_job_create(j.id())) {}
    explicit managed_ctype(ADM_job_t job) : m_job(job) {}

    ADM_job_t
    get() const {
        return m_job.get();
    }

    rpc_job_ptr<ADM_job_t, ADM_job_destroy> m_job;
};

template <>
struct admire::api::managed_rpc_type<ADM_job_t> {

    template <typename T, auto Deleter>
    using rpc_job_ptr = scord::utils::ctype_ptr<T, Deleter>;

    explicit managed_rpc_type(ADM_job_t job) : m_job(job) {}

    admire::job
    get() const {
        return admire::job(m_job.get());
    }

    rpc_job_ptr<ADM_job_t, ADM_job_destroy> m_job;
};

template <>
struct admire::api::unmanaged_rpc_type<admire::job> {

    explicit unmanaged_rpc_type(const admire::job& j)
        : m_job(ADM_job_create(j.id())) {}

    ADM_job_t
    get() const {
        return m_job;
    release() {
        return m_job.release();
    }

    ADM_job_t m_job;
    scord::utils::ctype_ptr<ADM_job_t, ADM_job_destroy> m_job;
};

#endif // SCORD_CONVERT_HPP
+28 −0
Original line number Diff line number Diff line
@@ -57,6 +57,20 @@ struct ctype_ptr_vector {

    ctype_ptr_vector() = default;

    ctype_ptr_vector(T* const data, size_t size) {
        reserve(size);

        for(size_t i = 0; i < size; ++i) {
            emplace_back(data[i]);
        }
    }

    ctype_ptr_vector(ctype_ptr_vector&& rhs) noexcept
        : m_data(std::move(rhs.m_data)), m_addrs(std::move(rhs.m_addrs)) {}

    ctype_ptr_vector&
    operator=(ctype_ptr_vector&&) noexcept = default;

    ~ctype_ptr_vector() = default;

    constexpr void
@@ -87,6 +101,20 @@ struct ctype_ptr_vector {
        return m_data.size();
    }

    constexpr T*
    release() noexcept {

        auto* data = (T*) calloc(m_data.size(), sizeof(T));

        for(size_t i = 0; i < m_data.size(); ++i) {
            data[i] = m_data[i].release();
            m_addrs[i] = nullptr;
        }

        return data;
    }


    std::vector<scord::utils::ctype_ptr<T, fn>> m_data{};
    std::vector<T> m_addrs{};
};
+1 −1
Original line number Diff line number Diff line
@@ -55,7 +55,7 @@ ADM_register_job(ADM_server_t server, ADM_job_requirements_t reqs,
        return rv.error();
    }

    *job = admire::api::unmanaged_rpc_type<admire::job>{*rv}.get();
    *job = admire::api::convert(*rv).release();

    return ADM_SUCCESS;
}
+5 −6
Original line number Diff line number Diff line
@@ -180,7 +180,7 @@ register_job(const admire::server& srv, const admire::job_requirements& reqs) {
    LOGGER_INFO("RPC (ADM_{}) => {{job_requirements: {{{}}}}}", __FUNCTION__,
                reqs);

    auto rpc_reqs = api::managed_rpc_type<admire::job_requirements>{reqs};
    auto rpc_reqs = api::convert(reqs);

    ADM_register_job_in_t in{*rpc_reqs.get()};
    ADM_register_job_out_t out;
@@ -192,8 +192,7 @@ register_job(const admire::server& srv, const admire::job_requirements& reqs) {
        return tl::make_unexpected(static_cast<admire::error_code>(out.retval));
    }

    const auto rpc_job = api::managed_rpc_type<ADM_job_t>{out.job};
    const admire::job job = rpc_job.get();
    const admire::job job = api::convert(out.job);

    LOGGER_INFO("RPC (ADM_{}) <= {{retval: {}, job: {{{}}}}}", __FUNCTION__,
                ADM_SUCCESS, job.id());
@@ -211,8 +210,8 @@ update_job(const server& srv, const job& job, const job_requirements& reqs) {
    LOGGER_INFO("RPC ({}): {{job: {{{}}}, job_requirements: {{{}}}}}",
                "ADM_update_job", job, reqs);

    const auto rpc_job = api::managed_rpc_type<admire::job>{job};
    const auto rpc_reqs = api::managed_rpc_type<admire::job_requirements>{reqs};
    const auto rpc_job = api::convert(job);
    const auto rpc_reqs = api::convert(reqs);

    ADM_update_job_in_t in{rpc_job.get(), *rpc_reqs.get()};
    ADM_update_job_out_t out;
@@ -239,7 +238,7 @@ remove_job(const server& srv, const job& job) {

    LOGGER_INFO("RPC (ADM_{}) => {{job: {}}}", __FUNCTION__, job);

    const auto rpc_job = api::managed_rpc_type<admire::job>{job};
    const auto rpc_job = api::convert(job);

    ADM_remove_job_in_t in{rpc_job.get()};
    ADM_remove_job_out_t out;
Loading