Commit 096f91c2 authored by Alberto Miranda's avatar Alberto Miranda ♨️
Browse files

Merge branch '46-refactor-api-conversion-types' into 'main'

Resolve "Refactor API conversion types"

This MR 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.

Closes #46

See merge request !32
parents f5fbf9f1 70a8dfb7
Loading
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -49,3 +49,8 @@ add_library(common::network::rpc_server ALIAS _rpc_server)
target_include_directories(_rpc_types INTERFACE
  ${CMAKE_CURRENT_SOURCE_DIR})
add_library(common::network::rpc_types ALIAS _rpc_types)

add_subdirectory(api)
target_include_directories(_api_types INTERFACE
  ${CMAKE_CURRENT_SOURCE_DIR})
add_library(common::api::types ALIAS _api_types)
+40 −0
Original line number Diff line number Diff line
################################################################################
# Copyright 2021-2022, Barcelona Supercomputing Center (BSC), Spain            #
#                                                                              #
# This software was partially supported by the EuroHPC-funded project ADMIRE   #
#   (Project ID: 956748, https://www.admire-eurohpc.eu).                       #
#                                                                              #
# This file is part of scord.                                                  #
#                                                                              #
# scord is free software: you can redistribute it and/or modify                #
# it under the terms of the GNU General Public License as published by         #
# the Free Software Foundation, either version 3 of the License, or            #
# (at your option) any later version.                                          #
#                                                                              #
# scord is distributed in the hope that it will be useful,                     #
# but WITHOUT ANY WARRANTY; without even the implied warranty of               #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
# GNU General Public License for more details.                                 #
#                                                                              #
# You should have received a copy of the GNU General Public License            #
# along with scord.  If not, see <https://www.gnu.org/licenses/>.              #
#                                                                              #
# SPDX-License-Identifier: GPL-3.0-or-later                                    #
################################################################################

add_library(_api_types STATIC)

target_sources(_api_types PUBLIC admire_types.h admire_types.hpp PRIVATE
  types.cpp convert.hpp convert.cpp)

target_include_directories(_api_types PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

target_link_libraries(_api_types PRIVATE
  Margo::Margo common::logger PUBLIC fmt::fmt)

set_property(TARGET _api_types PROPERTY POSITION_INDEPENDENT_CODE ON)

install(
  FILES admire_types.h admire_types.hpp
  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
+0 −0

File moved.

+0 −168
Original line number Diff line number Diff line
@@ -252,177 +252,9 @@ private:
    std::unique_ptr<impl> m_pimpl;
};

template <typename T>
struct managed_rpc_type;

template <typename T>
struct unmanaged_rpc_type;

} // namespace admire


////////////////////////////////////////////////////////////////////////////////
//  Specializations for conversion types
////////////////////////////////////////////////////////////////////////////////

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

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

    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())) {}

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

    managed_ptr<ADM_adhoc_context_t, ADM_adhoc_context_destroy> m_adhoc_context;
};


template <>
struct admire::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>;

    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())) {}

    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;
};

template <>
struct admire::managed_rpc_type<std::vector<admire::dataset>> {

    template <typename T, auto Deleter>
    using managed_ptr_vector = scord::utils::ctype_ptr_vector<T, Deleter>;

    explicit managed_rpc_type(const std::vector<admire::dataset>& datasets) {
        m_datasets.reserve(datasets.size());

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

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

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

    std::size_t
    size() const {
        return m_datasets.size();
    }

    managed_ptr_vector<ADM_dataset_t, ADM_dataset_destroy> m_datasets;
};

template <>
struct admire::managed_rpc_type<admire::job_requirements> {

    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())) {}

    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>
            m_reqs;
};

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

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

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

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

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

    rpc_job_ptr<ADM_job_t, ADM_job_destroy> m_job;
};

template <>
struct admire::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::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;
    }

    ADM_job_t m_job;
};


////////////////////////////////////////////////////////////////////////////////
//  Formatting functions
////////////////////////////////////////////////////////////////////////////////
+100 −0
Original line number Diff line number Diff line
/******************************************************************************
 * Copyright 2021-2022, Barcelona Supercomputing Center (BSC), Spain
 *
 * This software was partially supported by the EuroHPC-funded project ADMIRE
 *   (Project ID: 956748, https://www.admire-eurohpc.eu).
 *
 * This file is part of scord.
 *
 * scord is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * scord is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with scord.  If not, see <https://www.gnu.org/licenses/>.
 *
 * 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
Loading