Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add profile base class and update profile dictionary to not leverage template methods #537

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tesseract_command_language/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ add_library(
src/poly/waypoint_poly.cpp
src/move_instruction.cpp
src/profile_dictionary.cpp
src/profile.cpp
src/set_analog_instruction.cpp
src/set_tool_instruction.cpp
src/timer_instruction.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ enum class WaitInstructionType : int;
class WaitInstruction;

// Profile Dictionary
class Profile;
class ProfileDictionary;
} // namespace tesseract_planning
#endif // TESSERACT_COMMAND_LANGUAGE_FWD_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* @file profile.h
* @brief This is a profile base class
*
* @author Levi Armstrong
* @date December 2, 2024
* @version TODO
* @bug No known bugs
*
* @copyright Copyright (c) 2024, Southwest Research Institute
*
* @par License
* Software License Agreement (Apache License)
* @par
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* @par
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TESSERACT_MOTION_PLANNERS_PROFILE_H
#define TESSERACT_MOTION_PLANNERS_PROFILE_H

#include <memory>
#include <boost/serialization/access.hpp>
#include <boost/serialization/export.hpp>

namespace tesseract_planning
{
/**
* @brief The Profile class
*/
class Profile
{
public:
using Ptr = std::shared_ptr<Profile>;
using ConstPtr = std::shared_ptr<const Profile>;

Profile() = default;
Profile(std::size_t key);
Profile(const Profile&) = delete;
Profile& operator=(const Profile&) = delete;
Profile(Profile&&) = delete;
Profile&& operator=(Profile&&) = delete;
virtual ~Profile() = default;

/**
* @brief Get the hash code associated with the profile
* @return The profile's hash code
*/
std::size_t getKey() const;

protected:
std::size_t key_{ 0 };
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive&, const unsigned int); // NOLINT
};
} // namespace tesseract_planning

BOOST_CLASS_EXPORT_KEY(tesseract_planning::Profile)

#endif // TESSERACT_MOTION_PLANNERS_PROFILE_H
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,12 @@

#include <tesseract_common/macros.h>
TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
#include <any>
#include <typeindex>
#include <unordered_map>
#include <memory>
#include <mutex>
#include <shared_mutex>
TESSERACT_COMMON_IGNORE_WARNINGS_POP

#include <tesseract_command_language/profile.h>
#include <tesseract_common/any_poly.h>

namespace tesseract_planning
Expand All @@ -50,184 +48,88 @@ namespace tesseract_planning
using ProfileRemapping = std::unordered_map<std::string, std::unordered_map<std::string, std::string>>;

/**
* @brief This class is used to store profiles for motion planning and process planning
* @brief This class is used to store profiles used by various tasks
* @details This is a thread safe class
* A ProfileEntry<T> is a std::unordered_map<std::string, std::shared_ptr<const T>>
* - The key is the profile name
* - Where std::shared_ptr<const T> is the profile
* The ProfleEntry<T> is also stored in std::unordered_map where the key here is the std::type_index(typeid(T))
* @note When adding a profile entry the T should be the base class type.
*/
class ProfileDictionary
{
public:
using Ptr = std::shared_ptr<ProfileDictionary>;
using ConstPtr = std::shared_ptr<const ProfileDictionary>;

/**
* @brief Check if a profile entry exists
* @param ns The namesspace to search under
* @return True if exists, otherwise false
*/
template <typename ProfileType>
bool hasProfileEntry(const std::string& ns) const
{
std::shared_lock lock(mutex_);
auto it = profiles_.find(ns);
if (it == profiles_.end())
return false;

return (it->second.find(std::type_index(typeid(ProfileType))) != it->second.end());
}

/** @brief Remove a profile entry */
template <typename ProfileType>
void removeProfileEntry(const std::string& ns)
{
std::unique_lock lock(mutex_);

auto it = profiles_.find(ns);
if (it == profiles_.end())
return;

it->second.erase(std::type_index(typeid(ProfileType)));
}

/**
* @brief Get a profile entry
* @return The profile map associated with the profile entry
*/
template <typename ProfileType>
std::unordered_map<std::string, std::shared_ptr<const ProfileType>> getProfileEntry(const std::string& ns) const
{
std::shared_lock lock(mutex_);
auto it = profiles_.find(ns);
if (it == profiles_.end())
throw std::runtime_error("Profile namespace does not exist for '" + ns + "'!");

auto it2 = it->second.find(std::type_index(typeid(ProfileType)));
if (it2 != it->second.end())
return std::any_cast<const std::unordered_map<std::string, std::shared_ptr<const ProfileType>>&>(it2->second);

throw std::runtime_error("Profile entry does not exist for type name '" +
std::string(std::type_index(typeid(ProfileType)).name()) + "' in namespace '" + ns + "'!");
}

/**
* @brief Add a profile
* @details If the profile entry does not exist it will create one
* @param ns The profile namespace
* @param profile_name The profile name
* @param profile The profile to add
*/
template <typename ProfileType>
void addProfile(const std::string& ns, const std::string& profile_name, std::shared_ptr<const ProfileType> profile)
{
if (ns.empty())
throw std::runtime_error("Adding profile with an empty namespace!");

if (profile_name.empty())
throw std::runtime_error("Adding profile with an empty string as the key!");

if (profile == nullptr)
throw std::runtime_error("Adding profile that is a nullptr");

std::unique_lock lock(mutex_);
auto it = profiles_.find(ns);
if (it == profiles_.end())
{
std::unordered_map<std::string, std::shared_ptr<const ProfileType>> new_entry;
new_entry[profile_name] = profile;
profiles_[ns][std::type_index(typeid(ProfileType))] = new_entry;
}
else
{
auto it2 = it->second.find(std::type_index(typeid(ProfileType)));
if (it2 != it->second.end())
{
std::any_cast<std::unordered_map<std::string, std::shared_ptr<const ProfileType>>&>(it2->second)[profile_name] =
profile;
}
else
{
std::unordered_map<std::string, std::shared_ptr<const ProfileType>> new_entry;
new_entry[profile_name] = profile;
it->second[std::type_index(typeid(ProfileType))] = new_entry;
}
}
}
void addProfile(const std::string& ns, const std::string& profile_name, const Profile::ConstPtr& profile);

/**
* @brief Check if a profile exists
* @details If profile entry does not exist it also returns false
* @param key The profile key
* @param ns The profile namespace
* @param profile_name The profile name
* @return True if profile exists, otherwise false
*/
template <typename ProfileType>
bool hasProfile(const std::string& ns, const std::string& profile_name) const
{
std::shared_lock lock(mutex_);
auto it = profiles_.find(ns);
if (it == profiles_.end())
return false;

auto it2 = it->second.find(std::type_index(typeid(ProfileType)));
if (it2 != it->second.end())
{
const auto& profile_map =
std::any_cast<const std::unordered_map<std::string, std::shared_ptr<const ProfileType>>&>(it2->second);
auto it3 = profile_map.find(profile_name);
if (it3 != profile_map.end())
return true;
}
return false;
}
bool hasProfile(std::size_t key, const std::string& ns, const std::string& profile_name) const;

/**
* @brief Get a profile by name
* @details Check if the profile exist before calling this function, if missing an exception is thrown
* @param key The profile key
* @param ns The profile namespace
* @param profile_name The profile name
* @return The profile
*/
template <typename ProfileType>
std::shared_ptr<const ProfileType> getProfile(const std::string& ns, const std::string& profile_name) const
{
std::shared_lock lock(mutex_);
const auto& it = profiles_.at(ns);
const auto& it2 = it.at(std::type_index(typeid(ProfileType)));
const auto& profile_map =
std::any_cast<const std::unordered_map<std::string, std::shared_ptr<const ProfileType>>&>(it2);
return profile_map.at(profile_name);
}
Profile::ConstPtr getProfile(std::size_t key, const std::string& ns, const std::string& profile_name) const;

/**
* @brief Remove a profile
* @param key The profile key
* @param ns The profile namespace
* @param profile_name The profile to be removed
*/
template <typename ProfileType>
void removeProfile(const std::string& ns, const std::string& profile_name)
{
std::unique_lock lock(mutex_);
auto it = profiles_.find(ns);
if (it == profiles_.end())
return;

auto it2 = it->second.find(std::type_index(typeid(ProfileType)));
if (it2 != it->second.end())
std::any_cast<std::unordered_map<std::string, std::shared_ptr<const ProfileType>>&>(it2->second)
.erase(profile_name);
}
void removeProfile(std::size_t key, const std::string& ns, const std::string& profile_name);

/**
* @brief Check if a profile entry exists
* @param key The profile key
* @param ns The profile namespace
* @return True if exists, otherwise false
*/
bool hasProfileEntry(std::size_t key, const std::string& ns) const;

/**
* @brief Remove a profile entry
* @param key The profile key
* @param ns The profile namespace
*/
void removeProfileEntry(std::size_t key, const std::string& ns);

/**
* @brief Get a profile entry
* @param key The profile key
* @param ns The profile namespace
* @return The profile map associated with the profile entry
*/
std::unordered_map<std::string, Profile::ConstPtr> getProfileEntry(std::size_t key, const std::string& ns) const;

/** @brief Clear the dictionary */
void clear();

protected:
std::unordered_map<std::string, std::unordered_map<std::type_index, std::any>> profiles_;
mutable std::shared_mutex mutex_;
std::unordered_map<std::string, std::unordered_map<std::size_t, std::unordered_map<std::string, Profile::ConstPtr>>>
profiles_;

friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int version); // NOLINT
};

} // namespace tesseract_planning

BOOST_CLASS_EXPORT_KEY(tesseract_planning::ProfileDictionary)
Expand Down
Loading
Loading