diff --git a/ros2bag/ros2bag/verb/info.py b/ros2bag/ros2bag/verb/info.py index 005c4b0ea..d101c0c52 100644 --- a/ros2bag/ros2bag/verb/info.py +++ b/ros2bag/ros2bag/verb/info.py @@ -45,6 +45,6 @@ def main(self, *, args): # noqa: D102 Info().print_output_verbose(args.bag_path, m, args.sort) else: if args.topic_name: - Info().print_output_topic_name_only(m) + Info().print_output_topic_name_only(m, args.sort) else: Info().print_output(m, args.sort) diff --git a/rosbag2_py/CMakeLists.txt b/rosbag2_py/CMakeLists.txt index feb07925f..781fb3387 100644 --- a/rosbag2_py/CMakeLists.txt +++ b/rosbag2_py/CMakeLists.txt @@ -86,6 +86,7 @@ pybind11_add_module(_info SHARED src/rosbag2_py/_info.cpp src/rosbag2_py/format_bag_metadata.cpp src/rosbag2_py/format_service_info.cpp + src/rosbag2_py/info_sorting_method.cpp ) target_link_libraries(_info PUBLIC rosbag2_cpp::rosbag2_cpp diff --git a/rosbag2_py/src/rosbag2_py/_info.cpp b/rosbag2_py/src/rosbag2_py/_info.cpp index 8fd39d69b..7b5d0473d 100644 --- a/rosbag2_py/src/rosbag2_py/_info.cpp +++ b/rosbag2_py/src/rosbag2_py/_info.cpp @@ -18,6 +18,7 @@ #include #include +#include "info_sorting_method.hpp" #include "format_bag_metadata.hpp" #include "format_service_info.hpp" #include "rosbag2_cpp/info.hpp" @@ -30,11 +31,6 @@ namespace rosbag2_py { -std::unordered_map stringToSortingMethod = { - {"name", SortingMethod::NAME}, - {"type", SortingMethod::TYPE}, - {"count", SortingMethod::COUNT}}; - class Info { public: @@ -51,28 +47,23 @@ class Info } void print_output( - const rosbag2_storage::BagMetadata & metadata_info, std::string sorting_method) + const rosbag2_storage::BagMetadata & metadata_info, const std::string & sorting_method) { - rosbag2_py::SortingMethod sort_method = rosbag2_py::stringToSortingMethod[sorting_method]; + InfoSortingMethod sort_method = info_sorting_method_from_string(sorting_method); // Output formatted metadata std::cout << format_bag_meta_data(metadata_info, {}, false, false, sort_method) << std::endl; } - void print_output_topic_name_only(const rosbag2_storage::BagMetadata & metadata_info) + void print_output_topic_name_only( + const rosbag2_storage::BagMetadata & metadata_info, const std::string & sorting_method) { - std::vector sorted_idx(metadata_info.topics_with_message_count.size()); - std::iota(sorted_idx.begin(), sorted_idx.end(), 0); - std::sort( - sorted_idx.begin(), - sorted_idx.end(), - [&metadata_info](size_t i1, size_t i2) { - std::string topic_name_1 = metadata_info.topics_with_message_count[i1].topic_metadata.name; - std::string topic_name_2 = metadata_info.topics_with_message_count[i2].topic_metadata.name; - return topic_name_1 < topic_name_2; - } - ); + InfoSortingMethod sort_method = info_sorting_method_from_string(sorting_method); + std::vector sorted_idx = generate_sorted_idx( + metadata_info.topics_with_message_count, + sort_method); + for (auto idx : sorted_idx) { - auto topic_info = metadata_info.topics_with_message_count[idx]; + const auto & topic_info = metadata_info.topics_with_message_count[idx]; if (!rosbag2_cpp::is_service_event_topic( topic_info.topic_metadata.name, topic_info.topic_metadata.type)) @@ -85,7 +76,7 @@ class Info void print_output_verbose( const std::string & uri, const rosbag2_storage::BagMetadata & metadata_info, - std::string sorting_method) + const std::string & sorting_method) { std::vector> all_services_info; for (auto & file_info : metadata_info.files) { @@ -110,7 +101,7 @@ class Info } } - rosbag2_py::SortingMethod sort_method = rosbag2_py::stringToSortingMethod[sorting_method]; + rosbag2_py::InfoSortingMethod sort_method = info_sorting_method_from_string(sorting_method); // Output formatted metadata and service info std::cout << format_bag_meta_data(metadata_info, messages_size, true, true, sort_method); std::cout << format_service_info(all_services_info, messages_size, true) << std::endl; @@ -119,7 +110,7 @@ class Info std::unordered_set get_sorting_methods() { std::unordered_set sorting_methods; - for (auto sorting_method : rosbag2_py::stringToSortingMethod) { + for (auto sorting_method : rosbag2_py::sorting_method_map) { sorting_methods.insert(sorting_method.first); } return sorting_methods; diff --git a/rosbag2_py/src/rosbag2_py/format_bag_metadata.cpp b/rosbag2_py/src/rosbag2_py/format_bag_metadata.cpp index 0b1fa48bd..117d80793 100644 --- a/rosbag2_py/src/rosbag2_py/format_bag_metadata.cpp +++ b/rosbag2_py/src/rosbag2_py/format_bag_metadata.cpp @@ -118,7 +118,7 @@ void format_topics_with_type( bool verbose, std::stringstream & info_stream, int indentation_spaces, - const rosbag2_py::SortingMethod sort_method = rosbag2_py::SortingMethod::NAME) + const rosbag2_py::InfoSortingMethod sort_method = rosbag2_py::InfoSortingMethod::NAME) { if (topics.empty()) { info_stream << std::endl; @@ -142,21 +142,7 @@ void format_topics_with_type( info_stream << std::endl; }; - std::vector sorted_idx(topics.size()); - std::iota(sorted_idx.begin(), sorted_idx.end(), 0); - std::sort( - sorted_idx.begin(), - sorted_idx.end(), - [&topics, sort_method](size_t i1, size_t i2) { - if (sort_method == rosbag2_py::SortingMethod::TYPE) { - return topics[i1].topic_metadata.type < topics[i2].topic_metadata.type; - } - if (sort_method == rosbag2_py::SortingMethod::COUNT) { - return topics[i1].message_count < topics[i2].message_count; - } - return topics[i1].topic_metadata.name < topics[i2].topic_metadata.name; - } - ); + std::vector sorted_idx = rosbag2_py::generate_sorted_idx(topics, sort_method); size_t number_of_topics = topics.size(); size_t i = 0; @@ -186,31 +172,19 @@ void format_topics_with_type( } } -struct ServiceMetadata -{ - std::string name; - std::string type; - std::string serialization_format; -}; -struct ServiceInformation -{ - ServiceMetadata service_metadata; - size_t event_message_count = 0; -}; - -std::vector> filter_service_event_topic( +std::vector> filter_service_event_topic( const std::vector & topics_with_message_count, size_t & total_service_event_msg_count) { total_service_event_msg_count = 0; - std::vector> service_info_list; + std::vector> service_info_list; for (auto & topic : topics_with_message_count) { if (rosbag2_cpp::is_service_event_topic( topic.topic_metadata.name, topic.topic_metadata.type)) { - auto service_info = std::make_shared(); + auto service_info = std::make_shared(); service_info->service_metadata.name = rosbag2_cpp::service_event_topic_name_to_service_name(topic.topic_metadata.name); service_info->service_metadata.type = @@ -227,12 +201,12 @@ std::vector> filter_service_event_topic( } void format_service_with_type( - const std::vector> & services, + const std::vector> & services, const std::unordered_map & messages_size, bool verbose, std::stringstream & info_stream, int indentation_spaces, - const rosbag2_py::SortingMethod sort_method = rosbag2_py::SortingMethod::NAME) + const rosbag2_py::InfoSortingMethod sort_method = rosbag2_py::InfoSortingMethod::NAME) { if (services.empty()) { info_stream << std::endl; @@ -241,7 +215,7 @@ void format_service_with_type( auto print_service_info = [&info_stream, &messages_size, verbose]( - const std::shared_ptr & si) -> void { + const std::shared_ptr & si) -> void { info_stream << "Service: " << si->service_metadata.name << " | "; info_stream << "Type: " << si->service_metadata.type << " | "; info_stream << "Event Count: " << si->event_message_count << " | "; @@ -258,21 +232,7 @@ void format_service_with_type( info_stream << std::endl; }; - std::vector sorted_idx(services.size()); - std::iota(sorted_idx.begin(), sorted_idx.end(), 0); - std::sort( - sorted_idx.begin(), - sorted_idx.end(), - [&services, sort_method](size_t i1, size_t i2) { - if (sort_method == rosbag2_py::SortingMethod::TYPE) { - return services[i1]->service_metadata.type < services[i2]->service_metadata.type; - } - if (sort_method == rosbag2_py::SortingMethod::COUNT) { - return services[i1]->event_message_count < services[i2]->event_message_count; - } - return services[i1]->service_metadata.name < services[i2]->service_metadata.name; - } - ); + std::vector sorted_idx = rosbag2_py::generate_sorted_idx(services, sort_method); print_service_info(services[sorted_idx[0]]); auto number_of_services = services.size(); @@ -292,7 +252,7 @@ std::string format_bag_meta_data( const std::unordered_map & messages_size, bool verbose, bool only_topic, - const SortingMethod sort_method) + const InfoSortingMethod sort_method) { auto start_time = metadata.starting_time.time_since_epoch(); auto end_time = start_time + metadata.duration; @@ -304,7 +264,7 @@ std::string format_bag_meta_data( } size_t total_service_event_msg_count = 0; - std::vector> service_info_list; + std::vector> service_info_list; service_info_list = filter_service_event_topic( metadata.topics_with_message_count, total_service_event_msg_count); diff --git a/rosbag2_py/src/rosbag2_py/format_bag_metadata.hpp b/rosbag2_py/src/rosbag2_py/format_bag_metadata.hpp index de8def134..88343006a 100644 --- a/rosbag2_py/src/rosbag2_py/format_bag_metadata.hpp +++ b/rosbag2_py/src/rosbag2_py/format_bag_metadata.hpp @@ -18,27 +18,18 @@ #include #include +#include "info_sorting_method.hpp" #include "rosbag2_storage/bag_metadata.hpp" namespace rosbag2_py { -/** - * \brief Available sorting methods for info output. - */ -enum class SortingMethod -{ - NAME, - TYPE, - COUNT, -}; - std::string format_bag_meta_data( const rosbag2_storage::BagMetadata & metadata, const std::unordered_map & messages_size = {}, bool verbose = false, bool only_topic = false, - const SortingMethod sort_method = SortingMethod::NAME); + const InfoSortingMethod sort_method = InfoSortingMethod::NAME); } // namespace rosbag2_py diff --git a/rosbag2_py/src/rosbag2_py/format_service_info.cpp b/rosbag2_py/src/rosbag2_py/format_service_info.cpp index 379425915..4b4f3d121 100644 --- a/rosbag2_py/src/rosbag2_py/format_service_info.cpp +++ b/rosbag2_py/src/rosbag2_py/format_service_info.cpp @@ -46,7 +46,8 @@ std::string format_service_info( std::vector> & service_info_list, const std::unordered_map & messages_size, - bool verbose) + bool verbose, + const InfoSortingMethod sort_method) { std::stringstream info_stream; const std::string service_info_string = "Service information: "; @@ -78,11 +79,13 @@ format_service_info( info_stream << std::endl; }; - print_service_info(service_info_list[0]); + std::vector sorted_idx = rosbag2_py::generate_sorted_idx(service_info_list, sort_method); + + print_service_info(service_info_list[sorted_idx[0]]); auto number_of_services = service_info_list.size(); for (size_t j = 1; j < number_of_services; ++j) { info_stream << std::string(indentation_spaces, ' '); - print_service_info(service_info_list[j]); + print_service_info(service_info_list[sorted_idx[j]]); } return info_stream.str(); diff --git a/rosbag2_py/src/rosbag2_py/format_service_info.hpp b/rosbag2_py/src/rosbag2_py/format_service_info.hpp index 2feb1432c..58b696e08 100644 --- a/rosbag2_py/src/rosbag2_py/format_service_info.hpp +++ b/rosbag2_py/src/rosbag2_py/format_service_info.hpp @@ -20,6 +20,7 @@ #include #include +#include "info_sorting_method.hpp" #include "rosbag2_cpp/info.hpp" namespace rosbag2_py @@ -28,7 +29,8 @@ namespace rosbag2_py std::string format_service_info( std::vector> & service_info, const std::unordered_map & messages_size = {}, - bool verbose = false); + bool verbose = false, + const InfoSortingMethod sort_method = InfoSortingMethod::NAME); } // namespace rosbag2_py diff --git a/rosbag2_py/src/rosbag2_py/info_sorting_method.cpp b/rosbag2_py/src/rosbag2_py/info_sorting_method.cpp new file mode 100644 index 000000000..cc07725e4 --- /dev/null +++ b/rosbag2_py/src/rosbag2_py/info_sorting_method.cpp @@ -0,0 +1,103 @@ +// Copyright 2024 Open Source Robotics Foundation, Inc. +// +// 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 +// +// 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. + +#include "rosbag2_storage/bag_metadata.hpp" + +#include "info_sorting_method.hpp" + + +namespace rosbag2_py +{ + +InfoSortingMethod info_sorting_method_from_string(std::string str) +{ + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + auto find_result = sorting_method_map.find("str"); + if (find_result == sorting_method_map.end()) { + throw std::runtime_error("Enum value match for \"" + str + "\" string is not found."); + } + return find_result->second; +} + +std::vector generate_sorted_idx( + const std::vector & topics, + const InfoSortingMethod sort_method) +{ + std::vector sorted_idx(topics.size()); + std::iota(sorted_idx.begin(), sorted_idx.end(), 0); + std::sort( + sorted_idx.begin(), + sorted_idx.end(), + [&topics, sort_method](size_t i1, size_t i2) { + if (sort_method == InfoSortingMethod::TYPE) { + return topics[i1].topic_metadata.type < topics[i2].topic_metadata.type; + } + if (sort_method == InfoSortingMethod::COUNT) { + return topics[i1].message_count < topics[i2].message_count; + } + return topics[i1].topic_metadata.name < topics[i2].topic_metadata.name; + } + ); + return sorted_idx; +} + + +std::vector generate_sorted_idx( + std::vector> & services, + const InfoSortingMethod sort_method) +{ + std::vector sorted_idx(services.size()); + std::iota(sorted_idx.begin(), sorted_idx.end(), 0); + std::sort( + sorted_idx.begin(), + sorted_idx.end(), + [&services, sort_method](size_t i1, size_t i2) { + if (sort_method == InfoSortingMethod::TYPE) { + return services[i1]->type < services[i2]->type; + } + if (sort_method == InfoSortingMethod::COUNT) { + const auto & count_1 = services[i1]->request_count + services[i1]->response_count; + const auto & count_2 = services[i2]->request_count + services[i2]->response_count; + return count_1 < count_2; + } + return services[i1]->name < services[i2]->name; + } + ); + return sorted_idx; +} + + +std::vector generate_sorted_idx( + const std::vector> & services, + const InfoSortingMethod sort_method) +{ + std::vector sorted_idx(services.size()); + std::iota(sorted_idx.begin(), sorted_idx.end(), 0); + std::sort( + sorted_idx.begin(), + sorted_idx.end(), + [&services, sort_method](size_t i1, size_t i2) { + if (sort_method == InfoSortingMethod::TYPE) { + return services[i1]->service_metadata.type < services[i2]->service_metadata.type; + } + if (sort_method == InfoSortingMethod::COUNT) { + return services[i1]->event_message_count < services[i2]->event_message_count; + } + return services[i1]->service_metadata.name < services[i2]->service_metadata.name; + } + ); + return sorted_idx; +} + +} // namespace rosbag2_py diff --git a/rosbag2_py/src/rosbag2_py/info_sorting_method.hpp b/rosbag2_py/src/rosbag2_py/info_sorting_method.hpp new file mode 100644 index 000000000..807e0116d --- /dev/null +++ b/rosbag2_py/src/rosbag2_py/info_sorting_method.hpp @@ -0,0 +1,63 @@ +// Copyright 2024 Open Source Robotics Foundation, Inc. +// +// 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 +// +// 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 ROSBAG2_PY__INFO_SORTING_METHOD_HPP_ +#define ROSBAG2_PY__INFO_SORTING_METHOD_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +#include "rosbag2_storage/topic_metadata.hpp" +#include "rosbag2_storage/bag_metadata.hpp" +#include "rosbag2_cpp/info.hpp" + +namespace rosbag2_py +{ + +/// \brief Available sorting methods for info output. +enum class InfoSortingMethod +{ + NAME, + TYPE, + COUNT, +}; + +const std::unordered_map sorting_method_map = { + {"name", InfoSortingMethod::NAME}, + {"type", InfoSortingMethod::TYPE}, + {"count", InfoSortingMethod::COUNT}}; + +InfoSortingMethod info_sorting_method_from_string(std::string str); + +std::vector generate_sorted_idx( + const std::vector & topics, + const InfoSortingMethod sort_method = InfoSortingMethod::NAME); + +std::vector generate_sorted_idx( + const std::vector> & services, + const InfoSortingMethod sort_method = InfoSortingMethod::NAME); + +std::vector generate_sorted_idx( + const std::vector> & services, + const InfoSortingMethod sort_method = InfoSortingMethod::NAME); + +} // namespace rosbag2_py + +#endif // ROSBAG2_PY__INFO_SORTING_METHOD_HPP_ diff --git a/rosbag2_storage/include/rosbag2_storage/bag_metadata.hpp b/rosbag2_storage/include/rosbag2_storage/bag_metadata.hpp index 4bbc1cda9..865772ddb 100644 --- a/rosbag2_storage/include/rosbag2_storage/bag_metadata.hpp +++ b/rosbag2_storage/include/rosbag2_storage/bag_metadata.hpp @@ -32,6 +32,19 @@ struct TopicInformation size_t message_count; }; +struct ServiceMetadata +{ + std::string name; + std::string type; + std::string serialization_format; +}; + +struct ServiceInformation +{ + ServiceMetadata service_metadata; + size_t event_message_count = 0; +}; + struct FileInformation { std::string path;