Skip to content
Snippets Groups Projects
util.h 6.15 KiB
Newer Older
Fabian Reister's avatar
Fabian Reister committed
/*
 * This file is part of ArmarX.
 *
 * ArmarX is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * ArmarX 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 this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * @author     Fabian Reister ( fabian dot reister at kit dot edu )
 * @date       2021
 * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
 *             GNU General Public License
 */

#pragma once

#include <vector>
#include <optional>

#include <RobotAPI/libraries/armem/client/MemoryNameSystem.h>
#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h>
#include <RobotAPI/libraries/aron/core/codegeneration/cpp/AronGeneratedClass.h>
Fabian Reister's avatar
Fabian Reister committed

Fabian Reister's avatar
Fabian Reister committed
namespace armarx::armem
{
Fabian Reister's avatar
Fabian Reister committed

    /**
     * @brief Tries to cast a armem::EntityInstance to AronClass
Fabian Reister's avatar
Fabian Reister committed
     *
Fabian Reister's avatar
Fabian Reister committed
     * @tparam AronClass class name. Needs to be derived from armarx::aron::cppcodegenerator::AronCppClass
Fabian Reister's avatar
Fabian Reister committed
     * @param item
     * @return std::optional<AronClass>
Fabian Reister's avatar
Fabian Reister committed
     */
    template <typename AronClass>
    std::optional<AronClass> tryCast(const wm::EntityInstance& item)
Fabian Reister's avatar
Fabian Reister committed
    {
        static_assert(std::is_base_of<armarx::aron::cpp::AronGeneratedClass, AronClass>::value);
Fabian Reister's avatar
Fabian Reister committed

#if 0
        // item.data() is by definition a DictNavigator
        if (item.data()->getDescriptor() != aron::data::Descriptor::DICT)
Fabian Reister's avatar
Fabian Reister committed
        try
        {
            return AronClass::FromAron(item.data());
Fabian Reister's avatar
Fabian Reister committed
        }
        catch (const armarx::aron::error::AronException&)
        {
            return std::nullopt;
        }
    }

    /**
     * @brief Returns all entities that can be cast to AronClass
Fabian Reister's avatar
Fabian Reister committed
     *
Fabian Reister's avatar
Fabian Reister committed
     * @tparam AronClass class name. Needs to be derived from armarx::aron::cppcodegenerator::AronCppClass
     * @param entities collection of entities
Fabian Reister's avatar
Fabian Reister committed
     * @return std::vector<AronClass>
Fabian Reister's avatar
Fabian Reister committed
     */
    template <typename AronClass>
    std::vector<AronClass>
    allOfType(const std::map<std::string, wm::Entity>& entities)
Fabian Reister's avatar
Fabian Reister committed
    {
        static_assert(std::is_base_of<armarx::aron::cpp::AronGeneratedClass, AronClass>::value);
Fabian Reister's avatar
Fabian Reister committed

        std::vector<AronClass> outV;

        // loop over all entities and their snapshots
        for (const auto &[s, entity] : entities)
        {
            entity.forEachInstance([&outV](const wm::EntityInstance& entityInstance)
Fabian Reister's avatar
Fabian Reister committed
            {
                const auto o = tryCast<AronClass>(entityInstance);
Fabian Reister's avatar
Fabian Reister committed

                if (o)
                {
                    outV.push_back(*o);
Fabian Reister's avatar
Fabian Reister committed
                }
Fabian Reister's avatar
Fabian Reister committed
        }

        return outV;
    }

    /**
Fabian Reister's avatar
Fabian Reister committed
     * @brief filter + transform for entities.
     *
Fabian Reister's avatar
Fabian Reister committed
     * Can be used instead of
     *
     *      std::vector<Bar> ret;
     *
     *      const auto allOf = allOfType<Foo>(entities);
     *      std::transform(allOf.begin(), allOf.end(), std::back_inserter(ret), pred)
     *
Fabian Reister's avatar
Fabian Reister committed
     * This function has the benefit that the transform function will be applied directly.
     * No intermediate vector has to be created (e.g. "allOf" in the example above).
     *
Fabian Reister's avatar
Fabian Reister committed
     * @tparam AronClass class name. Needs to be derived from armarx::aron::cppcodegenerator::AronCppClass
     * @param entities collection of entities
     * @param pred binary predicate function, applied to all entity instances
Fabian Reister's avatar
Fabian Reister committed
     * @return vector of "pred"-transformed elements that can be cast to AronClass
Fabian Reister's avatar
Fabian Reister committed
     */
    template <typename AronClass>
    auto transformAllOfType(const std::map<std::string, wm::Entity>& entities,
Fabian Reister's avatar
Fabian Reister committed
                            auto pred) -> std::vector<decltype(pred(AronClass()))>
Fabian Reister's avatar
Fabian Reister committed
    {
        static_assert(std::is_base_of<armarx::aron::cpp::AronGeneratedClass, AronClass>::value);
Fabian Reister's avatar
Fabian Reister committed

        std::vector<decltype(pred(AronClass()))> outV;

Fabian Reister's avatar
Fabian Reister committed
        if (entities.empty())
        {
            ARMARX_WARNING << "No entities!";
        }

Fabian Reister's avatar
Fabian Reister committed
        // loop over all entities and their snapshots
        for (const auto &[s, entity] : entities)
        {
            entity.forEachInstance([&outV, &pred](const wm::EntityInstance& entityInstance)
Fabian Reister's avatar
Fabian Reister committed
            {
                const auto o = tryCast<AronClass>(entityInstance);
Fabian Reister's avatar
Fabian Reister committed

Fabian Reister's avatar
Fabian Reister committed
                {
                    outV.push_back(pred(*o));
Fabian Reister's avatar
Fabian Reister committed
                }
Fabian Reister's avatar
Fabian Reister committed
        }

        return outV;
    }

    /**
     * @brief resolve a single MemoryID with the given MemoryNameSystem.
     *
     * Returns a Memory containing only the desired segment / entity if it was
     * successfully queried. If the query was unsuccessful (the MNS could not
     * resolve the memory server, the MemoryID does not exist, etc.),
     * nothing is returned.
     *
     * @param mns the MemoryNameSystem to use for the query
     * @param memoryID the MemoryID to query for
     * @return memory containing the object referenced by the MemoryID if available
     */
    std::optional<armarx::armem::wm::Memory>
    resolveID(armarx::armem::client::MemoryNameSystem& mns,
              const armarx::armem::MemoryID& memoryID);


    /**
     * @brief get the data and type of the given MemoryID in the given Memory.
     *
     * Returns the data and the type of the latest instance corresponding to
     * the given MemoryID (whatever `memory.findLatestInstance(memoryID)` returns).
     * If no such instance exists in the memory or no type for the instance is available,
     * nothing is returned.
     *
     * @param memory the Memory to extract the data and type from
     * @param memoryID the MemoryID of the instance to extract
     * @return pair of data and type for the instance if available
     */
    std::optional<std::pair<armarx::aron::data::DictPtr, armarx::aron::type::ObjectPtr>>
    extractDataAndType(const armarx::armem::wm::Memory& memory,
                       const armarx::armem::MemoryID& memoryID);